stim 1.18.0 → 1.20.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 +21 -4
- package/dist/{activity-BxnkDZDi.mjs → activity-BrGh9EAI.mjs} +3 -3
- package/dist/{agent-device-usage-output-CZ66YA4T.mjs → agent-device-usage-output-DVyv_hWj.mjs} +7 -7
- package/dist/android-0vv-OruW.mjs +6 -0
- package/dist/android-Brx6EKvJ.mjs +1258 -0
- package/dist/{android-DC3ZLuw0.mjs → android-BsYNR81W.mjs} +103 -45
- package/dist/{android-CBwCNicO.mjs → android-CK3fpEyZ.mjs} +2 -2
- package/dist/{android-cas-BBFyr9CA.mjs → android-cas-DCAuXryb.mjs} +9 -5
- package/dist/android-cas-compiler.mjs +1 -1
- package/dist/api-run.mjs +159 -8
- package/dist/{api-D0VtFhqk.mjs → api-zuX3ynYN.mjs} +9 -7
- package/dist/api.d.mts +104 -4
- package/dist/api.mjs +1 -1
- package/dist/{app-install-D-PUENug.mjs → app-install-0LgaQRT7.mjs} +39 -18
- package/dist/artifact-CnC0mfov.mjs +807 -0
- package/dist/artifact-DClXJNWx.mjs +772 -0
- package/dist/artifact-lifecycle-DzPpBYvK.mjs +30 -0
- package/dist/{web-DTU0uiWj.mjs → browser-web-CzBmhmgs.mjs} +136 -174
- package/dist/{budget-DIhL2BKx.mjs → budget-BONq9vXY.mjs} +3096 -3244
- package/dist/build-BixRI6sB.mjs +462 -0
- package/dist/build-plan-CP0tckNU.mjs +553 -0
- package/dist/{cache-manifest-BI7ozfmH.mjs → cache-manifest-qA3dT2x2.mjs} +1 -1
- package/dist/cache-manifest.mjs +1 -1
- package/dist/ccache-CjHQ5F8g.mjs +142 -0
- package/dist/{chrome-DJnmnS5q.mjs → chrome-Dp2lMLBe.mjs} +1 -1
- package/dist/{cli-DNJMwADx.mjs → cli-B2R8wH1F.mjs} +20 -20
- package/dist/cli.mjs +1 -1
- package/dist/{client-DzhapoMB.mjs → client-BLy1Pw2V.mjs} +172 -165
- package/dist/collector-run.d.mts +10 -0
- package/dist/collector-run.mjs +7 -7
- package/dist/{command-output-CBtzyIgF.mjs → command-output-BjPN99ZB.mjs} +2 -2
- package/dist/{config-CgYMahz7.mjs → config-D0LhTY3S.mjs} +13 -13
- package/dist/{created-devices-DKbeWsiK.mjs → created-devices-HU_DAb_Q.mjs} +7 -6
- package/dist/{dependency-state-xKoOypBm.mjs → dependency-state-B2m8eqsS.mjs} +2 -2
- package/dist/{detached-entry-BLfcgc4O.mjs → detached-entry-BXq4fIl-.mjs} +1 -1
- package/dist/{dev-client-CLnIH02x.mjs → dev-client-ClATaJoH.mjs} +2 -2
- package/dist/{device-D7oCHGWi.mjs → device-B7lsC0K1.mjs} +8 -8
- package/dist/device-DVCwAFlX.mjs +727 -0
- package/dist/{device-capacity-EUOOYr8T.mjs → device-capacity-Ca_ke1LE.mjs} +25 -15
- package/dist/device-host-worker.mjs +38 -18
- package/dist/{device-ios-6MewKKnc.mjs → device-ios-CRUqPxKw.mjs} +12 -11
- package/dist/{device-lease-Co-EwifR.mjs → device-lease-DHOBXGgS.mjs} +135 -22
- package/dist/{device-lease-run-w1xhCqIW.mjs → device-lease-run-CvDeHTkG.mjs} +4 -4
- package/dist/{device-pool-F5WvRPtD.mjs → device-pool-L2-5GxMy.mjs} +3 -3
- package/dist/{device-remote-tHbd1fKy.mjs → device-remote-Bmg42063.mjs} +17 -69
- package/dist/doctor-C2MSuMMg.mjs +515 -0
- package/dist/{doctor-B9ckYUoU.mjs → doctor-DPAqhVCK.mjs} +334 -721
- package/dist/doctor-watchman-CB4NnVZm.mjs +260 -0
- package/dist/{simslim-EHBQ2R4G.mjs → eas-build-Dw_ec2Km.mjs} +6 -152
- package/dist/{stim-installations-aR_WsNOA.mjs → eas-session-ledger-DZlC-Fq3.mjs} +57 -4
- package/dist/{error-diagnostics-BRXOqDzG.mjs → error-diagnostics-Du7I_GuY.mjs} +17 -12
- package/dist/errors-DzkMYh8Q.mjs +205 -0
- package/dist/{exec-DWhCZDGm.mjs → exec-B81Qodjn.mjs} +69 -15
- package/dist/{gc-Dh6mXOKC.mjs → gc-PWp34zGb.mjs} +23 -22
- package/dist/{gradle-C6GKnunQ.mjs → gradle-C2OEKCCI.mjs} +50 -125
- package/dist/{guide-tm6igAaa.mjs → guide-Dai9lphv.mjs} +862 -538
- package/dist/{hosted-android-Bv285t_t.mjs → hosted-android-DQ-Agsd8.mjs} +5 -5
- package/dist/{hosted-client-C-rMtppF.mjs → hosted-client-Io01s5By.mjs} +9 -3
- package/dist/{hosted-ios-D5mNmtj4.mjs → hosted-ios-DIxFnYp-.mjs} +3 -3
- package/dist/{hosted-logs-DN8Iz4mJ.mjs → hosted-logs-DP-ABU_M.mjs} +8 -8
- package/dist/{hosted-macos-B-wEjlwG.mjs → hosted-macos-Aziw9T_9.mjs} +7 -6
- package/dist/{hosted-native-DeeOG8xZ.mjs → hosted-native-BdAQi21M.mjs} +23 -16
- package/dist/{idle-shutdown-jjtxAn5C.mjs → idle-shutdown-DdMqoSUB.mjs} +7 -7
- package/dist/ios-BZ9dg2Fr.mjs +9 -0
- package/dist/{ios-B3SbOWdw.mjs → ios-CXLIUxXJ.mjs} +180 -24
- package/dist/ios-CZuv6gRv.mjs +1112 -0
- package/dist/{ios-Bvbf0SGY.mjs → ios-VGvNdsv2.mjs} +1 -1
- package/dist/{ios-device-Bn7jWDB1.mjs → ios-device-B1B14xND.mjs} +1 -1
- package/dist/{ios-device-vOaByMhw.mjs → ios-device-BreZOpM0.mjs} +3 -3
- package/dist/ios-project-B9drt_aY.mjs +197 -0
- package/dist/{ios-state-B2pES6Vs.mjs → ios-state-CjrL2qv-.mjs} +1 -1
- package/dist/js-swap-C8icNYIY.mjs +432 -0
- package/dist/launch-DxH0THLP.mjs +745 -0
- package/dist/launch-YrbqaIFj.mjs +1530 -0
- package/dist/{launch-verify-hskNcWkZ.mjs → launch-verify-BzRdbuO1.mjs} +26 -7
- package/dist/{logs-1Ylc1Ri6.mjs → logs-DHaRNfg7.mjs} +11 -11
- package/dist/macos-C0iljhsN.mjs +2 -0
- package/dist/{macos-DF6C7wUU.mjs → macos-V_3Ui7g4.mjs} +125 -155
- package/dist/macos-run.mjs +1 -1
- package/dist/maintenance-run.mjs +13 -10
- package/dist/{metro-Dh8T4Ytd.mjs → metro-D_j9sN-B.mjs} +209 -43
- package/dist/{metro-gateway-CEUw9RMH.mjs → metro-gateway-BBJldOdi.mjs} +2 -2
- package/dist/miss-reason-BPAzZS0r.mjs +238 -0
- package/dist/{named-ports-BFIz1Shz.mjs → named-ports-C2lvoPsb.mjs} +12 -5
- package/dist/native-android-lHzaew7r.mjs +226 -0
- package/dist/native-gradle-inputs-BQnIdAlL.mjs +356 -0
- package/dist/{native-runtime-D_603JiC.mjs → native-runtime-BRmWL7ru.mjs} +9 -8
- package/dist/native-xcode-inputs-eutS19jU.mjs +307 -0
- package/dist/native-xcode-ios-DP3cHLwu.mjs +434 -0
- package/dist/{ndjson-LGZAMsqa.mjs → ndjson-GOnbyvso.mjs} +6 -6
- package/dist/offload-worker.d.mts +12 -6
- package/dist/offload-worker.mjs +409 -73
- package/dist/{ownership-D6Se7gg_.mjs → ownership-DXzMMSx6.mjs} +2 -2
- package/dist/{placement-log-BcPhRwR4.mjs → placement-log-reFbjqEr.mjs} +7 -3
- package/dist/plan-BDk2AeY_.mjs +260 -0
- package/dist/plan-placement-D_YYlE6N.mjs +73 -0
- package/dist/{ports-BLTtfBq-.mjs → ports-jzvAJXXL.mjs} +3 -3
- package/dist/{prebuild-juCyreaR.mjs → prebuild-Bw44QxVh.mjs} +4 -4
- package/dist/{preview-D5V07Nrl.mjs → preview-BaBJ72Al.mjs} +51 -34
- package/dist/project-B8_duAzW.mjs +1067 -0
- package/dist/project-plan-BPwbLwQu.mjs +10 -0
- package/dist/{pull-request-u4vp7zmK.mjs → pull-request-vOhLNmIb.mjs} +1 -1
- package/dist/pull-requests.mjs +1 -1
- package/dist/react-native-android-chm1DMlA.mjs +921 -0
- package/dist/react-native-build-oAw6gQeW.mjs +239 -0
- package/dist/react-native-doctor-DYXoh-6I.mjs +78 -0
- package/dist/react-native-ios-SCTK_CT5.mjs +595 -0
- package/dist/{recordings-BAWltsVt.mjs → recordings-Bk-VivUV.mjs} +1 -1
- package/dist/{reload-DvyWzVjJ.mjs → reload-D34GkY78.mjs} +17 -14
- package/dist/remote-BU9UyhCJ.mjs +192 -0
- package/dist/{remote-cache-BGg7aGIZ.mjs → remote-cache-Bsts6f6Y.mjs} +5 -5
- package/dist/result-BDoRk1k3.mjs +186 -0
- package/dist/{run-vhtDgpHO.mjs → run-qvff78hv.mjs} +3 -3
- package/dist/{server-bare-B9E7S1aR.mjs → server-bare-dWjAarki.mjs} +6 -6
- package/dist/server-command-7XIKlWtO.mjs +69 -0
- package/dist/{server-expo-DoBHhuzK.mjs → server-expo-CsYu2aKL.mjs} +107 -82
- package/dist/server-expo-DV43vep4.mjs +2 -0
- package/dist/settings-Bbztm4oV.mjs +1503 -0
- package/dist/{settings-Byp2AQ_E.mjs → settings-CT3E71-i.mjs} +6 -7
- package/dist/{state-lKh8shBp.d.mts → settings-vk3mJGSm.d.mts} +4 -2
- package/dist/settings.schema.json +156 -6
- package/dist/simslim-ChMfe8rg.mjs +149 -0
- package/dist/{slot-launch-C1nqh4mu.mjs → slot-launch-B9hn96wd.mjs} +6 -6
- package/dist/{stage-g_WqWeaE.mjs → stage-BNKKdDNc.mjs} +6 -3
- package/dist/start-CbQCSnXQ.mjs +2 -0
- package/dist/{start-D-IeOyoK.mjs → start-CdvcTaXr.mjs} +113 -77
- package/dist/{state-xnqpx3AD.mjs → state-Boo0IMJq.mjs} +4 -2
- package/dist/{state-BG-aAk4k.mjs → state-DI84A-uu.mjs} +29 -10
- package/dist/{stats-DY6ekz8F.mjs → stats-BIIDrjA8.mjs} +6 -6
- package/dist/{status-BEeL6IKz.mjs → status-BDGHwkCs.mjs} +3 -1
- package/dist/{status-DCjZeE-K.mjs → status-DARMkc9q.mjs} +80 -294
- package/dist/status-watch-DvmI3SmN.mjs +296 -0
- package/dist/{stim-desktop-Behws_fi.mjs → stim-desktop-8GQX2OV8.mjs} +1 -1
- package/dist/{stop-DIJtD2GL.mjs → stop-CCZS-C9m.mjs} +2 -2
- package/dist/stop-WQPQHLuy.mjs +72 -0
- package/dist/{stop-BTjs3xbc.mjs → stop-iNemHsJC.mjs} +81 -33
- package/dist/supervisor-run.d.mts +7 -2
- package/dist/supervisor-run.mjs +32 -20
- package/dist/{support-Bwvbrq5-.mjs → support-CnE_SIjt.mjs} +17 -7
- package/dist/{support-BaayeYCf.mjs → support-DCco5fut.mjs} +61 -8
- package/dist/swiftpm-macos-afeNUExW.mjs +119 -0
- package/dist/{native-run-B06FkmZx.mjs → tailnet-CoJUb2tB.mjs} +113 -6
- package/dist/toolchain-BIupIro1.mjs +2 -0
- package/dist/{toolchain-Bnyd_K3A.mjs → toolchain-DqyDXs30.mjs} +225 -315
- package/dist/{trigger-CJMhwXe8.mjs → trigger-C0MWBi8O.mjs} +3 -3
- package/dist/trigger-SHLOWJ4O.mjs +2 -0
- package/dist/{warm-progress-CjB-MP6H.mjs → warm-progress-C3ASD6z5.mjs} +134 -37
- package/dist/{status-Dcr0Qexd.mjs → watchman-CQl51YZu.mjs} +75 -7
- package/dist/web-B3eldHFH.mjs +123 -0
- package/dist/web-BLXpOe6b.mjs +2 -0
- package/dist/web-run.mjs +10 -10
- package/dist/{workspace-state-C59dqG-Z.mjs → workspace-state-CSIFuuDa.mjs} +33 -33
- package/dist/{workspaces-xXItD8Dj.mjs → workspaces-D2xSHBDY.mjs} +1297 -1211
- package/dist/{worktree-BSYlofkq.mjs → worktree-BxDqaTev.mjs} +102 -63
- package/dist/worktree-q7_OZNY0.mjs +2 -0
- package/package.json +8 -6
- package/shim/bundle-response.cjs +2 -1
- package/shim/bundle-response.d.cts +1 -1
- package/shim/expo-metro-config.cjs +1 -1
- package/shim/native-android.gradle +101 -0
- package/dist/android-BKA16DTf.mjs +0 -4
- package/dist/android-BvwuMUJ9.mjs +0 -3572
- package/dist/guide-status-Bhf9SJXc.mjs +0 -125
- package/dist/ios-CPdkoKaa.mjs +0 -3953
- package/dist/ios-DNpdygiv.mjs +0 -7
- package/dist/macos-Ck7OBMNY.mjs +0 -2
- package/dist/metro-store-BAHFcJm6.mjs +0 -106
- package/dist/plan-placement-CtxkCO54.mjs +0 -1859
- package/dist/project-C3ChRLZy.mjs +0 -212
- package/dist/projects-DD7dBTCj.mjs +0 -92
- package/dist/server-expo-Db9HBUoa.mjs +0 -2
- package/dist/settings-CQyMElEP.mjs +0 -701
- package/dist/start-NTc1Ifqs.mjs +0 -2
- package/dist/stop-BGhKMOuH.mjs +0 -48
- package/dist/trigger-DWAq9hkw.mjs +0 -2
- package/dist/web-B6_bFDn7.mjs +0 -2
- package/dist/worktree-BJfnU6r5.mjs +0 -2
- package/dist/worktree-CsKYexJM.mjs +0 -753
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
1
|
+
import { t as ANDROID_AVD_CONFIG_HELP } from "./settings-Bbztm4oV.mjs";
|
|
2
|
+
import { r as findProjectRoot } from "./project-B8_duAzW.mjs";
|
|
3
|
+
import { s as RECENT_LAUNCH_MS } from "./watchman-CQl51YZu.mjs";
|
|
4
|
+
import { o as guideStatus, t as WATCHMAN_NESTED_WORKTREES } from "./doctor-watchman-CB4NnVZm.mjs";
|
|
5
|
+
import "./status-watch-DvmI3SmN.mjs";
|
|
6
|
+
import { SETTINGS, SETTINGS_SCHEMA_URL, TUTORIAL_VERSION } from "@stim-cli/core/state";
|
|
6
7
|
import chalk from "chalk";
|
|
7
8
|
//#region src/guide/agent.ts
|
|
8
9
|
var agent_default = {
|
|
@@ -14,6 +15,9 @@ device with another workspace. Prefer plain output: it streams each phase and
|
|
|
14
15
|
ends with the facts the next step needs. Use --json only when a script must
|
|
15
16
|
parse a stable payload.
|
|
16
17
|
|
|
18
|
+
For a native Xcode or Gradle app without React Native or Expo, read guide
|
|
19
|
+
lifecycle native-ios or guide lifecycle native-android before running it.
|
|
20
|
+
|
|
17
21
|
TWO WORKFLOWS
|
|
18
22
|
|
|
19
23
|
WORKTREE is the default. Take SINGLE CHECKOUT only when the user asks to work in
|
|
@@ -91,7 +95,10 @@ the printed remedy and keep concurrent runs on the same STIM_HOME.
|
|
|
91
95
|
Before native work, run doctor for the platform in scope when the STATUS block
|
|
92
96
|
at the top of this topic says it is due. No block means doctor is current and
|
|
93
97
|
Stim is up to date. In the worktree workflow, run it from the linked worktree
|
|
94
|
-
so it also checks the source checkout.
|
|
98
|
+
so it also checks the source checkout. Doctor never loads fingerprint.config.js
|
|
99
|
+
or runs an eas from the project tree; its fingerprint checks can still run
|
|
100
|
+
installed Expo packages, including hoisted ones, as a build does. warm,
|
|
101
|
+
start, ios and android run project code. Follow each finding's printed remedy,
|
|
95
102
|
and read the routed topic below before acting on one you do not understand. If
|
|
96
103
|
the stim resolved from PATH is older than another installation, fix PATH or the
|
|
97
104
|
installation before continuing so commands and guidance match. Under host
|
|
@@ -405,7 +412,7 @@ FULL TOPIC LIST
|
|
|
405
412
|
//#endregion
|
|
406
413
|
//#region src/guide/api.ts
|
|
407
414
|
var api_default = {
|
|
408
|
-
summary: "Typed lifecycle API: createStim, run, stop, diagnostics, and cancellation",
|
|
415
|
+
summary: "Typed lifecycle API: createStim, build, run, stop, diagnostics, and cancellation",
|
|
409
416
|
body: () => `PROGRAMMATIC API
|
|
410
417
|
|
|
411
418
|
Install stim as a project dependency: npm install --save-dev stim.
|
|
@@ -435,8 +442,27 @@ run takes platform plus its options:
|
|
|
435
442
|
macos: remoteBuild
|
|
436
443
|
web: headed (default false)
|
|
437
444
|
iOS and Android also accept slot, metroCheck, buildCache, and remoteBuild.
|
|
438
|
-
All methods accept signal. run builds, installs and launches
|
|
439
|
-
|
|
445
|
+
All methods accept signal. run builds, installs and launches.
|
|
446
|
+
Web requires a running server, just like stim web.
|
|
447
|
+
|
|
448
|
+
build produces an artifact without acquiring a device, starting a runtime, or
|
|
449
|
+
stopping an existing session. Its result is inferred from platform:
|
|
450
|
+
const result = await stim.build({ platform: 'ios' });
|
|
451
|
+
console.log(result.facts.appPath);
|
|
452
|
+
|
|
453
|
+
Build options:
|
|
454
|
+
ios: scheme, configuration, arch (arm64, x86_64, all), buildCache, remoteBuild
|
|
455
|
+
android: variant, abi (arm64-v8a, armeabi-v7a, x86, x86_64, all), buildCache, remoteBuild
|
|
456
|
+
macos: remoteBuild
|
|
457
|
+
An iOS build targets the simulator. A Debug build defaults to the host
|
|
458
|
+
architecture (Android only while optimizations.android.targetAbiOnly is on, the
|
|
459
|
+
default); Release defaults to all. macOS builds the configured Debug SwiftPM app.
|
|
460
|
+
Build results retain an owned appPath (iOS), apkPath (Android) or bundle (macOS)
|
|
461
|
+
inside this workspace until worktree removal. Later builds keep earlier copies.
|
|
462
|
+
A build leaves a running app's last build record and build log untouched; it
|
|
463
|
+
writes its own build-artifact-<platform>.ndjson. No distribution archive or web build
|
|
464
|
+
pipeline is inferred. Use @stim-cli/ci's buildCI to export a portable artifact and
|
|
465
|
+
diagnostics for your CI provider.
|
|
440
466
|
|
|
441
467
|
run returns { platform, facts }. iOS facts include udid; Android includes
|
|
442
468
|
serial; both include bundleId, appPath, metroPort, cacheHit and launched.
|
|
@@ -518,7 +544,9 @@ worktree, carries git:
|
|
|
518
544
|
null when git fails or does not answer within 3 s, or the
|
|
519
545
|
worktree has no environment and sits in ~/Desktop, ~/Documents,
|
|
520
546
|
~/Downloads, iCloud Drive, ~/Library/CloudStorage or /Volumes,
|
|
521
|
-
which status does not open on macOS
|
|
547
|
+
which status does not open on macOS; one-shot status also
|
|
548
|
+
leaves it null for a worktree with no live environment and
|
|
549
|
+
for every unprovisioned worktree
|
|
522
550
|
changed tracked paths with staged or unstaged changes, conflicts included
|
|
523
551
|
untracked untracked entries as git status lists them; a new directory
|
|
524
552
|
counts once
|
|
@@ -528,16 +556,17 @@ worktree, carries git:
|
|
|
528
556
|
mergedInto "origin/<default>" when gc would call the branch merged, judged
|
|
529
557
|
from local refs without fetching, else null
|
|
530
558
|
|
|
531
|
-
status runs \`git status --porcelain=v2 --branch\` in
|
|
532
|
-
|
|
559
|
+
status runs \`git status --porcelain=v2 --branch\` in the worktrees it reads,
|
|
560
|
+
six git calls at a time, and caches the merge verdict by HEAD and default-branch commit
|
|
533
561
|
under $STIM_HOME/git-merge. One call starts no new merge check 250 ms after
|
|
534
562
|
its first; later calls judge the rest, and until then a verdict for the same
|
|
535
563
|
HEAD at an older default-branch commit stands in; a check that timed out
|
|
536
564
|
is retried after 5 minutes. \`status --watch\` reuses a worktree's git read
|
|
537
565
|
until its index, HEAD, reflog or the branch, upstream or default-branch refs
|
|
538
566
|
change, and for at most 60 s, so a file edit, creation or deletion that is
|
|
539
|
-
not staged can take up to a minute to show.
|
|
540
|
-
|
|
567
|
+
not staged can take up to a minute to show. One-shot status reads git only
|
|
568
|
+
for live environments; \`status --watch\` reads every worktree. Plain status prints "git: 2 changed, 1 untracked, ahead 3" under
|
|
569
|
+
each environment it read, and the same after each worktree with no environment under \`--watch\`.
|
|
541
570
|
|
|
542
571
|
The paired phone's Work sheet can open changed and untracked files when the
|
|
543
572
|
server advertises workspace-diff. File lists and selected patches load on
|
|
@@ -632,7 +661,8 @@ leased until <time>" for each one.`,
|
|
|
632
661
|
port the Metro port RESERVED for this workspace
|
|
633
662
|
supervisorPid the detached supervisor's pid, or NULL when a dev server was
|
|
634
663
|
already answering that Stim did not start
|
|
635
|
-
mode "bare-inproc" | "expo-child" |
|
|
664
|
+
mode "bare-inproc" | "expo-child" | "command-child" | null
|
|
665
|
+
(see \`guide metro\`)
|
|
636
666
|
logsDir where the NDJSON timeline is written
|
|
637
667
|
agentDevice { stateDir }: absolute workspace agent-device state path;
|
|
638
668
|
set AGENT_DEVICE_STATE_DIR to it (see guide logs)
|
|
@@ -696,8 +726,9 @@ leased until <time>" for each one.`,
|
|
|
696
726
|
configuration the Xcode configuration that was built ("Release" from
|
|
697
727
|
--configuration or the ios.configuration setting); null for
|
|
698
728
|
the default Debug
|
|
699
|
-
scheme the explicit shared Xcode scheme selected by --scheme
|
|
700
|
-
absent for automatic selection;
|
|
729
|
+
scheme the explicit shared Xcode scheme selected by --scheme or
|
|
730
|
+
the ios.scheme setting; absent for automatic selection;
|
|
731
|
+
not the app URL scheme
|
|
701
732
|
cacheKey the shared-build-cache key derived from it (the
|
|
702
733
|
configuration is part of it: -release-sim vs
|
|
703
734
|
-debug-sim-arm64). A single-architecture simulator build
|
|
@@ -757,8 +788,11 @@ leased until <time>" for each one.`,
|
|
|
757
788
|
the bundle would cost more than installing it
|
|
758
789
|
launched true, "bundling", or "unverified". THE THREE ARE DIFFERENT
|
|
759
790
|
FACTS and only the last one is a problem.
|
|
760
|
-
true Metro finished the bundle response,
|
|
761
|
-
|
|
791
|
+
true Metro finished the bundle response, or an app
|
|
792
|
+
without Metro (a release build, or a native
|
|
793
|
+
Xcode or Gradle app) has a live process; then
|
|
794
|
+
the app stayed alive through a three-second
|
|
795
|
+
stability window.
|
|
762
796
|
The command checks process liveness when the
|
|
763
797
|
platform exposes it. Errors from that window
|
|
764
798
|
are printed even when the app stays alive,
|
|
@@ -1013,6 +1047,9 @@ leased until <time>" for each one.`,
|
|
|
1013
1047
|
optional fields
|
|
1014
1048
|
findings the diagnostic findings; a lower resolved Stim is a
|
|
1015
1049
|
costs-time finding with a PATH or installation remedy
|
|
1050
|
+
memory-culprit is a costs-time finding naming a process
|
|
1051
|
+
with an abnormally large footprint and, when it is safe to
|
|
1052
|
+
restart, the command
|
|
1016
1053
|
offload-candidate is a note after 3+ successful local cold builds in 7 days average over 3 min, with no remote.machines and an online tailnet Mac; open Stim Desktop Settings > Remote Macs > Add
|
|
1017
1054
|
|
|
1018
1055
|
ON FAILURE
|
|
@@ -1432,8 +1469,9 @@ RULES
|
|
|
1432
1469
|
body: () => ` stim status --json
|
|
1433
1470
|
|
|
1434
1471
|
logs { dir, errorsSinceMarker }, or null without a log directory
|
|
1435
|
-
agentDevice { stateDir }: absolute workspace agent-device state
|
|
1436
|
-
every environment, shared by its slots
|
|
1472
|
+
agentDevice { stateDir, installed }: absolute workspace agent-device state
|
|
1473
|
+
path on every environment, shared by its slots, and whether
|
|
1474
|
+
the agent-device executable is on PATH. Reporting it creates
|
|
1437
1475
|
no directory; agent-device creates it when used.
|
|
1438
1476
|
|
|
1439
1477
|
Each environment carries phase, where the workspace is in its lifecycle:
|
|
@@ -1463,6 +1501,9 @@ RULES
|
|
|
1463
1501
|
of the Stim tutorial app (stim guide tutorial). Status
|
|
1464
1502
|
reports whatever version it finds; Desktop decides which
|
|
1465
1503
|
versions it supports. Static app.json only.
|
|
1504
|
+
doctorRuns { ios?: { at }, android?: { at } }: when stim doctor last
|
|
1505
|
+
ran in the workspace, per platform, as ISO timestamps;
|
|
1506
|
+
absent until it has run.
|
|
1466
1507
|
recording { enabled }: whether stim-server may record the workspace's
|
|
1467
1508
|
device screens for replay, from recording.enabled
|
|
1468
1509
|
|
|
@@ -1732,8 +1773,8 @@ RULES
|
|
|
1732
1773
|
build { platform, slot, state, phase, startedAt, phaseStartedAt,
|
|
1733
1774
|
outcome, outcomeKnown, cacheLookupOutcome?, expectedMs, expectedPhaseMs,
|
|
1734
1775
|
completedPhaseMs?, basis,
|
|
1735
|
-
plannedPhases, missReason?, missProvisional?, detail?,
|
|
1736
|
-
waitingOn?, waitingFor? }
|
|
1776
|
+
plannedPhases, missReason?, missProvisional?, detail?, activity?,
|
|
1777
|
+
placement, waitingOn?, waitingFor? }
|
|
1737
1778
|
|
|
1738
1779
|
state "running" while the run's own native-run claim is live;
|
|
1739
1780
|
"stale" when that claim was released or its process is
|
|
@@ -1749,7 +1790,10 @@ RULES
|
|
|
1749
1790
|
once the app is ready and covers waiting for the
|
|
1750
1791
|
device: its boot, adoption cleanup, or a physical
|
|
1751
1792
|
device's lease and connection check. A boot that
|
|
1752
|
-
finishes during the build adds no device time.
|
|
1793
|
+
finishes during the build adds no device time. For a
|
|
1794
|
+
device hosted on another Mac, device covers reserving
|
|
1795
|
+
and preparing it there, install covers delivering the
|
|
1796
|
+
app, and launch starts when the host launches it. An
|
|
1753
1797
|
--eas-profile run has no cache lookup, so its outcome
|
|
1754
1798
|
stays the project's most recent one until install.
|
|
1755
1799
|
A stim macos run enters only prepare, compile (SwiftPM,
|
|
@@ -1822,6 +1866,16 @@ RULES
|
|
|
1822
1866
|
to file names, at most 160 characters
|
|
1823
1867
|
updatedAt when the build last wrote it; the run writes it at most
|
|
1824
1868
|
every 2 seconds
|
|
1869
|
+
activity during device or launch, once Stim observed what the run
|
|
1870
|
+
waits on: { name, startedAt, percent? }. name is
|
|
1871
|
+
"booting" while device waits for the owned simulator or
|
|
1872
|
+
emulator the run is booting; during launch, "bundling"
|
|
1873
|
+
from the app's bundle request to this workspace's Metro
|
|
1874
|
+
until Metro delivered it, or "waiting-ready" while the
|
|
1875
|
+
app reports its readiness pending; absent in between.
|
|
1876
|
+
startedAt is the evidence's time. percent is Metro's own
|
|
1877
|
+
progress for that request, present only once Metro
|
|
1878
|
+
reported one. Activity never changes launched.
|
|
1825
1879
|
placement where the build runs: "local", or while it is offloaded
|
|
1826
1880
|
{ host, phase, startedAt, phaseStartedAt }. host is the
|
|
1827
1881
|
remote.machines entry; phase is the step there: sync,
|
|
@@ -1842,6 +1896,7 @@ RULES
|
|
|
1842
1896
|
|
|
1843
1897
|
build: ios compile, 1m10s elapsed -- about 3 min left (median of 4 cold runs)
|
|
1844
1898
|
build: ios compile on janics-mac-mini (build, 2m10s), 3m05s elapsed
|
|
1899
|
+
build: ios launch (bundling JS 45%, 12s), 58s elapsed
|
|
1845
1900
|
|
|
1846
1901
|
An environment with a recorded run also carries lastBuilds, each
|
|
1847
1902
|
platform's most recent ios or android run, finished or failed:
|
|
@@ -1942,7 +1997,8 @@ RULES
|
|
|
1942
1997
|
disk (environment) { worktreeBytes, nodeModulesBytes, buildBytes,
|
|
1943
1998
|
measuredAt }
|
|
1944
1999
|
worktreeBytes the linked worktree, or else the checkout holding the
|
|
1945
|
-
workspace, node_modules included
|
|
2000
|
+
workspace, node_modules included; the linked
|
|
2001
|
+
worktrees nested inside a checkout are not counted
|
|
1946
2002
|
nodeModulesBytes node_modules at that root and at the workspace path;
|
|
1947
2003
|
part of worktreeBytes
|
|
1948
2004
|
buildBytes Stim's folder for the workspace: Xcode derived data,
|
|
@@ -1952,11 +2008,13 @@ RULES
|
|
|
1952
2008
|
disk (device) { bytes, measuredAt }: the simulator's data folder
|
|
1953
2009
|
under CoreSimulator/Devices, or the AVD's .avd folder
|
|
1954
2010
|
|
|
1955
|
-
\`status --watch\` runs one du at a time
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
2011
|
+
\`status --watch\` runs one du at a time on the whole machine, at low
|
|
2012
|
+
priority, off its refresh path, and measures a folder at most every 5
|
|
2013
|
+
minutes while its environment is active and every hour otherwise. A walk
|
|
2014
|
+
that fails or times out is not repeated by any watcher for that period. It
|
|
2015
|
+
caches each size under $STIM_HOME/disk-usage, which one-shot status only
|
|
2016
|
+
reads, so the fields appear once a watcher, such as stim-server or Stim
|
|
2017
|
+
Desktop, has measured.
|
|
1960
2018
|
|
|
1961
2019
|
An environment carries agents when coding-agent sessions work in it, most
|
|
1962
2020
|
recently active first:
|
|
@@ -2018,7 +2076,9 @@ RULES
|
|
|
2018
2076
|
builds included, when machine.memorySource is footprint. Otherwise it is
|
|
2019
2077
|
the estimate, with memorySource estimate.
|
|
2020
2078
|
|
|
2021
|
-
capacity.committedMb sums memoryMb
|
|
2079
|
+
capacity.committedMb sums memoryMb; in a \`status --watch --json\` line each
|
|
2080
|
+
figure, including an environment's memoryMb, is held on its own (see
|
|
2081
|
+
\`guide lifecycle\`), so the sums can differ from what they sum. The memory budget plans before a boot
|
|
2022
2082
|
and always uses the estimate. What is using CPU and memory now is the
|
|
2023
2083
|
top-level machine section:
|
|
2024
2084
|
|
|
@@ -2252,8 +2312,9 @@ HOW A RUN IS COUNTED (\`stats\`)
|
|
|
2252
2312
|
|
|
2253
2313
|
DEVICE PLACEMENT (\`ios|android --remote auto\`)
|
|
2254
2314
|
Auto runs include devicePlacement: { decision, reason, machine? } in the run
|
|
2255
|
-
facts, lastBuilds and build history. decision is "local", "hosted"
|
|
2256
|
-
"waited-locally" (the local run actually waited for a device slot)
|
|
2315
|
+
facts, lastBuilds and build history. decision is "local", "hosted",
|
|
2316
|
+
"waited-locally" (the local run actually waited for a device slot) or "eas"
|
|
2317
|
+
(remote.easFallback put it on an EAS Simulator, reported like --remote eas). The same
|
|
2257
2318
|
optional devicePlacement appears on the status device entry for each slot.
|
|
2258
2319
|
Hosted host facts include selected: "auto" or the named machine, and reason
|
|
2259
2320
|
for automatic placement. Plain status prints (auto: <reason>) after the host.
|
|
@@ -2433,8 +2494,9 @@ WHAT THE SUPERVISOR IS
|
|
|
2433
2494
|
to install, and no cross-project state. It hosts the dev server, writes its
|
|
2434
2495
|
output as NDJSON into the global workspace logs directory
|
|
2435
2496
|
($STIM_HOME/workspaces/<project>--<digest>/logs; see \`guide logs\`), and
|
|
2436
|
-
records itself in that workspace's state.json before it starts serving.
|
|
2437
|
-
|
|
2497
|
+
records itself in that workspace's state.json before it starts serving. Three
|
|
2498
|
+
modes: metro.command selects command-child, otherwise ecosystem detection
|
|
2499
|
+
picks one of the first two:
|
|
2438
2500
|
|
|
2439
2501
|
bare-inproc bare React Native: Metro is hosted INSIDE the supervisor,
|
|
2440
2502
|
from the project's own node_modules, with Stim's reporter
|
|
@@ -2443,6 +2505,15 @@ WHAT THE SUPERVISOR IS
|
|
|
2443
2505
|
expo-child Expo: the project's own \`expo start --port <port>\` runs as
|
|
2444
2506
|
a child and its stdout is parsed into records. Levels are
|
|
2445
2507
|
INFERRED from each line, so those records carry raw: true.
|
|
2508
|
+
command-child metro.command (\`guide settings\`): that argv runs as a
|
|
2509
|
+
child in its own process group, with {port} replaced by the
|
|
2510
|
+
reserved port, and its output is parsed like expo-child's
|
|
2511
|
+
under command_stdout and command_stderr events. Stopping the
|
|
2512
|
+
dev server signals the whole group, so a wrapper such as
|
|
2513
|
+
yarn takes its Metro with it. Stim adds no reporter, warmup
|
|
2514
|
+
observer or shared transform store, so ios and android
|
|
2515
|
+
launches stay UNVERIFIED: read \`stim logs --source metro\`
|
|
2516
|
+
for the bundle lines.
|
|
2446
2517
|
|
|
2447
2518
|
In expo-child mode, remote intent plus metro.tunnel "expo" makes \`start\` pass
|
|
2448
2519
|
\`--tunnel\` and EXPO_UNSTABLE_TUNNEL_V2=1 (the legacy ws-tunnel path is
|
|
@@ -2461,7 +2532,8 @@ WHAT THE SUPERVISOR IS
|
|
|
2461
2532
|
|
|
2462
2533
|
IDLE STOP: the supervisor stops its dev server after metro.idleStopMinutes
|
|
2463
2534
|
(default 60; 0 never stops) with no bundle request, no client log record
|
|
2464
|
-
(in-app console logs; for Expo, any stdout line of the
|
|
2535
|
+
(in-app console logs; for Expo or metro.command, any stdout line of the
|
|
2536
|
+
dev server) and no Stim
|
|
2465
2537
|
command in the workspace (start, ios, android, reload, worktree warm). It
|
|
2466
2538
|
checks once a minute. It keeps running while a bundle response is in
|
|
2467
2539
|
flight, while a build in the workspace is in progress, while a stim ios,
|
|
@@ -2600,9 +2672,15 @@ then 8081, without probing or reserving; an invalid pin still refuses.
|
|
|
2600
2672
|
|
|
2601
2673
|
New allocations scan TCP ports 8900-8999. They skip registry reservations
|
|
2602
2674
|
and existing listeners, announcing occupied ports and upward retries on
|
|
2603
|
-
stderr.
|
|
2604
|
-
|
|
2605
|
-
|
|
2675
|
+
stderr. All 100 ports occupied or reserved is a refusal; stop or release
|
|
2676
|
+
unused allocations in their owning workspaces.
|
|
2677
|
+
|
|
2678
|
+
Metro allocation (from 8082 up) and named allocation find listeners in the
|
|
2679
|
+
native TCP table: netstat on macOS and Windows, /proc/net on Linux. When that
|
|
2680
|
+
table is denied, empty or unreadable, as in some sandboxes, each candidate is
|
|
2681
|
+
checked with an lsof listener scan and connects to 127.0.0.1 and ::1 instead.
|
|
2682
|
+
Allocation refuses only when none of them can answer: start refuses with
|
|
2683
|
+
STIM_PORT_INSPECTION_FAILED, and ports get prints the same message.
|
|
2606
2684
|
|
|
2607
2685
|
The machine registry, under STIM_HOME, serializes allocation and cleanup.
|
|
2608
2686
|
The workspace is the nearest package.json directory, resolved through
|
|
@@ -2625,6 +2703,7 @@ ports lists named labels and ports, plus Metro marked managed.
|
|
|
2625
2703
|
ports stop [label] kills TCP listeners on those named ports and releases
|
|
2626
2704
|
the allocations. It sends SIGTERM, waits two seconds, then SIGKILL if needed;
|
|
2627
2705
|
on Windows it terminates the listener's process tree with taskkill.
|
|
2706
|
+
Stopping listeners requires lsof on macOS and Linux, or netstat on Windows.
|
|
2628
2707
|
It prints the PID and command (the image name on Windows) for each stopped
|
|
2629
2708
|
process. The listener's cwd can be anywhere: the named reservation is
|
|
2630
2709
|
permission to stop that listener.
|
|
@@ -2635,11 +2714,12 @@ ports release [label] releases without signalling a process.
|
|
|
2635
2714
|
Omitting the label selects every named port, never Metro. stim stop leaves
|
|
2636
2715
|
named ports alone.
|
|
2637
2716
|
|
|
2638
|
-
worktree remove
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2717
|
+
worktree remove, gc --delete and automatic maintenance release named
|
|
2718
|
+
allocations without signalling their listeners; run ports stop first to stop
|
|
2719
|
+
a server this workspace started. gc reports allocations whose workspace no
|
|
2720
|
+
longer exists; gc --delete releases them. Unmounted or unresolved workspace
|
|
2721
|
+
paths are retained. Use the same current Stim version for cleanup: versions
|
|
2722
|
+
without ports do not know about named allocations.
|
|
2643
2723
|
|
|
2644
2724
|
A shared API does not get a shared reservation. Pass its port by environment
|
|
2645
2725
|
instead of allocating a separate label in every worktree.`
|
|
@@ -2864,7 +2944,8 @@ THE RECORD
|
|
|
2864
2944
|
clockOffsetMs the offset added to deviceTs; absent if the query failed.
|
|
2865
2945
|
A collector_clock warning then says timestamps retain device time.
|
|
2866
2946
|
raw true when the level was inferred from a line of text rather than
|
|
2867
|
-
reported by the producer (every expo-child
|
|
2947
|
+
reported by the producer (every expo-child and command-child
|
|
2948
|
+
record)
|
|
2868
2949
|
context --errors --json only: the code frame and stack lines Expo
|
|
2869
2950
|
printed after this error, as an array of strings. Absent when
|
|
2870
2951
|
there are none. Stim adds it at query time; it is not in the
|
|
@@ -2915,27 +2996,31 @@ remote Mac and a named --remote target write none:
|
|
|
2915
2996
|
stim logs --source placement --json
|
|
2916
2997
|
Fields: kind (build or device), platform, settings [{ key, value, from }] with
|
|
2917
2998
|
from flag, env, setting or default (remote.build and remote.buildMode for a
|
|
2918
|
-
build, ios.remote or android.remote
|
|
2999
|
+
build, ios.remote or android.remote, plus remote.easFallback when it is on, for
|
|
3000
|
+
a device), candidates [{ machine, code,
|
|
2919
3001
|
msg, detail? }], choice { machine, code, msg } with machine local when the run
|
|
2920
3002
|
stays on this Mac, and fallback { code, msg, machine? } when a remote Mac that
|
|
2921
3003
|
was meant to take the run did not (level warn). The msg is the same text the
|
|
2922
3004
|
placement: and build: phase lines print.
|
|
2923
3005
|
Candidate codes: accepted, unreachable, busy, disk, load, version-mismatch
|
|
2924
3006
|
(detail lists the toolchain parts: xcode, arch, jdk, ...), no-matching-device,
|
|
2925
|
-
declined, memory, no-capacity
|
|
3007
|
+
declined, memory, no-capacity; with machine eas, why an EAS Simulator was not
|
|
3008
|
+
used: eas-named-slot, eas-local-flags, eas-no-agent-device, eas-no-cli,
|
|
3009
|
+
eas-cli-too-old, eas-session-busy, eas-metro-unreachable, eas-logged-out, eas-not-enabled,
|
|
3010
|
+
eas-unavailable. Choice codes for a build: placed, named,
|
|
2926
3011
|
forced, this-mac-busy, this-mac-free, mode-off, local-selected, no-remote-mac,
|
|
2927
3012
|
unsupported; fallback codes: no-remote-mac-took-it, offload-failed, fallback.
|
|
2928
3013
|
Choice codes for a device: placed, sticky, this-mac-free, no-remote-mac,
|
|
2929
|
-
device-count-unknown, no-host-admits. Machine names appear in these records;
|
|
3014
|
+
device-count-unknown, no-host-admits, eas-fallback (machine eas). Machine names appear in these records;
|
|
2930
3015
|
they stay in the local logs. These records carry no tokens.
|
|
2931
3016
|
|
|
2932
3017
|
WHAT WRITES WHAT
|
|
2933
3018
|
maintenance.ndjson workspace maintenance actions, failures and explaining skips
|
|
2934
|
-
metro.ndjson the bundler, in
|
|
3019
|
+
metro.ndjson the bundler, in every supervisor mode
|
|
2935
3020
|
client.ndjson in-app console logs and redboxes -- BARE PROJECTS ONLY.
|
|
2936
|
-
In expo-child mode everything
|
|
2937
|
-
metro.ndjson with raw: true,
|
|
2938
|
-
returns nothing there.
|
|
3021
|
+
In expo-child and command-child mode everything the
|
|
3022
|
+
dev server prints lands in metro.ndjson with raw: true,
|
|
3023
|
+
so \`--source client\` returns nothing there.
|
|
2939
3024
|
device.ndjson the device-log collector uses \`simctl log stream\`
|
|
2940
3025
|
predicated on the app, or \`adb logcat\` filtered to
|
|
2941
3026
|
the app's pid. Local iOS simulator capture starts
|
|
@@ -3098,7 +3183,9 @@ WHAT WRITES WHAT
|
|
|
3098
3183
|
build-android.ndjson extracted diagnostics at level error, and the launch as
|
|
3099
3184
|
a marker record. One RUN's worth: each build starts the
|
|
3100
3185
|
file over, so the first error in it always belongs to
|
|
3101
|
-
the run that pointed you at it.
|
|
3186
|
+
the run that pointed you at it. A build from the API's
|
|
3187
|
+
build() writes build-artifact-<platform>.ndjson
|
|
3188
|
+
instead, so it never replaces a run's transcript.
|
|
3102
3189
|
|
|
3103
3190
|
Only a dev server Stim hosted is captured. If you started the bundler
|
|
3104
3191
|
yourself, the metro and client sources stay empty -- which is not a sign of a
|
|
@@ -3440,9 +3527,14 @@ Branch on the code, never on the message.`,
|
|
|
3440
3527
|
works. See stim guide macos.`
|
|
3441
3528
|
},
|
|
3442
3529
|
STIM_OFFLOAD_REFUSED: {
|
|
3443
|
-
summary: "the selected remote Mac cannot build this app",
|
|
3530
|
+
summary: "the selected remote Mac or automatic build pool cannot build this app",
|
|
3444
3531
|
body: () => `STIM_OFFLOAD_REFUSED
|
|
3445
3532
|
|
|
3533
|
+
Automatic placement also refuses when local is excluded in remote.buildPoolDisabled
|
|
3534
|
+
and no enabled remote can finish this build, or when the build requires a local
|
|
3535
|
+
compiler. Enable local or choose an explicit --remote-build placement. Existing
|
|
3536
|
+
builds are not interrupted and a cache hit needs no compiler.
|
|
3537
|
+
|
|
3446
3538
|
A named --remote-build selection is strict. The message names the machine
|
|
3447
3539
|
and why it cannot take or finish the build: not configured or paired, approval
|
|
3448
3540
|
pending or denied, unreachable or changed pinned identity, incompatible
|
|
@@ -3555,7 +3647,8 @@ Rerun with --remote-build auto for normal placement and local fallback, or
|
|
|
3555
3647
|
body: () => `STIM_NO_SCHEME
|
|
3556
3648
|
Stim could not list or select an app scheme in ios/. Share the intended app
|
|
3557
3649
|
scheme so xcodebuild can see it. Select an available exact name with
|
|
3558
|
-
\`stim ios --scheme <name
|
|
3650
|
+
\`stim ios --scheme <name>\`, or set it once with the ios.scheme setting. An
|
|
3651
|
+
unknown explicit name prints available choices.
|
|
3559
3652
|
Without an explicit selector, a workspace
|
|
3560
3653
|
name match wins; otherwise Stim accepts a sole non-test scheme, or a listed
|
|
3561
3654
|
scheme matching app.json. Unmatched ambiguous schemes are refused.`
|
|
@@ -3888,7 +3981,9 @@ so a Debug run on one is wired to a LAN origin instead of localhost.`,
|
|
|
3888
3981
|
physical, hosted, remote, parked and other homes' devices and never deletes.
|
|
3889
3982
|
A failed reclaim is logged and skipped; the run keeps waiting.
|
|
3890
3983
|
Stop an environment (\`stim stop\`), pass a longer \`--wait <seconds>\`,
|
|
3891
|
-
or raise concurrency.maxDevices.
|
|
3984
|
+
or raise concurrency.maxDevices. With --remote auto, remote.machines and
|
|
3985
|
+
the opt-in remote.easFallback (billed EAS Simulator) are tried before this
|
|
3986
|
+
wait; \`stim logs --source placement\` says why neither took the run. Waiting prints holder names and elapsed
|
|
3892
3987
|
time; status JSON exposes build.waitingFor independently of phase.
|
|
3893
3988
|
Stats records capacityWaits for waits and capacityRefusals for this code.
|
|
3894
3989
|
See \`guide lifecycle concurrency\`.`
|
|
@@ -4175,6 +4270,17 @@ captured" (in metro.ndjson, bare RN)
|
|
|
4175
4270
|
printed the last lines of the global workspace logs/supervisor.log above this -- read
|
|
4176
4271
|
them. A cold Metro on a large graph can genuinely need more than the default
|
|
4177
4272
|
60s: re-run with \`--wait 180\`. Otherwise \`stim stop\`, then \`start\`.`
|
|
4273
|
+
},
|
|
4274
|
+
STIM_PORT_INSPECTION_FAILED: {
|
|
4275
|
+
summary: "no free Metro port could be confirmed: netstat, lsof and loopback connects all failed",
|
|
4276
|
+
body: () => `STIM_PORT_INSPECTION_FAILED
|
|
4277
|
+
Stim reads the native TCP listener table (netstat on macOS and Windows,
|
|
4278
|
+
/proc/net on Linux) to find a free Metro port. When that table is denied,
|
|
4279
|
+
empty or unreadable, it checks each candidate with an lsof listener scan and
|
|
4280
|
+
connects to 127.0.0.1 and ::1. This refusal means none of them could answer,
|
|
4281
|
+
usually because a sandbox denies them. Allow Stim to run netstat or lsof, or
|
|
4282
|
+
to connect to loopback, then retry. A metro.port pin skips the scan for
|
|
4283
|
+
Metro. \`stim ports get\` prints the same message.`
|
|
4178
4284
|
},
|
|
4179
4285
|
STIM_SUPERVISOR_EXITED: {
|
|
4180
4286
|
summary: "the dev server failed outright; the quoted supervisor.log tail is the real error",
|
|
@@ -4218,10 +4324,10 @@ captured" (in metro.ndjson, bare RN)
|
|
|
4218
4324
|
\`--device-profile\` on an eas/proxy run (\`--remote\` or android.remote), a
|
|
4219
4325
|
\`android --remote auto\`, a changed hosted placement, or hosted Debug
|
|
4220
4326
|
with \`--no-metro-check\` (see lifecycle hosted-android), a working directory
|
|
4221
|
-
with no
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4327
|
+
with no supported app project, or a project whose integration refuses this
|
|
4328
|
+
operation. React Native and Expo require a readable package.json that
|
|
4329
|
+
declares react-native or expo; the refusal names the invalid file.
|
|
4330
|
+
\`doctor\` reports project admission problems as findings. A \`logs\` query in
|
|
4225
4331
|
a workspace that has never produced a log timeline (the refusal names the
|
|
4226
4332
|
nearest registered descendant app with logs when one exists), an
|
|
4227
4333
|
android/app/build.gradle that declares product flavors with
|
|
@@ -4248,7 +4354,7 @@ captured" (in metro.ndjson, bare RN)
|
|
|
4248
4354
|
\`gc --json --cache <name>\` refuses with STIM_BAD_ARG when no shared cache
|
|
4249
4355
|
carries the name; the remedy names the caches on this machine. \`gc\`
|
|
4250
4356
|
refuses --cache together with --worktrees the same way.
|
|
4251
|
-
A working directory with no
|
|
4357
|
+
A working directory with no supported project above it gets the same
|
|
4252
4358
|
STIM_NO_PROJECT refusal from \`start\`, \`ios\`, \`android\`, \`stop\`,
|
|
4253
4359
|
\`reload\`, \`logs\`, \`doctor\` and \`device lock|unlock\`. With \`--json\` the { code, message, remedy } object
|
|
4254
4360
|
is on stdout, except \`logs --json\`, whose stdout stays empty NDJSON; the
|
|
@@ -4709,6 +4815,10 @@ const lifecycle = {
|
|
|
4709
4815
|
summary: "The full worktree -> start -> ios/android -> logs -> teardown flow, with sections for builds, devices and flags",
|
|
4710
4816
|
preamble: () => `ENVIRONMENT LIFECYCLE
|
|
4711
4817
|
|
|
4818
|
+
For a native Xcode or Gradle app without React Native or Expo, read
|
|
4819
|
+
\`stim guide lifecycle native-ios\` or \`stim guide lifecycle native-android\`.
|
|
4820
|
+
The Metro and JavaScript steps below apply to React Native and Expo.
|
|
4821
|
+
|
|
4712
4822
|
Two workflows share steps 2 through 6.
|
|
4713
4823
|
|
|
4714
4824
|
SINGLE CHECKOUT: work in place, on a branch, in one directory. There is no
|
|
@@ -4784,7 +4894,7 @@ a seed belongs to this workflow.
|
|
|
4784
4894
|
# unwarmed worktrees with no Stim registry entry. Git-created branches stay.
|
|
4785
4895
|
stim worktree remove
|
|
4786
4896
|
|
|
4787
|
-
A Debug \`ios\` or \`android\` run checks the reserved port before the device
|
|
4897
|
+
A React Native or Expo Debug \`ios\` or \`android\` run checks the reserved port before the device
|
|
4788
4898
|
or the build. When no healthy dev server of this workspace answers there, it
|
|
4789
4899
|
runs the same start as step 2: a dev server started outside Stim is reused, a
|
|
4790
4900
|
reservation held by a foreign process moves to a free port, and the budgets
|
|
@@ -4948,7 +5058,10 @@ WAITING FOR A CHANGE
|
|
|
4948
5058
|
To wait for a device, a build or a dev server instead of polling, run
|
|
4949
5059
|
\`stim status --watch --json\`. It keeps running and prints one complete
|
|
4950
5060
|
status payload per line: one at once, then one each time the payload
|
|
4951
|
-
changes, never two identical ones in a row.
|
|
5061
|
+
changes, never two identical ones in a row. In a watch line, a usage
|
|
5062
|
+
figure repeats its value in the previous line until it moves by a step: an owner's cpuPercent 5 points, an
|
|
5063
|
+
owner's or environment's memoryMb and capacity.committedMb 16 MB. An owner's row
|
|
5064
|
+
changes as a whole, so its residentMb and processes update with it. It reacts to Stim state files,
|
|
4952
5065
|
the EAS session ledger, adb device arrivals and departures, and simulator
|
|
4953
5066
|
state, and recomputes every 30 seconds as a fallback. A log append updates
|
|
4954
5067
|
only the log error count and device activity, no sooner than 15 seconds
|
|
@@ -4959,6 +5072,161 @@ WAITING FOR A CHANGE
|
|
|
4959
5072
|
still running, which it notices at the next change.
|
|
4960
5073
|
Without --json it reprints the human view on change.`,
|
|
4961
5074
|
sections: {
|
|
5075
|
+
"native-ios": {
|
|
5076
|
+
summary: "native Xcode project selection, process launch, cache behavior and current limits",
|
|
5077
|
+
body: () => `NATIVE XCODE APPS
|
|
5078
|
+
Run from the directory containing the .xcodeproj or .xcworkspace. A Node
|
|
5079
|
+
package.json is not required. React Native and Expo apps keep their existing
|
|
5080
|
+
integration.
|
|
5081
|
+
|
|
5082
|
+
stim doctor --platform ios
|
|
5083
|
+
stim ios --scheme MyApp --configuration Debug --json
|
|
5084
|
+
stim ios --scheme MyApp --configuration Release --json
|
|
5085
|
+
stim logs --errors
|
|
5086
|
+
stim stop
|
|
5087
|
+
|
|
5088
|
+
Use the project's actual scheme and configuration names. Shared Run schemes
|
|
5089
|
+
select application targets; a unique application target can also use its
|
|
5090
|
+
automatic scheme. A workspace owns its referenced projects. --scheme selects
|
|
5091
|
+
an exact name; duplicate container/scheme matches refuse instead of guessing.
|
|
5092
|
+
--configuration overrides ios.configuration in .stim.json, then defaults to
|
|
5093
|
+
Debug. Custom configurations such as Staging use the same path.
|
|
5094
|
+
|
|
5095
|
+
Native Debug, Release and custom configurations do not start or require Metro,
|
|
5096
|
+
embed JavaScript, or swap a JavaScript bundle. The app is launched as a native
|
|
5097
|
+
process and reports metroPort: null. launched: true establishes a live process;
|
|
5098
|
+
verify the expected screen and interaction on the reported device separately.
|
|
5099
|
+
After a native source edit, rerun stim ios. stim reload is for JavaScript.
|
|
5100
|
+
The existing owned simulator, device lease, signing, log and teardown services
|
|
5101
|
+
still apply. Stim does not change signing accounts or provisioning profiles.
|
|
5102
|
+
|
|
5103
|
+
A reusable artifact key includes the selected build configuration, source and
|
|
5104
|
+
known dependency inputs, toolchain and build options. In a git checkout,
|
|
5105
|
+
ignored files the project does not reference are not part of the key. Native
|
|
5106
|
+
Release cache reuse does not depend on releaseBundleSwap. Xcode compilation
|
|
5107
|
+
uses the shared compilation cache when the toolchain and settings support it.
|
|
5108
|
+
--plan predicts this same local artifact without preparing dependencies or
|
|
5109
|
+
choosing a device.
|
|
5110
|
+
|
|
5111
|
+
Inputs whose complete build closure cannot be established build locally with
|
|
5112
|
+
artifact caching skipped. This includes shell build phases, custom build rules,
|
|
5113
|
+
C-family header graphs, Swift package graphs and unresolved external input
|
|
5114
|
+
paths or compiler overrides. The miss reason explains the exclusion. --plan
|
|
5115
|
+
refuses such a prediction; omit --plan to prepare and build the app.
|
|
5116
|
+
|
|
5117
|
+
A compatible approved build Mac can compile a native Xcode app with
|
|
5118
|
+
--remote-build auto or --remote-build <name>. Both peers must support
|
|
5119
|
+
native-xcode-build. This first worker path requires a verified artifact identity
|
|
5120
|
+
and all inputs contained in the repository and visible to git. Ignored or
|
|
5121
|
+
external inputs keep the build here, and placement names the first one; their
|
|
5122
|
+
bytes are never silently omitted. The common case is a Finder .DS_Store that a
|
|
5123
|
+
global gitignore hides: delete it, or stop ignoring it, to offload. The worker
|
|
5124
|
+
compares its own toolchain and compiler environment identity before compiling
|
|
5125
|
+
and refuses, naming the differing parameter, so the build falls back here.
|
|
5126
|
+
Worker source mirrors remove stale inputs, while Xcode compilation caches remain
|
|
5127
|
+
in the worker's private Stim home. Physical builds stay local.
|
|
5128
|
+
|
|
5129
|
+
Native Xcode apps can install on an already approved hosting Mac with
|
|
5130
|
+
process-mode support:
|
|
5131
|
+
stim ios --scheme MyApp --configuration Debug --remote janics-mac-mini --json
|
|
5132
|
+
|
|
5133
|
+
The host must advertise hosted-ios-process; older hosts refuse with an update
|
|
5134
|
+
remedy before reservation or upload. --remote auto skips incompatible hosts,
|
|
5135
|
+
but an existing session stays on its recorded host until stim stop. Debug,
|
|
5136
|
+
Release and custom configurations use the offered simulator architecture,
|
|
5137
|
+
report metroPort: null, and close any previous session Metro bridge. Logs,
|
|
5138
|
+
view/control, agent access and scoped stop use the existing hosted-ios services.
|
|
5139
|
+
Verify UI and interaction separately from the host's live process evidence.
|
|
5140
|
+
|
|
5141
|
+
Unbounded native build offload, hosted --plan, eas/proxy devices and EAS artifact
|
|
5142
|
+
profiles remain unsupported for native Xcode apps. These limits do not change React Native or
|
|
5143
|
+
Expo support.
|
|
5144
|
+
|
|
5145
|
+
Copyable agent request:
|
|
5146
|
+
Run this native Xcode app with stim ios --scheme MyApp --configuration Debug
|
|
5147
|
+
--json. Verify its expected screen and interaction on the reported device,
|
|
5148
|
+
inspect stim logs --errors, then stop only this workspace with stim stop.`
|
|
5149
|
+
},
|
|
5150
|
+
"native-android": {
|
|
5151
|
+
summary: "native Gradle app selection, hosted emulators, build-worker inputs and current limits",
|
|
5152
|
+
body: () => `NATIVE ANDROID GRADLE APPS
|
|
5153
|
+
Native Android Gradle apps run directly with \`stim android [--variant freeDebug]\`:
|
|
5154
|
+
no Metro, npm install or React Native dependency is required. The directory must
|
|
5155
|
+
contain a Gradle wrapper and settings.gradle or settings.gradle.kts. AGP resolves
|
|
5156
|
+
one application module and the exact variant (debug by default). Stim installs
|
|
5157
|
+
one signed universal or matching-ABI APK on an owned emulator or leased phone.
|
|
5158
|
+
Use \`--remote <approved-mac>\` or \`--remote auto\` for a hosted emulator; the host
|
|
5159
|
+
must support native Android process mode. Multiple application modules,
|
|
5160
|
+
density/split APK sets and EAS/proxy targets are unsupported. Set
|
|
5161
|
+
org.gradle.configureondemand=false; configuration cache remains supported.
|
|
5162
|
+
Stim verifies the existing APK signature; it does not sign it.
|
|
5163
|
+
|
|
5164
|
+
Stim artifact caching is unavailable because arbitrary Gradle inputs are not fully
|
|
5165
|
+
tracked. Build workers require a project-scoped \`android.offloadInputs\` declaration:
|
|
5166
|
+
\`{"complete":true,"ignored":["app/src/main/assets/generated.json"],"outputs":["build","app/build"]}\`.
|
|
5167
|
+
Use \`stim android --remote-build <approved-mac>\` after reviewing this declaration.
|
|
5168
|
+
Paths are exact repository-relative paths. complete affirms that Git-visible
|
|
5169
|
+
source plus the listed ignored files suffice, including optional files; Gradle
|
|
5170
|
+
DSL can read undeclared input without failing. Never list secrets or user Gradle
|
|
5171
|
+
homes. External inputs, directory links, submodules and custom local.properties
|
|
5172
|
+
refuse; an SDK-only local.properties stays local. Only declared directories
|
|
5173
|
+
reported by AGP and previously produced by this worker remain warm, along with
|
|
5174
|
+
worker project .gradle/.kotlin state. Undeclared bytes are removed. Gradle owns
|
|
5175
|
+
incremental, task-cache and configuration-cache reuse; transfer digests never
|
|
5176
|
+
become reusable APK cache keys. Older hosts refuse before source upload.
|
|
5177
|
+
|
|
5178
|
+
outputs must list every build directory of this build's projects that the build
|
|
5179
|
+
creates: the root build directory and each module's, library modules included.
|
|
5180
|
+
A remote build that creates an undeclared one fails with its name, and Stim
|
|
5181
|
+
builds locally; add it to outputs. A buildSrc directory refuses before upload.
|
|
5182
|
+
Included builds (includeBuild, such as a build-logic plugin build) and
|
|
5183
|
+
externalNativeBuild staging (.cxx) are not reported by AGP and cannot be
|
|
5184
|
+
declared, so a remote build that creates them fails and Stim builds locally.
|
|
5185
|
+
|
|
5186
|
+
Native Android \`--plan\` refuses without executing Gradle; \`doctor\` reports native
|
|
5187
|
+
prerequisites. \`reload\` refuses because the app has no Metro runtime. Re-run
|
|
5188
|
+
\`stim android\` after an edit and use \`stim stop\` for scoped cleanup.`
|
|
5189
|
+
},
|
|
5190
|
+
ci: {
|
|
5191
|
+
summary: "Run an app and tests through @stim-cli/ci with diagnostics and scoped cleanup",
|
|
5192
|
+
body: () => `CONTINUOUS INTEGRATION
|
|
5193
|
+
|
|
5194
|
+
Install app dependencies and platform tools first. Use a dedicated checkout:
|
|
5195
|
+
cleanup stops that workspace, including resources created before a build fails.
|
|
5196
|
+
|
|
5197
|
+
npx --yes --package @stim-cli/ci stim-ci run --platform ios --project ./app --timeout 1800 -- pnpm test:e2e
|
|
5198
|
+
|
|
5199
|
+
Or install npm install --global @stim-cli/ci and use stim-ci directly.
|
|
5200
|
+
Platforms: ios, android, macos, web. Everything after -- is argv, not a shell.
|
|
5201
|
+
--artifacts selects the result directory (a fresh temporary directory by default).
|
|
5202
|
+
An explicit artifacts directory must be empty; use a new directory per run.
|
|
5203
|
+
Stdout is one JSON result; progress and test output go to stderr.
|
|
5204
|
+
|
|
5205
|
+
Tests receive STIM_CI_PLATFORM, STIM_CI_DEVICE_ID, STIM_CI_APP_ID,
|
|
5206
|
+
STIM_CI_METRO_PORT, STIM_CI_ARTIFACTS_DIR and STIM_CI_RUN_RESULT. The last is
|
|
5207
|
+
run.json with the exact public API result. Use that target and check app
|
|
5208
|
+
readiness; launched can still be bundling or unverified.
|
|
5209
|
+
|
|
5210
|
+
result.json preserves the test exit code even if diagnostics or cleanup fail.
|
|
5211
|
+
Passing tests with failed cleanup return 1; timeout returns 124; cancellation
|
|
5212
|
+
returns 130. Leave 70 seconds before the job's hard timeout for diagnostics and
|
|
5213
|
+
stop. SIGKILL and runner loss cannot run cleanup. Stop shuts down owned devices;
|
|
5214
|
+
it never deletes them.
|
|
5215
|
+
|
|
5216
|
+
GitHub-hosted jobs default to $RUNNER_TEMP/stim-ci/home and
|
|
5217
|
+
$RUNNER_TEMP/stim-ci/build-cache, reused between steps in the job. Detection
|
|
5218
|
+
requires GITHUB_ACTIONS=true, RUNNER_ENVIRONMENT=github-hosted and RUNNER_TEMP.
|
|
5219
|
+
An explicit --home or STIM_HOME keeps the selected home and its normal cache
|
|
5220
|
+
configuration; --build-cache or STIM_BUILD_CACHE overrides the cache path.
|
|
5221
|
+
Self-hosted runners and local runs keep normal Stim configuration. Other
|
|
5222
|
+
exclusive disposable providers can set their job-local paths explicitly.
|
|
5223
|
+
CI=true alone does not change defaults, ownership or coordination. Persist only
|
|
5224
|
+
cache artifacts, not state, claims or device ledgers. Independent homes must
|
|
5225
|
+
not share a writable filesystem cache because its claims live in the home.
|
|
5226
|
+
|
|
5227
|
+
The programmatic runner is import { runCI } from '@stim-cli/ci'. See its package
|
|
5228
|
+
README for result types, cancellation, cache policy, and coordination findings.`
|
|
5229
|
+
},
|
|
4962
5230
|
"hosted-android": {
|
|
4963
5231
|
summary: "Android on a named approved Mac: strict placement, private Metro, status and stop",
|
|
4964
5232
|
body: () => `ANDROID ON A HOSTING MAC
|
|
@@ -4982,7 +5250,7 @@ policy. No flag or setting runs on this Mac.
|
|
|
4982
5250
|
A named Mac is strict: refusal, unreachable, declined or failed preparation
|
|
4983
5251
|
returns STIM_HOSTING_REFUSED without fallback. --device, a different recorded
|
|
4984
5252
|
machine, a running local owned emulator in the slot, and --no-metro-check for
|
|
4985
|
-
hosted
|
|
5253
|
+
hosted Metro development apps refuse STIM_BAD_ARG. Run stim stop before switching placement.
|
|
4986
5254
|
Unreadable android.host blocks only its slot; restore its recorded machine and
|
|
4987
5255
|
session from the host before stopping that slot.
|
|
4988
5256
|
|
|
@@ -4992,7 +5260,7 @@ compatible build worker. Stim builds before reserving, records the session as
|
|
|
4992
5260
|
soon as it exists, then delivers one App.apk. The emulator boots headless;
|
|
4993
5261
|
androidEmulatorApp is ignored with a note.
|
|
4994
5262
|
|
|
4995
|
-
Debug requires the local Metro supervisor. metro.publicUrl and metro.tunnel
|
|
5263
|
+
React Native Debug requires the local Metro supervisor. metro.publicUrl and metro.tunnel
|
|
4996
5264
|
are ignored with a note. A private tailnet gateway reaches the host loopback
|
|
4997
5265
|
bridge; the host reverses the client's Metro port into that bridge on its exact
|
|
4998
5266
|
ledger-owned serial and sets debug_http_host to localhost:<clientMetroPort>.
|
|
@@ -5002,6 +5270,14 @@ adb against the host serial on this Mac. Release variants skip Metro. Launch
|
|
|
5002
5270
|
is true only with client bundle evidence or a live host release process;
|
|
5003
5271
|
bundling requires a bundle request and unverified has no launch evidence.
|
|
5004
5272
|
|
|
5273
|
+
Native Gradle apps use process mode for every variant. The host must advertise
|
|
5274
|
+
hosted-android-process; older hosts refuse before admission or APK upload.
|
|
5275
|
+
Native runs close any previous Metro bridge, launch the signed APK and require
|
|
5276
|
+
a live app process for launched=true. --no-metro-check is allowed, and reload
|
|
5277
|
+
refuses because there is no Metro runtime. Re-run stim android after an edit.
|
|
5278
|
+
Native EAS/proxy targets remain unsupported. Build offload requires the complete
|
|
5279
|
+
android.offloadInputs declaration; see stim guide lifecycle native-android.
|
|
5280
|
+
|
|
5005
5281
|
Status adds android.host { machine, session, selected, agent, device: { name,
|
|
5006
5282
|
systemImage, api }, state } per slot. The public name is the profile and API
|
|
5007
5283
|
level, never the host serial or AVD name. ready, stopped and unverified are
|
|
@@ -5125,7 +5401,10 @@ there is a free concurrency.maxDevices slot (0 means unlimited), no device
|
|
|
5125
5401
|
waiter ahead, normal host memory pressure, no budget shortfall,
|
|
5126
5402
|
and 5-minute load per core below server.maxLoadPerCore. Without remote.machines,
|
|
5127
5403
|
auto is local. An unknown local device count also stays local; boot admission
|
|
5128
|
-
still decides. The default without a flag or setting stays local.
|
|
5404
|
+
still decides. The default without a flag or setting stays local. remote.devicePoolDisabled excludes
|
|
5405
|
+
members from new automatic placement only; an excluded local member is never a
|
|
5406
|
+
fallback. Existing sessions keep their owner and named placement bypasses the pool.
|
|
5407
|
+
See stim guide settings for separate build/device membership controls.
|
|
5129
5408
|
|
|
5130
5409
|
Otherwise Stim asks every approved remote.machines host in parallel, with a
|
|
5131
5410
|
3-second probe timeout and this run's model/runtime or image/profile selectors.
|
|
@@ -5136,9 +5415,24 @@ Hosts rank by the build preference (flag > STIM_REMOTE_BUILD > remote.build)
|
|
|
5136
5415
|
when it names a machine, then lowest load, most free memory and remote.machines order. Automatic build
|
|
5137
5416
|
offload resolves later, after the device architecture is known.
|
|
5138
5417
|
|
|
5139
|
-
When no host admits
|
|
5418
|
+
When no host admits and this Mac is at its concurrency.maxDevices cap (or runs
|
|
5419
|
+
are queued ahead), remote.easFallback (default false; EAS Simulator is billed)
|
|
5420
|
+
runs the device on an EAS Simulator exactly as --remote eas would: the build
|
|
5421
|
+
stays here, nothing starts an EAS cloud build, stop ends the session, and
|
|
5422
|
+
status reports it under remoteDevices. A busy Mac with a free slot never uses
|
|
5423
|
+
it. Before choosing it Stim checks, without starting a session, that eas-cli
|
|
5424
|
+
has simulator commands (and 22.2.0+ for --device-type), eas
|
|
5425
|
+
simulator:availability says this project's account can use it, agent-device
|
|
5426
|
+
is on PATH, the slot is default, no --runtime, --system-image or
|
|
5427
|
+
--device-profile flag is given, no EAS Simulator session of this workspace runs
|
|
5428
|
+
another platform or model, and a Debug run's Metro is reachable (not
|
|
5429
|
+
metro.tunnel off; on an Expo tunnel, run stim start --remote first). A recorded
|
|
5430
|
+
EAS session is not sticky: once this Mac has room, auto runs here and the
|
|
5431
|
+
session bills until stim stop. If any check fails, or the
|
|
5432
|
+
setting is off, auto runs here and may wait in the existing FIFO device
|
|
5140
5433
|
slot queue; --no-wait and --wait 0 refuse with STIM_AT_CAPACITY. The placement
|
|
5141
|
-
line explains the decision
|
|
5434
|
+
line explains the decision, the skipped hosts and why EAS was not used
|
|
5435
|
+
(machine "eas"). JSON progress goes to stderr.
|
|
5142
5436
|
The same decision, with a reason code per host, is a src: placement record in
|
|
5143
5437
|
stim logs (stim guide logs).
|
|
5144
5438
|
A recorded hosted session wins over load; a live local owned slot stays here.
|
|
@@ -5180,7 +5474,7 @@ sessions.
|
|
|
5180
5474
|
|
|
5181
5475
|
|
|
5182
5476
|
Stim builds or fetches before reserving, records the session immediately, then
|
|
5183
|
-
uploads the app on every run. Debug
|
|
5477
|
+
uploads the app on every run. React Native and Expo Debug keep Metro here; the supervisor owns a
|
|
5184
5478
|
private gateway bound to this Mac's Tailscale address, pinned to the host peer
|
|
5185
5479
|
and protected by a per-session secret. The host exposes only a loopback bridge.
|
|
5186
5480
|
No start --remote is needed; metro.tunnel and metro.publicUrl are ignored.
|
|
@@ -5188,7 +5482,8 @@ Debug requires a running supervisor with private gateway support before reservin
|
|
|
5188
5482
|
a simulator. --no-metro-check refuses with STIM_BAD_ARG for hosted Debug runs.
|
|
5189
5483
|
If its supervisor is missing or older, run stim stop; stim start, then retry.
|
|
5190
5484
|
Non-Debug runs skip Metro. Launch is unverified until this workspace's Metro
|
|
5191
|
-
provides bundle evidence, or the host proves a live release process.
|
|
5485
|
+
provides bundle evidence, or the host proves a live release process. Native Xcode
|
|
5486
|
+
apps use process mode in every configuration and require no Metro; see native-ios.
|
|
5192
5487
|
|
|
5193
5488
|
A rerun on the same named Mac reattaches and delivers a new app attempt. A
|
|
5194
5489
|
stopped or missing session is replaced; an unreachable or unknown owner refuses
|
|
@@ -5861,6 +6156,11 @@ PREDICTING THE NEXT BUILD (--plan)
|
|
|
5861
6156
|
installing, or starting Metro. They take no workspace lock and write no
|
|
5862
6157
|
Stim state, cache entry or statistic, so they run beside a build.
|
|
5863
6158
|
|
|
6159
|
+
The selected project integration supplies the read-only plan and uses its
|
|
6160
|
+
build recipe's identity and cache policy. If it has no planner, --plan
|
|
6161
|
+
refuses with STIM_BAD_ARG; run the command without --plan. The refusal
|
|
6162
|
+
reports no cache hit. React Native and Expo planning behaves as follows.
|
|
6163
|
+
|
|
5864
6164
|
stim ios --plan
|
|
5865
6165
|
plan ios 1b625d.. -> local cache hit
|
|
5866
6166
|
expect ~2.7s (median of 1 hit run)
|
|
@@ -5899,8 +6199,9 @@ PREDICTING THE NEXT BUILD (--plan)
|
|
|
5899
6199
|
this Mac and a listed Mac would build for another architecture, placement
|
|
5900
6200
|
says so, since that Mac's key differs. The plan only predicts the key: a
|
|
5901
6201
|
run reads the architecture of the device it actually gets. A Mac that does
|
|
5902
|
-
not answer,
|
|
5903
|
-
|
|
6202
|
+
not answer, ios.remote or android.remote set to eas or proxy, or auto that
|
|
6203
|
+
would use an EAS Simulator now (remote.easFallback), refuses with
|
|
6204
|
+
STIM_BAD_ARG. Without --eas-profile an Android plan also
|
|
5904
6205
|
refuses the experimental compiler CAS with STIM_BAD_ARG, and refuses with
|
|
5905
6206
|
STIM_NO_DEVICE when no system image is installed.
|
|
5906
6207
|
|
|
@@ -5910,13 +6211,16 @@ IOS SCHEME SELECTION
|
|
|
5910
6211
|
Xcode scheme, not the app's URL scheme. Combine it with --configuration
|
|
5911
6212
|
when choosing both an app scheme and a build configuration.
|
|
5912
6213
|
|
|
5913
|
-
|
|
6214
|
+
The ios.scheme setting names the scheme once for the app (guide settings);
|
|
6215
|
+
--scheme overrides it per run, and both give the same keys below.
|
|
6216
|
+
|
|
6217
|
+
Without --scheme or ios.scheme, automatic selection is unchanged:
|
|
5914
6218
|
Stim keeps a scheme matching the workspace/project name, or the sole non-test
|
|
5915
6219
|
scheme. When neither identifies one, it also checks the static top-level name
|
|
5916
6220
|
in the app directory's app.json against Xcode's listed schemes. It does not
|
|
5917
6221
|
execute app config or choose an arbitrary scheme from an ambiguous list.
|
|
5918
|
-
If selection fails, pass --scheme with an available name,
|
|
5919
|
-
scheme in Xcode first. See guide errors STIM_NO_SCHEME.
|
|
6222
|
+
If selection fails, pass --scheme with an available name, set ios.scheme, or
|
|
6223
|
+
share the app scheme in Xcode first. See guide errors STIM_NO_SCHEME.
|
|
5920
6224
|
|
|
5921
6225
|
Explicit schemes have separate artifact keys, shared-build locks, and Xcode
|
|
5922
6226
|
build directories. Stim identifies the resulting application from Xcode's
|
|
@@ -5925,7 +6229,8 @@ IOS SCHEME SELECTION
|
|
|
5925
6229
|
configured Stim cache providers use the scheme-specific key. The older Expo
|
|
5926
6230
|
buildCacheProvider tier is skipped for explicit schemes because a provider
|
|
5927
6231
|
may key only on the fingerprint and return another scheme's app. Omitting
|
|
5928
|
-
--scheme retains the existing cache keys and provider
|
|
6232
|
+
both --scheme and ios.scheme retains the existing cache keys and provider
|
|
6233
|
+
behavior.
|
|
5929
6234
|
|
|
5930
6235
|
AN ARTIFACT THE DEVICE ALREADY HOLDS IS NOT INSTALLED AGAIN
|
|
5931
6236
|
Both platforms store the artifact verbatim, so its hash is its identity.
|
|
@@ -5967,7 +6272,9 @@ A RUNNING APP IS RESTARTED, LIKE XCODE'S RUN
|
|
|
5967
6272
|
launch com.example.app restarted running app (was pid 4242) (0.9s)
|
|
5968
6273
|
|
|
5969
6274
|
A stop that fails refuses the launch rather than reusing the old process.
|
|
5970
|
-
When
|
|
6275
|
+
When a simulator's process list cannot be read, Stim launches with
|
|
6276
|
+
\`simctl launch --terminate-running-process\`, which replaces any running
|
|
6277
|
+
copy. When an emulator's cannot be read, Stim launches without stopping
|
|
5971
6278
|
anything and verification reports what it observes. An iPhone run
|
|
5972
6279
|
(\`ios --device\`) needs no extra step: its collector launches with
|
|
5973
6280
|
devicectl's \`--terminate-existing\`. Remote targets launch through
|
|
@@ -6886,7 +7193,7 @@ OPT-IN CONCURRENCY LIMITS (UNLIMITED BY DEFAULT)
|
|
|
6886
7193
|
MUTATE: the cache entry stays the pristine, shareable artifact, and the
|
|
6887
7194
|
per-run address lives only in the copy that is installed and then deleted.
|
|
6888
7195
|
|
|
6889
|
-
A RELEASE device run builds fresh every time for now. A cached Release app
|
|
7196
|
+
A React Native or Expo RELEASE device run builds fresh every time for now. A cached Release app
|
|
6890
7197
|
carries its BUILDER's JS, and the device JS swap (which has to re-seal what
|
|
6891
7198
|
it injects) lands with phase 6 of appandflow/stim#178, so the cache hit is
|
|
6892
7199
|
refused rather than installed with someone else's JavaScript.
|
|
@@ -7101,8 +7408,8 @@ THE POOL: WHICH DEVICE AN ID-LESS \`--device\` PICKS
|
|
|
7101
7408
|
distribution stay out of scope.
|
|
7102
7409
|
|
|
7103
7410
|
\`ios --configuration <name>\` selects the Xcode configuration --
|
|
7104
|
-
\`--configuration Release\` builds a SIMULATOR
|
|
7105
|
-
bundle embedded. It overrides the ios.configuration setting (the app-level
|
|
7411
|
+
for React Native and Expo, \`--configuration Release\` builds a SIMULATOR
|
|
7412
|
+
Release app with the JS bundle embedded. It overrides the ios.configuration setting (the app-level
|
|
7106
7413
|
default); unset, the Debug flow is unchanged. A non-Debug configuration
|
|
7107
7414
|
skips Metro ENTIRELY: no gate, no port wiring, no dev-client deep link (a
|
|
7108
7415
|
plain \`simctl launch\`), and the payload says \`metroPort: null\` --
|
|
@@ -7191,6 +7498,19 @@ HOST MEMORY PRESSURE AND STALLED SIMULATORS
|
|
|
7191
7498
|
a failed query remains unknown. Existing swap or low free RAM alone is not
|
|
7192
7499
|
enough to diagnose pressure.
|
|
7193
7500
|
|
|
7501
|
+
Doctor, and boot messages under warning or critical pressure, also name any
|
|
7502
|
+
process whose physical footprint is abnormal, read from macOS top (it counts
|
|
7503
|
+
compressed and swapped memory, which ps RSS leaves out, and reads root-owned
|
|
7504
|
+
daemons). Abnormal is at least a quarter of physical memory and 8 GiB, or
|
|
7505
|
+
2 GiB for fseventsd and Watchman, which are normally far smaller. A known
|
|
7506
|
+
safe-to-restart process comes with its command; Stim never runs it:
|
|
7507
|
+
fseventsd sudo killall fseventsd (launchd restarts it;
|
|
7508
|
+
file watchers rescan once)
|
|
7509
|
+
Watchman stim gc --delete --cache watchman
|
|
7510
|
+
Gradle or Kotlin daemon stim gc --delete --cache gradle-daemons
|
|
7511
|
+
Any other process is named with its size only; ask before quitting it.
|
|
7512
|
+
Doctor skips this check when STIM_HOME is set: processes are machine-global.
|
|
7513
|
+
|
|
7194
7514
|
If pressure is elevated, free host memory before retrying. Use \`stim stop\`
|
|
7195
7515
|
only in workspaces you own and have finished using; ask before closing other
|
|
7196
7516
|
agents' simulators or heavy apps. Never quit Device Hub or Simulator.app to
|
|
@@ -7239,7 +7559,9 @@ Pressure checks read free disk on the Stim home, projects and worker root
|
|
|
7239
7559
|
volumes. On macOS the memory signal is the sysctl pressure level, with no
|
|
7240
7560
|
signal if sysctl fails. Other platforms use os.freemem(); macOS never falls
|
|
7241
7561
|
back to it. Memory pressure is recorded only; stopping devices, dev servers
|
|
7242
|
-
and helpers is not automatic.
|
|
7562
|
+
and helpers is not automatic. While the level is warning or critical, the
|
|
7563
|
+
check also names abnormally large processes (guide lifecycle simslim) in
|
|
7564
|
+
status's maintenance block and the maintenance log.
|
|
7243
7565
|
|
|
7244
7566
|
In on mode a pass runs, cheapest to rebuild first:
|
|
7245
7567
|
1. orphaned workspace directories whose project is gone, and registered
|
|
@@ -7620,11 +7942,11 @@ STALE STATUS CACHE ENTRIES
|
|
|
7620
7942
|
if it comes back.
|
|
7621
7943
|
|
|
7622
7944
|
NAMED SERVER PORTS
|
|
7623
|
-
worktree remove
|
|
7624
|
-
|
|
7625
|
-
|
|
7626
|
-
registered.
|
|
7627
|
-
stim stop does not touch named ports. See guide ports.
|
|
7945
|
+
worktree remove, gc --delete and automatic maintenance release named
|
|
7946
|
+
allocations without signalling their listeners. gc reports named
|
|
7947
|
+
allocations for missing workspaces; gc --delete releases them. Unmounted or
|
|
7948
|
+
unresolved paths stay registered. Only ports stop stops a named listener,
|
|
7949
|
+
and stim stop does not touch named ports. See guide ports.
|
|
7628
7950
|
|
|
7629
7951
|
ON THE SOURCE CHECKOUT
|
|
7630
7952
|
git cannot remove a repository's main working tree, and deleting the source
|
|
@@ -7873,7 +8195,23 @@ THE ONE CASE GC WILL NOT REAP
|
|
|
7873
8195
|
|
|
7874
8196
|
--older-than does not apply to these kinds and is refused with
|
|
7875
8197
|
STIM_BAD_ARG. With STIM_HOME set, gc skips them: they are machine-global.
|
|
7876
|
-
\`stim doctor\` notes a watchman footprint over 2 GiB
|
|
8198
|
+
\`stim doctor\` notes a watchman footprint over 2 GiB.
|
|
8199
|
+
|
|
8200
|
+
A checkout that holds its linked worktrees inside it, such as
|
|
8201
|
+
.worktrees/<name>, makes a watchman root there crawl every worktree's files,
|
|
8202
|
+
node_modules and build output. \`stim doctor\` reports each such checkout
|
|
8203
|
+
whose .watchmanconfig ignore_dirs does not exclude them, as
|
|
8204
|
+
${WATCHMAN_NESTED_WORKTREES}, and says when watchman watches it now.
|
|
8205
|
+
\`stim doctor --fix\` merges the worktrees' shared parent (.worktrees) when
|
|
8206
|
+
git tracks nothing in it, otherwise each worktree path, into that
|
|
8207
|
+
checkout's .watchmanconfig and keeps every other key; it refuses a file
|
|
8208
|
+
that is not a JSON object or whose ignore_dirs is not an array. Watchman
|
|
8209
|
+
matches entries literally: \`.worktrees/\` or \`./.worktrees\` ignores
|
|
8210
|
+
nothing. Commit the file. Watchman reads ignore_dirs only from a root's
|
|
8211
|
+
.watchmanconfig, never from a global config, and only when it adds the
|
|
8212
|
+
root, so an existing root needs \`watchman watch-del <root>\` before the
|
|
8213
|
+
ignore applies. Doctor never runs watch-del or shutdown-server; a watch-del
|
|
8214
|
+
plus a watchman restart frees the memory now.`
|
|
7877
8215
|
},
|
|
7878
8216
|
disk: {
|
|
7879
8217
|
summary: "disk usage, workspace build outputs, logs and device recordings, AVD and build-log sizes, the data partition, trimming the shared caches",
|
|
@@ -8120,6 +8458,15 @@ KEYS STIM READS
|
|
|
8120
8458
|
The \`--runtime\` flag overrides this per invocation,
|
|
8121
8459
|
and an uninstalled version refuses the same way,
|
|
8122
8460
|
naming the layer the value came from
|
|
8461
|
+
ios.scheme e.g. "RNTester" -- the shared Xcode scheme to build
|
|
8462
|
+
when the workspace lists several and none matches
|
|
8463
|
+
its name, which otherwise refuses with
|
|
8464
|
+
STIM_NO_SCHEME. The \`--scheme\` flag overrides it
|
|
8465
|
+
per invocation; an \`--eas-profile\` build reads only
|
|
8466
|
+
the flag. Part of the cache key, like the flag, so
|
|
8467
|
+
it also skips the older Expo buildCacheProvider tier,
|
|
8468
|
+
which may key only on the fingerprint. Workspace or
|
|
8469
|
+
committed scope.
|
|
8123
8470
|
ios.configuration e.g. "Release" -- the Xcode configuration to build
|
|
8124
8471
|
(simulator only). Committing
|
|
8125
8472
|
{ "ios": { "configuration": "Release" } } makes every
|
|
@@ -8130,7 +8477,21 @@ KEYS STIM READS
|
|
|
8130
8477
|
ios.remote "proxy", "eas", or a named approved Mac from
|
|
8131
8478
|
remote.machines, with the same meaning as --remote.
|
|
8132
8479
|
"auto" places on an approved Mac when this Mac is full or
|
|
8133
|
-
busy. Unset runs here
|
|
8480
|
+
busy. Unset runs here; "local" runs here even when a
|
|
8481
|
+
lower layer says otherwise. See lifecycle hosted-ios.
|
|
8482
|
+
ios.projectPath directory under the app holding a bare React Native
|
|
8483
|
+
app's Xcode project and Podfile; default "ios". "."
|
|
8484
|
+
is the app directory itself (RNTester's layout).
|
|
8485
|
+
Detection, pod install, xcodebuild, the bundle id,
|
|
8486
|
+
doctor, worktree warm and remove, and remote builds
|
|
8487
|
+
all use it. A subdirectory is fingerprinted the way
|
|
8488
|
+
ios/ is; "." hashes every top-level entry except
|
|
8489
|
+
node_modules, Pods, build, android, .stim.json and
|
|
8490
|
+
anything git ignores, so a JS edit misses the build
|
|
8491
|
+
cache instead of risking a stale build. Workspace or committed scope. ios refuses
|
|
8492
|
+
with STIM_BAD_ARG a path that escapes the app or
|
|
8493
|
+
holds no .xcworkspace or .xcodeproj, and any value
|
|
8494
|
+
on an Expo app, whose prebuild writes ios/.
|
|
8134
8495
|
ios.simslimProfile a SimSlim JSON profile under the app directory,
|
|
8135
8496
|
at most 64 KiB. Install the
|
|
8136
8497
|
external tool once with
|
|
@@ -8241,6 +8602,26 @@ ${ANDROID_AVD_CONFIG_HELP.map((line) => ` ${line}`).joi
|
|
|
8241
8602
|
and hw.audioOutput for that headless launch. With
|
|
8242
8603
|
androidEmulatorApp "stim-desktop" on macOS, -gpu host
|
|
8243
8604
|
overrides hw.gpu.mode the same way.
|
|
8605
|
+
android.gradleRoot directory holding gradlew and settings.gradle(.kts),
|
|
8606
|
+
relative to the app; default "android". It may sit
|
|
8607
|
+
outside the app but not outside the repository:
|
|
8608
|
+
RNTester in the React Native monorepo uses "../..".
|
|
8609
|
+
android.module the app's Gradle project path; default ":app", e.g.
|
|
8610
|
+
":packages:rn-tester:android:app". Its directory is
|
|
8611
|
+
Gradle's default mapping from the root and must hold
|
|
8612
|
+
a build.gradle(.kts). With either set, Gradle runs
|
|
8613
|
+
from the root with qualified tasks such as
|
|
8614
|
+
<module>:assembleDebug; both values join the cache
|
|
8615
|
+
key and the remote build job, and the root's
|
|
8616
|
+
settings, build script, gradle.properties and
|
|
8617
|
+
gradle/ are fingerprinted. Native sources Gradle
|
|
8618
|
+
builds from elsewhere in the repository are not:
|
|
8619
|
+
list them in fingerprint.config.js extraSources.
|
|
8620
|
+
android refuses with STIM_BAD_ARG a root outside the
|
|
8621
|
+
repository or without settings.gradle, a module
|
|
8622
|
+
without a build script, and either value on an Expo
|
|
8623
|
+
app, whose prebuild writes android/. Workspace or
|
|
8624
|
+
committed scope.
|
|
8244
8625
|
android.variant e.g. "productionDebug" -- the gradle variant to
|
|
8245
8626
|
assemble and install on a project with product
|
|
8246
8627
|
flavors. A repo like tlon-mobile with
|
|
@@ -8256,24 +8637,55 @@ ${ANDROID_AVD_CONFIG_HELP.map((line) => ` ${line}`).joi
|
|
|
8256
8637
|
build: embedded JS, no Metro, cache keyed on the
|
|
8257
8638
|
variant, and an APK re-pack on cache hits. See
|
|
8258
8639
|
\`guide lifecycle release\`.
|
|
8640
|
+
android.offloadInputs a native Gradle build-worker declaration:
|
|
8641
|
+
{"complete":true,"ignored":[],"outputs":["build","app/build"]}.
|
|
8642
|
+
complete confirms Git-visible source plus the exact
|
|
8643
|
+
repository-relative ignored files suffice for this
|
|
8644
|
+
build. outputs names generated directories reported
|
|
8645
|
+
by AGP; recorded outputs can survive worker sync.
|
|
8646
|
+
Omitted optional inputs can change build results.
|
|
8647
|
+
Stim artifact caching remains unavailable. See
|
|
8648
|
+
\`stim guide lifecycle native-android\` for input,
|
|
8649
|
+
privacy and worker requirements.
|
|
8259
8650
|
android.keystore the keystore a RE-PACKED release APK is signed with,
|
|
8260
8651
|
absolute or relative to the project root. Unset means
|
|
8261
8652
|
android/app/debug.keystore, which every RN and Expo
|
|
8262
8653
|
android project carries -- the right default, because
|
|
8263
8654
|
what this signs is a local emulator install and never
|
|
8264
8655
|
anything distributed. Set it only when the release
|
|
8265
|
-
variant must be signed with the repo's own key.
|
|
8656
|
+
variant must be signed with the repo's own key. A
|
|
8657
|
+
value in the committed .stim.json must resolve
|
|
8658
|
+
inside the repository (symlinks included); an
|
|
8659
|
+
absolute path outside it needs --scope workspace
|
|
8660
|
+
or repo.
|
|
8266
8661
|
android.keystorePassword
|
|
8267
8662
|
the password for it. apksigner's SCHEMED form is
|
|
8268
8663
|
passed through unchanged (\`env:MY_KS_PASS\`,
|
|
8269
8664
|
\`file:/keys/pw.txt\`, \`stdin\`), which is how a
|
|
8270
8665
|
committed .stim.json avoids carrying a secret; a
|
|
8271
|
-
bare string
|
|
8272
|
-
|
|
8666
|
+
bare string (or \`pass:<password>\`) is the literal
|
|
8667
|
+
password, handed to apksigner through its
|
|
8668
|
+
environment, never its command line. Unset means
|
|
8669
|
+
the debug keystore's fixed "android".
|
|
8273
8670
|
android.remote "proxy", "eas", or a named approved Mac in
|
|
8274
8671
|
remote.machines; "auto" places on an approved Mac when
|
|
8275
|
-
this Mac is full or busy. Unset runs here
|
|
8672
|
+
this Mac is full or busy. Unset runs here; "local"
|
|
8673
|
+
runs here even when a lower layer says otherwise.
|
|
8276
8674
|
See lifecycle hosted-android.
|
|
8675
|
+
remote.easFallback true lets "auto" (ios.remote, android.remote or
|
|
8676
|
+
--remote auto) run the simulator or emulator on a
|
|
8677
|
+
billed EAS Simulator when this Mac is at its
|
|
8678
|
+
concurrency.maxDevices cap (or has runs queued) and no
|
|
8679
|
+
remote.machines Mac takes the run, instead of waiting
|
|
8680
|
+
or refusing with STIM_AT_CAPACITY. Default false. A
|
|
8681
|
+
busy Mac with a free slot never uses it. Stim checks
|
|
8682
|
+
first that the run could use --remote eas (eas-cli
|
|
8683
|
+
with simulator commands, eas simulator:availability,
|
|
8684
|
+
agent-device, the default slot, a reachable Metro);
|
|
8685
|
+
otherwise it waits or refuses as before. Machine or
|
|
8686
|
+
project scope; a committed value opts in everyone who
|
|
8687
|
+
runs the app. Only the user enables it. See lifecycle
|
|
8688
|
+
hosted-ios.
|
|
8277
8689
|
metro.tunnel selects how a remote device reaches this workspace's
|
|
8278
8690
|
Metro after remote intent exists. Plain \`start\` stays
|
|
8279
8691
|
local. For Expo and bare React Native, "auto" (default)
|
|
@@ -8288,6 +8700,21 @@ ${ANDROID_AVD_CONFIG_HELP.map((line) => ` ${line}`).joi
|
|
|
8288
8700
|
foreground serve process, never Funnel; "auto" never
|
|
8289
8701
|
selects it. The device must share the tailnet. See
|
|
8290
8702
|
\`guide metro\`. Any other value is refused as invalid.
|
|
8703
|
+
metro.command argv array that starts this app's dev server, for an
|
|
8704
|
+
app whose Metro only runs through its own command,
|
|
8705
|
+
e.g. ["node", "../react-native/cli.js", "start",
|
|
8706
|
+
"--port", "{port}"]. No shell; it runs from the app
|
|
8707
|
+
directory, and {port} becomes the reserved Metro port,
|
|
8708
|
+
which the command must pass. It replaces bare-inproc
|
|
8709
|
+
and expo-child with command-child (see \`guide
|
|
8710
|
+
metro\`). Workspace or committed scope.
|
|
8711
|
+
Metro must keep running from inside the app, which
|
|
8712
|
+
is how Stim proves it is this app's. Without Stim's
|
|
8713
|
+
Metro reporter, launches stay UNVERIFIED. start
|
|
8714
|
+
refuses with STIM_BAD_ARG a value that is not such an
|
|
8715
|
+
array or has no {port}, --reset-cache (put the
|
|
8716
|
+
command's own reset flag in metro.command instead),
|
|
8717
|
+
and any use on Windows.
|
|
8291
8718
|
metro.ngrokUrl the stable managed ngrok URL. It requires metro.tunnel
|
|
8292
8719
|
"ngrok" and passes --url to ngrok http. Stim owns
|
|
8293
8720
|
this process.
|
|
@@ -8522,8 +8949,9 @@ To show the booted simulator in Stim Desktop and open no simulator window:
|
|
|
8522
8949
|
|
|
8523
8950
|
{ "iosSimulatorApp": "stim-desktop" }
|
|
8524
8951
|
|
|
8525
|
-
Stim Desktop
|
|
8526
|
-
|
|
8952
|
+
Stim Desktop keeps the current page and shows a launch card. Clicking Show
|
|
8953
|
+
opens the workspace that owns the simulator and focuses that device.
|
|
8954
|
+
It only displays the simulator; it never boots or shuts it down.
|
|
8527
8955
|
When Stim Desktop is not running, Stim starts it without the command's
|
|
8528
8956
|
\`STIM_HOME\`, so it reads the same Stim home as when you open it yourself.
|
|
8529
8957
|
It shows only devices from that home: under another \`STIM_HOME\`, pick
|
|
@@ -8552,7 +8980,8 @@ headlessly and show it in Stim Desktop:
|
|
|
8552
8980
|
{ "androidEmulatorApp": "stim-desktop" }
|
|
8553
8981
|
|
|
8554
8982
|
Stim then starts the emulator with \`-no-window -gpu host\` and opens
|
|
8555
|
-
\`stim-desktop://open?serial=<serial>\` in the background. Stim Desktop
|
|
8983
|
+
\`stim-desktop://open?serial=<serial>\` in the background. Stim Desktop shows a
|
|
8984
|
+
launch card and opens the emulator only when Show is clicked. It reads
|
|
8556
8985
|
frames and sends input over the emulator's gRPC endpoint. The setting applies
|
|
8557
8986
|
only when Stim boots the emulator: one that is already running keeps its
|
|
8558
8987
|
current display until it next boots, and physical devices are unaffected.
|
|
@@ -8635,6 +9064,32 @@ simulator sessions on, by MagicDNS name with an optional serve port (default
|
|
|
8635
9064
|
stim settings set remote.machines '["janics-mac-mini"]'
|
|
8636
9065
|
stim doctor --fix
|
|
8637
9066
|
|
|
9067
|
+
Automatic membership is separate from approval. In Desktop Settings > Remote Macs,
|
|
9068
|
+
use Builds enabled and Simulators enabled for this Mac or a configured remote.
|
|
9069
|
+
The equivalent machine settings list the excluded members; both default to []:
|
|
9070
|
+
|
|
9071
|
+
stim settings set remote.buildPoolDisabled '["local"]'
|
|
9072
|
+
stim settings set remote.devicePoolDisabled '["janics-mac-mini"]'
|
|
9073
|
+
stim settings unset remote.buildPoolDisabled
|
|
9074
|
+
|
|
9075
|
+
Use local for this Mac and exact remote.machines entries for remotes, including
|
|
9076
|
+
case and port. Names are not trimmed; unmatched entries exclude nothing. Copy the
|
|
9077
|
+
configured name or use Desktop's switches. Each pool
|
|
9078
|
+
must retain local or at least one configured remote already approved for that role.
|
|
9079
|
+
Offline approved members count as configured members, but placement still requires
|
|
9080
|
+
an available compatible host. Settings refuses removing the last member, including
|
|
9081
|
+
removing it from remote.machines. Disabling does not unpair a machine or stop a run.
|
|
9082
|
+
|
|
9083
|
+
These settings apply only to new automatic work requested by this Mac. They do not
|
|
9084
|
+
change which work other requesters send to a host. Named placement and --remote-build
|
|
9085
|
+
local bypass membership; the default device placement without --remote auto remains
|
|
9086
|
+
local. Existing local and hosted device sessions keep their owner. Cache hits remain
|
|
9087
|
+
usable without compiling. If local is excluded, automatic placement cannot fall back
|
|
9088
|
+
to a local compile or boot; unavailable hosts and unsupported offloads refuse. Excluding
|
|
9089
|
+
local alone does not trigger billed EAS fallback; an existing explicit EAS opt-in still
|
|
9090
|
+
requires the physical device cap or queue condition. Restore membership before retrying or choose
|
|
9091
|
+
an explicit placement. Build and simulator memberships are independent.
|
|
9092
|
+
|
|
8638
9093
|
A remote Mac is used for a capability only after it grants that approval. Build
|
|
8639
9094
|
and device-host approvals are separate: a Mac in the list that never granted
|
|
8640
9095
|
one is not an error, it is not used for that capability, and doctor reports
|
|
@@ -8726,7 +9181,7 @@ value is unset. Trimmed auto/local are case-insensitive. Machine names match
|
|
|
8726
9181
|
configured names case-insensitively, with port 7443 when omitted; reports use
|
|
8727
9182
|
the configured entry.
|
|
8728
9183
|
|
|
8729
|
-
auto follows remote.buildMode
|
|
9184
|
+
auto follows remote.buildMode, considering only enabled automatic pool members
|
|
8730
9185
|
local builds only on this Mac for this invocation
|
|
8731
9186
|
name requires a matching entry in remote.machines, already paired and
|
|
8732
9187
|
approved for builds; ignores remote.buildMode and this Mac's load/slot gating
|
|
@@ -8765,7 +9220,7 @@ emulator debug build or a stim macos SwiftPM Debug build compiles:
|
|
|
8765
9220
|
Mac's. A Mac too old to report its load counts only while every
|
|
8766
9221
|
slot here is busy.
|
|
8767
9222
|
force on a remote Mac whenever one accepts it
|
|
8768
|
-
off
|
|
9223
|
+
off here when local remains enabled in the automatic build pool
|
|
8769
9224
|
|
|
8770
9225
|
Load per core is the 5-minute load average divided by the CPU count; a Mac's
|
|
8771
9226
|
native builds are its Stim runs in prebuild, pods or compile on that Mac, not
|
|
@@ -8793,7 +9248,7 @@ iPhone simulator on the target runtime. Its project-selected CocoaPods must matc
|
|
|
8793
9248
|
the app's Gemfile.lock pins CocoaPods: both Macs then run that version through
|
|
8794
9249
|
bundler, so the machine needs only Bundler on its stim-server PATH and
|
|
8795
9250
|
installs the pinned gems itself on the first build. The comparison selects
|
|
8796
|
-
the app's .ruby-version when installed, with pod install's UTF-8 locale defaults.
|
|
9251
|
+
the app's .ruby-version when installed, and otherwise the GEM_HOME, GEM_PATH and Ruby-related PATH entries of the Mac's login shell (read once with $SHELL -lic), unless the caller already sets GEM_HOME, with pod install's UTF-8 locale defaults. pod install, including the Bundler run, uses the same environment.
|
|
8797
9252
|
For Android its JDK major
|
|
8798
9253
|
version must match, and its Android SDK must hold the NDK, build-tools and
|
|
8799
9254
|
compile platform that the project's React Native version names in
|
|
@@ -9225,7 +9680,7 @@ the same as for any web project: start the dev server, then run stim web.
|
|
|
9225
9680
|
stim logs --errors
|
|
9226
9681
|
stim reload web
|
|
9227
9682
|
stim stop # closes Chrome; stim ports stop web stops Vite
|
|
9228
|
-
stim worktree remove # in a linked worktree: Chrome
|
|
9683
|
+
stim worktree remove # in a linked worktree: Chrome and profile, not Vite
|
|
9229
9684
|
|
|
9230
9685
|
The repo layer is shared by every worktree of the repository, so a new
|
|
9231
9686
|
worktree skips the two settings lines; the certificate and scheme remedies
|
|
@@ -9416,18 +9871,39 @@ executables, including Stim Desktop's sim-fold helper, are not built.
|
|
|
9416
9871
|
|
|
9417
9872
|
stim macos # fixed SwiftPM Debug build, then launch
|
|
9418
9873
|
stim macos --json # one launch record; progress goes to stderr
|
|
9874
|
+
stim macos --plan --json # validate the next build without running it
|
|
9419
9875
|
stim status --json # environments[].macos and build state
|
|
9420
9876
|
stim logs --source build
|
|
9421
9877
|
stim logs --errors
|
|
9422
9878
|
stim stop # stop this workspace's owned app and supervisor
|
|
9423
9879
|
|
|
9424
|
-
Each invocation
|
|
9880
|
+
Each invocation validates the project settings, development plist and resource
|
|
9881
|
+
entries before stopping its previous owned app, rebuilding and launching. SwiftPM
|
|
9425
9882
|
keeps incremental outputs in the workspace's runtime directory under STIM_HOME.
|
|
9883
|
+
Every process running an app bundle from that directory is the workspace's
|
|
9884
|
+
owned app, including copies opened through LaunchServices (open, agent-device
|
|
9885
|
+
open). stim macos, stim stop, stim worktree remove and stim gc --delete stop all
|
|
9886
|
+
of them: SIGTERM, up to 5 s, then SIGKILL, and success only once each has
|
|
9887
|
+
exited. When an app cannot be verified or does not exit, stop reports
|
|
9888
|
+
STIM_MACOS_OWNER_UNVERIFIED or a failure, and removal keeps the workspace.
|
|
9426
9889
|
Local stim macos starts the app in the background without activating it or
|
|
9427
9890
|
changing focus: it sets STIM_BACKGROUND_LAUNCH=1 in the app's environment, which
|
|
9428
|
-
Stim Desktop honors
|
|
9891
|
+
Stim Desktop honors, including for reopen events from open -g. An app that
|
|
9892
|
+
activates itself at launch or on reopen still takes focus.
|
|
9429
9893
|
Hosted launches (macos --remote) do not set it.
|
|
9430
|
-
macOS artifacts are not cached. This prototype has no --
|
|
9894
|
+
macOS artifacts are not cached. This prototype has no --slot or reload command.
|
|
9895
|
+
--plan validates the Swift Package directory, macos settings, development plist
|
|
9896
|
+
and declared resources without building, signing, staging, stopping or launching
|
|
9897
|
+
an app, writing workspace state or claiming a build slot. It does not execute
|
|
9898
|
+
Package.swift, so it cannot validate the executable product or package dependencies.
|
|
9899
|
+
--remote-build is respected, including named-machine setup refusals; no worker
|
|
9900
|
+
is contacted and live worker availability is unknown. --remote is launch-only
|
|
9901
|
+
and refuses with --plan. The JSON plan has platform "macos", product and
|
|
9902
|
+
buildMachine; fingerprint, cacheKey, provider, prebuild, outcome and expectedMs
|
|
9903
|
+
are null, cacheHit and cacheSkipped are false, and basis is 0. SwiftPM decides
|
|
9904
|
+
incremental compile work when a build runs; the plan predicts no cache outcome
|
|
9905
|
+
or duration. Desktop checks automatically while build details are visible,
|
|
9906
|
+
reusing a completed build or check for 60 seconds and skipping running builds.
|
|
9431
9907
|
A failed build records its error and compiler output without launching an app.
|
|
9432
9908
|
While it runs, stim status --json reports it as environments[].build with
|
|
9433
9909
|
platform "macos": phase prepare, compile, install, then launch, and during
|
|
@@ -9453,7 +9929,10 @@ refuse before stopping the app or changing its build record. See stim guide erro
|
|
|
9453
9929
|
|
|
9454
9930
|
With remote.build auto, remote.buildMode places these SwiftPM Debug builds:
|
|
9455
9931
|
auto builds here while this Mac has capacity, force uses an approved build
|
|
9456
|
-
machine when one accepts, and off
|
|
9932
|
+
machine when one accepts, and off builds here when local remains in the automatic
|
|
9933
|
+
build pool. remote.buildPoolDisabled excludes members from automatic placement,
|
|
9934
|
+
including its local fallback. Explicit local or named placement bypasses membership.
|
|
9935
|
+
Configure remote.machines
|
|
9457
9936
|
and approve build access as described in stim guide settings. The worker needs
|
|
9458
9937
|
matching Stim, CPU architecture, Xcode and macOS SDK, plus network access to
|
|
9459
9938
|
fetch package dependencies the first time. It keeps SwiftPM dependencies in a
|
|
@@ -9771,290 +10250,178 @@ this workspace's app. Do not change permissions or use custom build scripts."
|
|
|
9771
10250
|
};
|
|
9772
10251
|
//#endregion
|
|
9773
10252
|
//#region src/guide/tutorial-data.ts
|
|
9774
|
-
const
|
|
9775
|
-
|
|
9776
|
-
template: "expo-template-blank@58.0.15"
|
|
9777
|
-
};
|
|
9778
|
-
const TUTORIAL_FILES = {
|
|
9779
|
-
"App.js": `import { useEffect, useState } from 'react';
|
|
9780
|
-
import { Pressable, StyleSheet, Text, View } from 'react-native';
|
|
9781
|
-
import { StatusBar } from 'expo-status-bar';
|
|
9782
|
-
import { TITLE_COLOR } from './theme';
|
|
9783
|
-
|
|
9784
|
-
const TAG = '[stim:tutorial]';
|
|
9785
|
-
|
|
9786
|
-
function Button({ label, onPress }) {
|
|
9787
|
-
return (
|
|
9788
|
-
<Pressable accessibilityRole="button" onPress={onPress} style={styles.button}>
|
|
9789
|
-
<Text style={styles.buttonText}>{label}</Text>
|
|
9790
|
-
</Pressable>
|
|
9791
|
-
);
|
|
9792
|
-
}
|
|
9793
|
-
|
|
9794
|
-
export default function App() {
|
|
9795
|
-
const [note, setNote] = useState('');
|
|
9796
|
-
|
|
9797
|
-
useEffect(() => {
|
|
9798
|
-
console.log(\`\${TAG} title color=\${TITLE_COLOR}\`);
|
|
9799
|
-
}, [TITLE_COLOR]);
|
|
9800
|
-
|
|
9801
|
-
const logError = () => {
|
|
9802
|
-
console.error(\`\${TAG} error-button test error\`);
|
|
9803
|
-
setNote('Logged an error.');
|
|
9804
|
-
};
|
|
9805
|
-
|
|
9806
|
-
const crash = () => {
|
|
9807
|
-
setTimeout(() => {
|
|
9808
|
-
throw new Error(\`\${TAG} crash-button uncaught test error\`);
|
|
9809
|
-
}, 0);
|
|
9810
|
-
};
|
|
9811
|
-
|
|
9812
|
-
const slowRequest = async () => {
|
|
9813
|
-
const started = Date.now();
|
|
9814
|
-
setNote('Waiting 3 seconds...');
|
|
9815
|
-
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
9816
|
-
const elapsed = Date.now() - started;
|
|
9817
|
-
console.warn(\`\${TAG} slow-request \${elapsed}ms\`);
|
|
9818
|
-
setNote(\`Slow request took \${elapsed}ms.\`);
|
|
9819
|
-
};
|
|
9820
|
-
|
|
9821
|
-
return (
|
|
9822
|
-
<View style={styles.container}>
|
|
9823
|
-
<Text style={[styles.title, { color: TITLE_COLOR }]}>Stim Tutorial</Text>
|
|
9824
|
-
<Text style={styles.body}>Tap a button, then look at Stim Desktop > Logs.</Text>
|
|
9825
|
-
<Button label="Log an error" onPress={logError} />
|
|
9826
|
-
<Button label="Crash me" onPress={crash} />
|
|
9827
|
-
<Button label="Slow request" onPress={slowRequest} />
|
|
9828
|
-
<Text style={styles.note}>{note}</Text>
|
|
9829
|
-
<StatusBar style="auto" />
|
|
9830
|
-
</View>
|
|
9831
|
-
);
|
|
9832
|
-
}
|
|
9833
|
-
|
|
9834
|
-
const styles = StyleSheet.create({
|
|
9835
|
-
container: { flex: 1, backgroundColor: '#fff', alignItems: 'center', justifyContent: 'center', padding: 24 },
|
|
9836
|
-
title: { fontSize: 32, fontWeight: '700', marginBottom: 8 },
|
|
9837
|
-
body: { fontSize: 16, color: '#4b5563', textAlign: 'center', marginBottom: 24 },
|
|
9838
|
-
button: { backgroundColor: '#111827', borderRadius: 10, paddingVertical: 14, paddingHorizontal: 28, marginBottom: 12 },
|
|
9839
|
-
buttonText: { color: '#fff', fontSize: 17, fontWeight: '600' },
|
|
9840
|
-
note: { marginTop: 12, fontSize: 15, color: '#374151' },
|
|
9841
|
-
});
|
|
9842
|
-
`,
|
|
9843
|
-
"theme.js": `export const TITLE_COLOR = '#1f2937';
|
|
9844
|
-
`,
|
|
9845
|
-
"app.json": `{
|
|
9846
|
-
"expo": {
|
|
9847
|
-
"name": "Stim Tutorial",
|
|
9848
|
-
"slug": "stim-tutorial",
|
|
9849
|
-
"version": "1.0.0",
|
|
9850
|
-
"orientation": "portrait",
|
|
9851
|
-
"icon": "./assets/icon.png",
|
|
9852
|
-
"userInterfaceStyle": "light",
|
|
9853
|
-
"ios": {
|
|
9854
|
-
"supportsTablet": true,
|
|
9855
|
-
"bundleIdentifier": "dev.stim.tutorial"
|
|
9856
|
-
},
|
|
9857
|
-
"android": {
|
|
9858
|
-
"adaptiveIcon": {
|
|
9859
|
-
"backgroundColor": "#E6F4FE",
|
|
9860
|
-
"foregroundImage": "./assets/android-icon-foreground.png",
|
|
9861
|
-
"backgroundImage": "./assets/android-icon-background.png",
|
|
9862
|
-
"monochromeImage": "./assets/android-icon-monochrome.png"
|
|
9863
|
-
},
|
|
9864
|
-
"package": "dev.stim.tutorial"
|
|
9865
|
-
},
|
|
9866
|
-
"web": {
|
|
9867
|
-
"favicon": "./assets/favicon.png"
|
|
9868
|
-
},
|
|
9869
|
-
"extra": {
|
|
9870
|
-
"stimTutorial": 1
|
|
9871
|
-
}
|
|
9872
|
-
}
|
|
9873
|
-
}
|
|
9874
|
-
`,
|
|
9875
|
-
".gitignore": `/ios
|
|
9876
|
-
/android
|
|
9877
|
-
/tutorial*.ad
|
|
9878
|
-
/tutorial*.png
|
|
9879
|
-
`
|
|
9880
|
-
};
|
|
9881
|
-
const TUTORIAL_PROMPTS = {
|
|
9882
|
-
begin: "Run the Stim tutorial.",
|
|
9883
|
-
rebuild: "Continue the Stim tutorial: rebuild",
|
|
9884
|
-
agent: "Continue the Stim tutorial: agent",
|
|
9885
|
-
refresh: "Continue the Stim tutorial: refresh",
|
|
9886
|
-
machine: "Continue the Stim tutorial: machine",
|
|
9887
|
-
finish: "Continue the Stim tutorial: finish"
|
|
9888
|
-
};
|
|
10253
|
+
const TUTORIAL_REPO = "appandflow/stim-tutorial";
|
|
10254
|
+
const TUTORIAL_BUNDLE_ID = "dev.stim.tutorial";
|
|
9889
10255
|
const TUTORIAL_RESTART_PROMPT = "Restart the Stim tutorial.";
|
|
10256
|
+
/**
|
|
10257
|
+
* The requests Stim Desktop offers to copy, written the way a developer would ask. {base}, {tour} and {worktrees}
|
|
10258
|
+
* are filled in by Desktop. A step with a section names the guide section that holds its safety rules.
|
|
10259
|
+
*/
|
|
10260
|
+
const TUTORIAL_ASKS = {
|
|
10261
|
+
begin: `Clone ${TUTORIAL_REPO} into {base} and follow stim guide tutorial run.`,
|
|
10262
|
+
build: "Make the title purple in the Stim tutorial app and check it on the simulator.",
|
|
10263
|
+
agent: "Open the app on the iOS simulator, take a screenshot and confirm the title color.",
|
|
10264
|
+
finish: "I'm done with these experiments in {base} and don't need the changes. Stop the apps and remove the worktrees {worktrees}, and keep the clone. Follow stim guide tutorial finish.",
|
|
10265
|
+
delete: "Remove the Stim tutorial: remove its worktrees and the clone at {base} with stim worktree remove, then delete {base}. Follow stim guide tutorial delete.",
|
|
10266
|
+
share: `Open a pull request to ${TUTORIAL_REPO} with my title color change, with before and after screenshots from the simulator. See stim guide tutorial share.`,
|
|
10267
|
+
retry: "The first iOS build of the tutorial app in {tour} failed. Find out why and run it on iOS again."
|
|
10268
|
+
};
|
|
9890
10269
|
const TUTORIAL_STEPS = [
|
|
9891
10270
|
{
|
|
9892
10271
|
id: "begin",
|
|
9893
|
-
title: "
|
|
10272
|
+
title: "Get the Test App",
|
|
9894
10273
|
who: "agent",
|
|
9895
10274
|
optional: false,
|
|
9896
|
-
|
|
10275
|
+
ask: TUTORIAL_ASKS.begin,
|
|
9897
10276
|
section: "run",
|
|
9898
|
-
|
|
9899
|
-
"base=\"{base}\"",
|
|
9900
|
-
"mkdir -p \"${base%/*}\"",
|
|
9901
|
-
"if [ ! -e \"$base\" ]; then",
|
|
9902
|
-
"cd \"${base%/*}\"",
|
|
9903
|
-
"if git -C \"${base%/*}\" rev-parse --is-inside-work-tree >/dev/null 2>&1; then echo \"Stop: inside another repository. Ask for another folder; never git add in the user repository.\"; exit 1; fi",
|
|
9904
|
-
`npx --yes create-expo-app@${TUTORIAL_PINS.createExpoApp} stim-tutorial --template ${TUTORIAL_PINS.template} --no-install --no-agents-md --yes`,
|
|
9905
|
-
"cd \"$base\"",
|
|
9906
|
-
"stim guide tutorial app",
|
|
9907
|
-
...Object.entries(TUTORIAL_FILES).flatMap(([name, content]) => [`cat ${name === ".gitignore" ? ">>" : ">"} ${name} <<'STIM_TUTORIAL_EOF'`].concat(content.trimEnd().split("\n"), "STIM_TUTORIAL_EOF")),
|
|
9908
|
-
"npm install --prefer-offline",
|
|
9909
|
-
"npm pkg set scripts.ios=\"expo run:ios\" scripts.android=\"expo run:android\"",
|
|
9910
|
-
"git init",
|
|
9911
|
-
"git add -A",
|
|
9912
|
-
"git -c user.name=Stim -c user.email=stim@localhost -c commit.gpgsign=false commit -m \"Stim tutorial\"",
|
|
9913
|
-
"else",
|
|
9914
|
-
"cd \"$base\"",
|
|
9915
|
-
`node -e 'const fs = require("node:fs"); const app = fs.existsSync("app.json") ? JSON.parse(fs.readFileSync("app.json", "utf8")) : null; if (app?.expo?.extra?.stimTutorial !== ${JSON.parse(TUTORIAL_FILES["app.json"]).expo.extra.stimTutorial}) { console.error("Stop: existing non-tutorial folder or another version. Ask for another folder; never overwrite or delete it."); process.exit(1); }'`,
|
|
9916
|
-
`git rev-parse --show-toplevel | node -e 'const fs = require("node:fs"); const root = fs.readFileSync(0, "utf8").trim(); if (fs.realpathSync(root) !== fs.realpathSync(process.cwd())) { console.error("Stop: inside another repository. Ask for another folder; never git add in the user repository."); process.exit(1); }'`,
|
|
9917
|
-
"fi"
|
|
9918
|
-
]
|
|
10277
|
+
commands: []
|
|
9919
10278
|
},
|
|
9920
10279
|
{
|
|
9921
|
-
id: "
|
|
9922
|
-
title: "
|
|
10280
|
+
id: "build",
|
|
10281
|
+
title: "Make a Change",
|
|
9923
10282
|
who: "you",
|
|
9924
10283
|
optional: false,
|
|
9925
|
-
|
|
10284
|
+
ask: TUTORIAL_ASKS.build,
|
|
9926
10285
|
section: null,
|
|
9927
|
-
|
|
10286
|
+
commands: []
|
|
9928
10287
|
},
|
|
9929
10288
|
{
|
|
9930
|
-
id: "
|
|
9931
|
-
title: "
|
|
10289
|
+
id: "parallel",
|
|
10290
|
+
title: "Change It Again in Parallel",
|
|
9932
10291
|
who: "you",
|
|
9933
10292
|
optional: false,
|
|
9934
|
-
|
|
10293
|
+
ask: null,
|
|
9935
10294
|
section: null,
|
|
9936
|
-
|
|
9937
|
-
"cd \"{base}\"",
|
|
9938
|
-
"git worktree add -B stim-tutorial/tour \"{tour}\" HEAD",
|
|
9939
|
-
"cd \"{tour}\"",
|
|
9940
|
-
"stim worktree warm",
|
|
9941
|
-
"stim guide agent",
|
|
9942
|
-
"stim doctor --platform ios",
|
|
9943
|
-
"stim start",
|
|
9944
|
-
"stim ios"
|
|
9945
|
-
]
|
|
9946
|
-
},
|
|
9947
|
-
{
|
|
9948
|
-
id: "rebuild",
|
|
9949
|
-
title: "Rebuild from Cache",
|
|
9950
|
-
who: "agent",
|
|
9951
|
-
optional: false,
|
|
9952
|
-
prompt: TUTORIAL_PROMPTS.rebuild,
|
|
9953
|
-
section: "rebuild",
|
|
9954
|
-
manual: [
|
|
9955
|
-
"cd \"{tour}\"",
|
|
9956
|
-
"stim ios",
|
|
9957
|
-
"stim status --json"
|
|
9958
|
-
]
|
|
10295
|
+
commands: []
|
|
9959
10296
|
},
|
|
9960
10297
|
{
|
|
9961
10298
|
id: "device",
|
|
9962
10299
|
title: "Live View and Control",
|
|
9963
10300
|
who: "you",
|
|
9964
|
-
optional:
|
|
9965
|
-
|
|
9966
|
-
section: null,
|
|
9967
|
-
manual: ["stim status"]
|
|
9968
|
-
},
|
|
9969
|
-
{
|
|
9970
|
-
id: "logs",
|
|
9971
|
-
title: "App Logs",
|
|
9972
|
-
who: "you",
|
|
9973
|
-
optional: false,
|
|
9974
|
-
prompt: null,
|
|
10301
|
+
optional: true,
|
|
10302
|
+
ask: null,
|
|
9975
10303
|
section: null,
|
|
9976
|
-
|
|
10304
|
+
commands: ["stim status"]
|
|
9977
10305
|
},
|
|
9978
10306
|
{
|
|
9979
10307
|
id: "agent",
|
|
9980
10308
|
title: "Agent Actions and Replay",
|
|
9981
10309
|
who: "agent",
|
|
9982
|
-
optional:
|
|
9983
|
-
|
|
9984
|
-
section:
|
|
9985
|
-
|
|
10310
|
+
optional: true,
|
|
10311
|
+
ask: TUTORIAL_ASKS.agent,
|
|
10312
|
+
section: null,
|
|
10313
|
+
commands: [
|
|
9986
10314
|
"cd \"{tour}\"",
|
|
9987
10315
|
"export AGENT_DEVICE_STATE_DIR=\"{stateDir}\"",
|
|
9988
|
-
|
|
9989
|
-
"read -r iosUdid",
|
|
9990
|
-
"agent-device open dev.stim.tutorial --platform ios --udid \"$iosUdid\" --save-script=tutorial.ad",
|
|
9991
|
-
"agent-device react-native dismiss-overlay || true",
|
|
9992
|
-
`agent-device press 'label="Log an error"' --settle`,
|
|
10316
|
+
`agent-device open ${TUTORIAL_BUNDLE_ID} --platform ios --udid {udid}`,
|
|
9993
10317
|
"agent-device screenshot tutorial.png",
|
|
9994
10318
|
"agent-device close",
|
|
9995
|
-
"grep -v -e 'target-v1' -e 'dismiss-overlay' tutorial.ad > tutorial-replay.ad",
|
|
9996
|
-
"agent-device replay tutorial-replay.ad --platform ios --udid \"$iosUdid\"",
|
|
9997
10319
|
"stim logs --source agent --tail 10"
|
|
9998
10320
|
]
|
|
9999
10321
|
},
|
|
10000
10322
|
{
|
|
10001
|
-
id: "
|
|
10002
|
-
title: "
|
|
10003
|
-
who: "
|
|
10004
|
-
optional:
|
|
10005
|
-
|
|
10006
|
-
section:
|
|
10007
|
-
|
|
10008
|
-
"cd \"{tour}\"",
|
|
10009
|
-
"cat > theme.js <<'STIM_TUTORIAL_EOF'",
|
|
10010
|
-
"export const TITLE_COLOR = '#7c3aed';",
|
|
10011
|
-
"STIM_TUTORIAL_EOF",
|
|
10012
|
-
"sleep 6",
|
|
10013
|
-
"stim logs --errors",
|
|
10014
|
-
"stim logs --grep 'title color'"
|
|
10015
|
-
]
|
|
10323
|
+
id: "logs",
|
|
10324
|
+
title: "App Logs",
|
|
10325
|
+
who: "you",
|
|
10326
|
+
optional: true,
|
|
10327
|
+
ask: null,
|
|
10328
|
+
section: null,
|
|
10329
|
+
commands: ["stim logs --errors", "stim logs --grep stim:tutorial"]
|
|
10016
10330
|
},
|
|
10017
10331
|
{
|
|
10018
10332
|
id: "phone",
|
|
10019
10333
|
title: "Watch on Your Phone",
|
|
10020
10334
|
who: "you",
|
|
10021
10335
|
optional: true,
|
|
10022
|
-
|
|
10336
|
+
ask: null,
|
|
10023
10337
|
section: null,
|
|
10024
|
-
|
|
10338
|
+
commands: []
|
|
10025
10339
|
},
|
|
10026
10340
|
{
|
|
10027
|
-
id: "
|
|
10028
|
-
title: "
|
|
10029
|
-
who: "
|
|
10341
|
+
id: "share",
|
|
10342
|
+
title: "Share Your Finish",
|
|
10343
|
+
who: "you",
|
|
10030
10344
|
optional: true,
|
|
10031
|
-
|
|
10032
|
-
section: "
|
|
10033
|
-
|
|
10345
|
+
ask: TUTORIAL_ASKS.share,
|
|
10346
|
+
section: "share",
|
|
10347
|
+
commands: [
|
|
10348
|
+
"cd \"{tour}\"",
|
|
10349
|
+
"git commit -am \"<one-line summary>\"",
|
|
10350
|
+
"mkdir -p .expo/screenshots",
|
|
10351
|
+
"git checkout origin/main -- theme.js",
|
|
10352
|
+
"xcrun simctl io {udid} screenshot .expo/screenshots/before.png",
|
|
10353
|
+
"git checkout HEAD -- theme.js",
|
|
10354
|
+
"xcrun simctl io {udid} screenshot .expo/screenshots/after.png",
|
|
10355
|
+
"cp .github/pull_request_template.md .expo/screenshots/body.md",
|
|
10356
|
+
`gh repo fork ${TUTORIAL_REPO} --remote --remote-name fork`,
|
|
10357
|
+
"git push -u fork HEAD",
|
|
10358
|
+
`gh pr create --repo ${TUTORIAL_REPO} --title "<one-line summary>" --body-file .expo/screenshots/body.md --attach ".expo/screenshots/before.png#Before" --attach ".expo/screenshots/after.png#After"`
|
|
10359
|
+
]
|
|
10034
10360
|
},
|
|
10035
10361
|
{
|
|
10036
10362
|
id: "finish",
|
|
10037
10363
|
title: "Finish and Archive",
|
|
10038
10364
|
who: "agent",
|
|
10039
10365
|
optional: false,
|
|
10040
|
-
|
|
10366
|
+
ask: TUTORIAL_ASKS.finish,
|
|
10041
10367
|
section: "finish",
|
|
10042
|
-
|
|
10043
|
-
"git -C \"{tour}\" checkout -- theme.js",
|
|
10368
|
+
commands: [
|
|
10044
10369
|
"cd \"{tour}\"",
|
|
10045
10370
|
"stim stop",
|
|
10371
|
+
"cd \"{second}\"",
|
|
10372
|
+
"stim stop",
|
|
10046
10373
|
"cd \"{base}\"",
|
|
10047
|
-
"stim worktree remove \"{tour}\""
|
|
10374
|
+
"stim worktree remove \"{tour}\"",
|
|
10375
|
+
"stim worktree remove \"{second}\""
|
|
10376
|
+
]
|
|
10377
|
+
},
|
|
10378
|
+
{
|
|
10379
|
+
id: "delete",
|
|
10380
|
+
title: "Delete the Test App",
|
|
10381
|
+
who: "agent",
|
|
10382
|
+
optional: true,
|
|
10383
|
+
ask: TUTORIAL_ASKS.delete,
|
|
10384
|
+
section: "delete",
|
|
10385
|
+
commands: [
|
|
10386
|
+
"cd \"{base}\"",
|
|
10387
|
+
"grep stimTutorial app.json",
|
|
10388
|
+
"git worktree list",
|
|
10389
|
+
"stim stop",
|
|
10390
|
+
"stim worktree remove \"{base}\"",
|
|
10391
|
+
"cd ..",
|
|
10392
|
+
"rm -rf \"{base}\""
|
|
10048
10393
|
]
|
|
10049
10394
|
}
|
|
10050
10395
|
];
|
|
10051
10396
|
//#endregion
|
|
10052
10397
|
//#region src/guide/tutorial.ts
|
|
10053
|
-
const paths = `Use {base} = ~/stim-tutorial
|
|
10054
|
-
|
|
10055
|
-
|
|
10398
|
+
const paths = `Use {base} = ~/stim-tutorial unless the user named another folder. Expand ~
|
|
10399
|
+
to the absolute home path when substituting inside quotes. Keep the tutorial
|
|
10400
|
+
outside the user's own projects.`;
|
|
10401
|
+
const local = `The tutorial runs on this Mac. Every time you run the tutorial app on iOS
|
|
10402
|
+
from a worktree of {base}, use stim ios --remote local --remote-build local,
|
|
10403
|
+
even when the user's settings would place the device or the build on another
|
|
10404
|
+
Mac. Only an explicit request to build on another Mac changes the build, with
|
|
10405
|
+
stim ios --remote local --remote-build "<machine>"; the device stays here.`;
|
|
10406
|
+
const screenshots = `Before and after screenshots, for a pull request: in each change's worktree,
|
|
10407
|
+
run the app on iOS before you edit anything, open it with agent-device and save
|
|
10408
|
+
the screen, then make the change and, once Fast Refresh applies it, save the
|
|
10409
|
+
same screen on the same device:
|
|
10410
|
+
|
|
10411
|
+
mkdir -p .expo/screenshots
|
|
10412
|
+
export AGENT_DEVICE_STATE_DIR="<agentDevice.stateDir from stim status --json>"
|
|
10413
|
+
agent-device open ${TUTORIAL_BUNDLE_ID} --platform ios --udid <ios.udid>
|
|
10414
|
+
agent-device screenshot .expo/screenshots/before.png
|
|
10415
|
+
(make the change)
|
|
10416
|
+
agent-device screenshot .expo/screenshots/after.png
|
|
10417
|
+
|
|
10418
|
+
Without agent-device, use xcrun simctl io <ios.udid> screenshot
|
|
10419
|
+
.expo/screenshots/before.png, using that worktree's udid from stim status --json,
|
|
10420
|
+
never booted. Take both with the same tool so they match in size. .expo/ is
|
|
10421
|
+
ignored and outside the native fingerprint, so the files are never committed,
|
|
10422
|
+
never change the build, and never block stim worktree remove. Keep each PNG under 1 MB.`;
|
|
10056
10423
|
function commands(id) {
|
|
10057
|
-
return TUTORIAL_STEPS.find((step) => step.id === id).
|
|
10424
|
+
return TUTORIAL_STEPS.find((step) => step.id === id).commands.join("\n");
|
|
10058
10425
|
}
|
|
10059
10426
|
//#endregion
|
|
10060
10427
|
//#region src/guide/index.ts
|
|
@@ -10072,260 +10439,217 @@ const TOPICS = {
|
|
|
10072
10439
|
web: web_default,
|
|
10073
10440
|
macos: macos_default,
|
|
10074
10441
|
tutorial: {
|
|
10075
|
-
summary: "
|
|
10442
|
+
summary: "A cloned test app: a first build, a second change in parallel with a cache hit, and cleanup",
|
|
10076
10443
|
sectionHint: "run",
|
|
10077
10444
|
preamble: () => `STIM TUTORIAL
|
|
10078
10445
|
|
|
10079
|
-
|
|
10080
|
-
|
|
10081
|
-
|
|
10446
|
+
The tutorial clones ${TUTORIAL_REPO}, a tiny Expo app, into {base}; the clone is
|
|
10447
|
+
never run, and only the optional delete step removes it. The user then asks for a visual change, and for another
|
|
10448
|
+
change while the first builds. Each change runs in its own linked worktree of
|
|
10449
|
+
{base}, so each has its own simulator and Metro port, and the second worktree's
|
|
10450
|
+
first iOS build reuses the first one's native build. Only the clone, the
|
|
10451
|
+
optional share and the cleanup need this guide: the changes are ordinary
|
|
10452
|
+
requests, so follow stim guide agent for them, and check each change on the
|
|
10453
|
+
device.
|
|
10082
10454
|
|
|
10083
|
-
|
|
10084
|
-
Stim Desktop, and give the next prompt. Pause never means stim stop.
|
|
10085
|
-
"${TUTORIAL_PROMPTS.begin}" means stim guide tutorial run.
|
|
10086
|
-
"Continue the Stim tutorial: <section>" means stim guide tutorial <section>.
|
|
10087
|
-
"${TUTORIAL_RESTART_PROMPT}" means stim guide tutorial restart.
|
|
10455
|
+
${local}
|
|
10088
10456
|
|
|
10089
|
-
|
|
10090
|
-
|
|
10091
|
-
Follow stim guide
|
|
10092
|
-
|
|
10457
|
+
"Follow stim guide tutorial run" means stim guide tutorial run.
|
|
10458
|
+
"Follow stim guide tutorial finish" means stim guide tutorial finish.
|
|
10459
|
+
"Follow stim guide tutorial delete" means stim guide tutorial delete.
|
|
10460
|
+
"${TUTORIAL_RESTART_PROMPT}" means stim guide tutorial restart.
|
|
10093
10461
|
|
|
10094
10462
|
${paths}
|
|
10095
10463
|
|
|
10096
|
-
|
|
10097
|
-
|
|
10098
|
-
required npm and native dependencies are already cached.`,
|
|
10464
|
+
Never pair phones, approve machines, or grant access on the user's behalf.
|
|
10465
|
+
For commands to type yourself, read stim guide tutorial manual.`,
|
|
10099
10466
|
sections: {
|
|
10100
10467
|
run: {
|
|
10101
|
-
summary: "
|
|
10468
|
+
summary: "Clone the test app into a fresh folder and install its dependencies",
|
|
10102
10469
|
body: () => `RUN THE TUTORIAL
|
|
10103
10470
|
|
|
10104
10471
|
${paths}
|
|
10105
10472
|
|
|
10106
|
-
Folder safety:
|
|
10107
|
-
|
|
10108
|
-
${
|
|
10109
|
-
|
|
10110
|
-
|
|
10111
|
-
|
|
10112
|
-
|
|
10113
|
-
|
|
10114
|
-
|
|
10115
|
-
|
|
10116
|
-
|
|
10117
|
-
|
|
10118
|
-
|
|
10119
|
-
|
|
10120
|
-
|
|
10121
|
-
|
|
10122
|
-
|
|
10123
|
-
|
|
10124
|
-
|
|
10125
|
-
|
|
10126
|
-
|
|
10127
|
-
|
|
10128
|
-
|
|
10129
|
-
|
|
10130
|
-
|
|
10131
|
-
|
|
10132
|
-
|
|
10133
|
-
|
|
10134
|
-
|
|
10135
|
-
|
|
10136
|
-
|
|
10137
|
-
|
|
10138
|
-
|
|
10139
|
-
|
|
10140
|
-
|
|
10141
|
-
stim guide agent
|
|
10142
|
-
|
|
10143
|
-
Apply the guide agent doctor rule before native work: if its STATUS block
|
|
10144
|
-
says doctor is due, run stim doctor --platform ios from the tour worktree and
|
|
10145
|
-
resolve its findings. No STATUS block means doctor is current. Then run:
|
|
10146
|
-
|
|
10147
|
-
stim start
|
|
10148
|
-
stim ios
|
|
10149
|
-
|
|
10150
|
-
Tell the user the first build can take about four minutes on a cold cache.
|
|
10151
|
-
Relay the Open in Stim Desktop link printed by stim ios once.
|
|
10152
|
-
|
|
10153
|
-
PAUSE: end the turn. Ask the user to look at the Build section, then the
|
|
10154
|
-
device, then Logs in Stim Desktop. Without Desktop, use stim status,
|
|
10155
|
-
stim stats, and stim logs --errors. Give the next prompt:
|
|
10156
|
-
"${TUTORIAL_PROMPTS.rebuild}". Leave the workspace running.`
|
|
10473
|
+
Folder safety: if {base} does not exist, clone into it. If it exists, reuse it
|
|
10474
|
+
only when all of these hold: app.json has expo.extra.stimTutorial equal to
|
|
10475
|
+
${TUTORIAL_VERSION}, git remote get-url origin names ${TUTORIAL_REPO}, git
|
|
10476
|
+
rev-parse --show-toplevel equals {base}, and git status --porcelain prints
|
|
10477
|
+
nothing. Then skip the clone, install its dependencies (npm ci), run stim doctor
|
|
10478
|
+
--platform ios there, and continue at PAUSE. For any other existing folder (another
|
|
10479
|
+
repository, local changes, no tutorial marker), stop and ask the user for
|
|
10480
|
+
another folder; never overwrite or delete it. Before cloning, check the parent folder:
|
|
10481
|
+
create it if absent, then run git -C <parent> rev-parse --is-inside-work-tree.
|
|
10482
|
+
If that succeeds, the folder is inside another repository: stop and ask the
|
|
10483
|
+
user for another folder. Never git add in the user's repo.
|
|
10484
|
+
|
|
10485
|
+
Then, from the parent folder, run:
|
|
10486
|
+
|
|
10487
|
+
git clone https://github.com/${TUTORIAL_REPO}.git stim-tutorial
|
|
10488
|
+
|
|
10489
|
+
Check that app.json in the clone has expo.extra.stimTutorial equal to
|
|
10490
|
+
${TUTORIAL_VERSION}. If it does not, report the mismatch and stop; the user needs a newer Stim.
|
|
10491
|
+
Enter the clone and install its dependencies (npm ci) so the worktrees made for
|
|
10492
|
+
the changes inherit them, then run stim doctor --platform ios there: it registers
|
|
10493
|
+
the clone with Stim so Stim Desktop sees it, and builds or boots nothing. Do not
|
|
10494
|
+
run the app: the clone is only the base for the user's changes; only the optional
|
|
10495
|
+
delete step removes it.
|
|
10496
|
+
Report the findings of stim doctor and do not act on them: no SimSlim install, no
|
|
10497
|
+
--fix, nothing that changes the machine during the tutorial. On npm or network failure, report stderr
|
|
10498
|
+
and stop.
|
|
10499
|
+
|
|
10500
|
+
${local}
|
|
10501
|
+
|
|
10502
|
+
${screenshots}
|
|
10503
|
+
|
|
10504
|
+
PAUSE: end the turn. Tell the user to ask for a visual change next, such as
|
|
10505
|
+
making the title purple, in their own words. Each change runs in a new linked
|
|
10506
|
+
worktree of {base} (stim guide agent), and its first iOS build takes a few
|
|
10507
|
+
minutes.`
|
|
10157
10508
|
},
|
|
10158
|
-
|
|
10159
|
-
summary: "
|
|
10160
|
-
body: () => `
|
|
10161
|
-
|
|
10162
|
-
create-expo-app: ${TUTORIAL_PINS.createExpoApp}
|
|
10163
|
-
Template: ${TUTORIAL_PINS.template}
|
|
10164
|
-
Write the app files verbatim. Append the .gitignore lines to the template's
|
|
10165
|
-
existing file. App log lines start with [stim:tutorial]. Crash me raises an
|
|
10166
|
-
uncaught JavaScript error, and Slow request times a local three-second timer;
|
|
10167
|
-
Stim does not capture native network requests.
|
|
10168
|
-
|
|
10169
|
-
${Object.entries(TUTORIAL_FILES).map(([name, content]) => `${name}\n\n\`\`\`${name.endsWith(".json") ? "json" : name.endsWith(".js") ? "js" : "text"}\n${content}\`\`\``).join("\n\n")}`
|
|
10170
|
-
},
|
|
10171
|
-
rebuild: {
|
|
10172
|
-
summary: "Repeat the iOS build and explain the cache result",
|
|
10173
|
-
body: () => `REBUILD
|
|
10174
|
-
|
|
10175
|
-
${paths}
|
|
10176
|
-
|
|
10177
|
-
Run the same build again, never with --no-build-cache:
|
|
10178
|
-
|
|
10179
|
-
${commands("rebuild")}
|
|
10180
|
-
|
|
10181
|
-
Read this workspace's environments[].lastBuilds.ios.cacheHit from
|
|
10182
|
-
stim status --json, and the miss reason printed by stim ios. Explain a local or remote hit, or the actual miss
|
|
10183
|
-
reason when cacheHit is false. A repeat run can miss; report the evidence.
|
|
10184
|
-
|
|
10185
|
-
PAUSE: end the turn. Point at the Build section and cache badge, or stim stats.
|
|
10186
|
-
Ask the user to open the device's live view and tap Log an error; without
|
|
10187
|
-
Desktop use the simulator. Then inspect Logs or stim logs --errors. Crash me
|
|
10188
|
-
and Slow request are optional: the former shows a red box, the latter prints
|
|
10189
|
-
a timing line. Give the next prompt: "${TUTORIAL_PROMPTS.agent}".`
|
|
10190
|
-
},
|
|
10191
|
-
agent: {
|
|
10192
|
-
summary: "Record a tap and screenshot, replay it, and inspect agent logs",
|
|
10193
|
-
body: () => `AGENT ACTIONS
|
|
10194
|
-
|
|
10195
|
-
${paths}
|
|
10196
|
-
|
|
10197
|
-
Set {stateDir} to this workspace's agentDevice.stateDir from stim ios or
|
|
10198
|
-
stim status --json. Replace <ios.udid> with this workspace's ios.udid from
|
|
10199
|
-
stim status --json. Use that exact owned simulator, not a guessed one.
|
|
10200
|
-
Run from the tour worktree:
|
|
10201
|
-
|
|
10202
|
-
${commands("agent").replace("read -r iosUdid", "iosUdid=\"<ios.udid>\"")}
|
|
10203
|
-
|
|
10204
|
-
Use --save-script=tutorial.ad with the equals sign: agent-device treats a
|
|
10205
|
-
separate path as a URL and refuses. The dismiss-overlay step clears a red box that would cover the buttons.
|
|
10206
|
-
Replay with the same --platform and --udid so its steps reach the agent log.
|
|
10207
|
-
Remove the target-v1 evidence and dismiss-overlay lines before replay: replaying
|
|
10208
|
-
them can fail with REPLAY_DIVERGENCE on the recorded button identity.
|
|
10209
|
-
The scripts and screenshot stay in the tour worktree and are git-ignored.
|
|
10210
|
-
|
|
10211
|
-
PAUSE: end the turn. Point at Agent Actions, or the agent log records just
|
|
10212
|
-
printed. Expect another error-button line after replay. When screen recording
|
|
10213
|
-
is enabled, the user can scrub Replay in Desktop. Give the next prompt:
|
|
10214
|
-
"${TUTORIAL_PROMPTS.refresh}".`
|
|
10215
|
-
},
|
|
10216
|
-
refresh: {
|
|
10217
|
-
summary: "Change the title to purple and verify Fast Refresh through logs",
|
|
10218
|
-
body: () => `FAST REFRESH
|
|
10509
|
+
finish: {
|
|
10510
|
+
summary: "Stop and remove the two tutorial worktrees, keeping the clone",
|
|
10511
|
+
body: () => `FINISH
|
|
10219
10512
|
|
|
10220
10513
|
${paths}
|
|
10221
10514
|
|
|
10222
|
-
|
|
10223
|
-
|
|
10224
|
-
|
|
10225
|
-
|
|
10515
|
+
The worktrees to remove are the two the tutorial tracked: the linked
|
|
10516
|
+
worktrees of {base} made for the user's changes. The finish request names them
|
|
10517
|
+
as {tour} and {second}. Never touch any other worktree, an earlier tutorial
|
|
10518
|
+
clone, or the clone itself. For each, stop from its path, then remove it from
|
|
10519
|
+
the clone:
|
|
10226
10520
|
|
|
10227
|
-
|
|
10228
|
-
the app. The intentional button errors may still be in the error log; check
|
|
10229
|
-
whether the edit introduced a new error.
|
|
10521
|
+
${commands("finish")}
|
|
10230
10522
|
|
|
10231
|
-
|
|
10232
|
-
|
|
10233
|
-
|
|
10234
|
-
|
|
10235
|
-
|
|
10236
|
-
|
|
10523
|
+
Use a plain remove first. The user's finish request says they do not need the
|
|
10524
|
+
changes, which is the consent stim guide agent asks for before worktree remove
|
|
10525
|
+
--force, for exactly those two paths: if the plain remove refuses one of them
|
|
10526
|
+
only because of uncommitted changes or commits found nowhere else, remove that
|
|
10527
|
+
worktree with --force. Never use --force on the clone or on any other
|
|
10528
|
+
worktree, and on any other refusal report it and stop. Keep the clone: the
|
|
10529
|
+
optional delete step removes it only when the user asks (stim guide tutorial
|
|
10530
|
+
delete).
|
|
10531
|
+
|
|
10532
|
+
If archive is enabled, tell the user the worktrees appear under Archived in
|
|
10533
|
+
Stim Desktop. With archive disabled, report removal without promising an
|
|
10534
|
+
archive. Without Desktop, inspect stim status --json for the removed
|
|
10535
|
+
environments. End the turn.`
|
|
10237
10536
|
},
|
|
10238
|
-
|
|
10239
|
-
summary: "
|
|
10240
|
-
body: () => `
|
|
10537
|
+
delete: {
|
|
10538
|
+
summary: "Remove the tutorial worktrees and the clone through Stim, then delete the folder",
|
|
10539
|
+
body: () => `DELETE THE TEST APP (OPTIONAL)
|
|
10241
10540
|
|
|
10242
10541
|
${paths}
|
|
10243
10542
|
|
|
10244
|
-
|
|
10245
|
-
|
|
10246
|
-
|
|
10247
|
-
|
|
10248
|
-
${commands("machine")}
|
|
10249
|
-
|
|
10250
|
-
This step bypasses the artifact cache so the build can use the named machine.
|
|
10251
|
-
A named machine refuses without a local fallback. If it refuses, report the
|
|
10252
|
-
refusal and offer --remote-build auto or local; do not retry silently.
|
|
10253
|
-
|
|
10254
|
-
PAUSE: end the turn. Point at the build's machine in Desktop or its report in
|
|
10255
|
-
stim status --json. Give the next prompt: "${TUTORIAL_PROMPTS.finish}".`
|
|
10256
|
-
},
|
|
10257
|
-
finish: {
|
|
10258
|
-
summary: "Revert the tutorial edit, stop, and remove only the tour worktree",
|
|
10259
|
-
body: () => `FINISH
|
|
10260
|
-
|
|
10261
|
-
${paths}
|
|
10543
|
+
Only on the user's explicit request, which the delete prompt is. It covers
|
|
10544
|
+
{base} and its linked worktrees, nothing else. Remove them through Stim so their
|
|
10545
|
+
simulators, Metro ports and Stim records are torn down before the files go.
|
|
10262
10546
|
|
|
10263
|
-
|
|
10264
|
-
|
|
10265
|
-
Stop from the tour path, then remove from the base checkout:
|
|
10547
|
+
First check that {base}/app.json has expo.extra.stimTutorial. If it does not,
|
|
10548
|
+
{base} is not the tutorial clone: report it and stop.
|
|
10266
10549
|
|
|
10267
|
-
|
|
10550
|
+
List the worktrees with git -C "{base}" worktree list. For each linked worktree
|
|
10551
|
+
(every entry except {base} itself), run stim stop from its path, then
|
|
10552
|
+
stim worktree remove "<path>" from {base}. Never use --force here: the delete
|
|
10553
|
+
request does not say which changes the user can lose. If a remove refuses, report
|
|
10554
|
+
it and stop without deleting anything, so the user can decide about that
|
|
10555
|
+
worktree.
|
|
10268
10556
|
|
|
10269
|
-
|
|
10270
|
-
|
|
10271
|
-
|
|
10557
|
+
Then, from {base}, run stim stop and stim worktree remove "{base}". On the
|
|
10558
|
+
source checkout it reclaims the Stim environment and leaves the files. If it
|
|
10559
|
+
refuses, report it and stop. Only after it succeeds, from the parent folder,
|
|
10560
|
+
delete the clone:
|
|
10272
10561
|
|
|
10273
10562
|
rm -rf "{base}"
|
|
10274
|
-
git -C "{base}" branch -D stim-tutorial/tour
|
|
10275
10563
|
|
|
10276
|
-
|
|
10277
|
-
|
|
10278
|
-
|
|
10279
|
-
|
|
10564
|
+
Never use --force in this step, and never delete any path other than {base}. Report
|
|
10565
|
+
what you removed and end the turn.`
|
|
10566
|
+
},
|
|
10567
|
+
share: {
|
|
10568
|
+
summary: "Optionally open a public pull request with before and after screenshots of the change",
|
|
10569
|
+
body: () => `SHARE YOUR FINISH (OPTIONAL)
|
|
10570
|
+
|
|
10571
|
+
Only on the user's explicit request, which the share prompt is, and before the
|
|
10572
|
+
finish step removes the worktrees. The pull request is public: the user's GitHub
|
|
10573
|
+
name and change appear on ${TUTORIAL_REPO}, and a bot replies and closes it. It
|
|
10574
|
+
needs gh signed in. Never open it unprompted or from any other step.
|
|
10575
|
+
|
|
10576
|
+
Work from the worktree holding the user's change, {tour}. Commit only the
|
|
10577
|
+
change's files there, never .expo/screenshots/. Fork the repository and push the
|
|
10578
|
+
branch to the fork, since the user has no write access:
|
|
10579
|
+
|
|
10580
|
+
gh repo fork ${TUTORIAL_REPO} --remote --remote-name fork
|
|
10581
|
+
git push -u fork HEAD
|
|
10582
|
+
|
|
10583
|
+
Screenshots: use .expo/screenshots/before.png and .expo/screenshots/after.png from that
|
|
10584
|
+
worktree (stim guide tutorial run). If either is missing, take it now on the same
|
|
10585
|
+
device, that worktree's ios.udid from stim status --json, never booted, with the
|
|
10586
|
+
app running from the branch (run it again first if needed). For
|
|
10587
|
+
a missing before, show the original screen with
|
|
10588
|
+
git checkout origin/main -- <changed files>, capture it once Fast Refresh applies,
|
|
10589
|
+
then restore the change with git checkout HEAD -- <changed files> and capture the
|
|
10590
|
+
after again with the same tool, so both match in size.
|
|
10591
|
+
|
|
10592
|
+
Body: write .expo/screenshots/body.md from the clone's
|
|
10593
|
+
.github/pull_request_template.md, keeping its headings, table and Stim link and
|
|
10594
|
+
dropping its <!-- --> comments. An older clone without the template gets the
|
|
10595
|
+
same parts, in this order:
|
|
10596
|
+
- the first line: one sentence saying what changed and why;
|
|
10597
|
+
- the table, with  and
|
|
10598
|
+
 in its cells;
|
|
10599
|
+
- a How it was verified section, with only what you observed: Device is ios.name from
|
|
10600
|
+
stim status --json; Readiness is the "app reported ready" time stim ios
|
|
10601
|
+
printed; Build is lastBuilds.ios.durationMs and whether lastBuilds.ios.cacheHit
|
|
10602
|
+
was local or remote (a cache hit) or false (a full build), plus, when you know
|
|
10603
|
+
it, whether the second worktree's first iOS build was a cache hit; Logs is the
|
|
10604
|
+
result of stim logs --errors. Drop a line you did not observe rather than
|
|
10605
|
+
guess it;
|
|
10606
|
+
- the closing line: Built and verified with [Stim](https://github.com/appandflow/stim).
|
|
10607
|
+
|
|
10608
|
+
Open the pull request from {tour}:
|
|
10609
|
+
|
|
10610
|
+
gh pr create --repo ${TUTORIAL_REPO} --title "<the one-line summary>" \\
|
|
10611
|
+
--body-file .expo/screenshots/body.md \\
|
|
10612
|
+
--attach ".expo/screenshots/before.png#Before" --attach ".expo/screenshots/after.png#After"
|
|
10613
|
+
|
|
10614
|
+
--attach uploads each image and rewrites the matching ./.expo/screenshots/ reference in
|
|
10615
|
+
the body to the uploaded file, so the table shows both images. gh 2.99.0
|
|
10616
|
+
(2026-09-01) has --attach; confirm with gh pr create --help rather than guessing
|
|
10617
|
+
a version. When gh has no --attach, open the pull request with --body-file alone
|
|
10618
|
+
and tell the user to drag the two images into the table on GitHub. Give the user
|
|
10619
|
+
the pull request URL.`
|
|
10280
10620
|
},
|
|
10281
10621
|
restart: {
|
|
10282
|
-
summary: "
|
|
10622
|
+
summary: "Start the tutorial again without removing anything",
|
|
10283
10623
|
body: () => `RESTART
|
|
10284
10624
|
|
|
10285
10625
|
${paths}
|
|
10286
10626
|
|
|
10287
|
-
For "${TUTORIAL_RESTART_PROMPT}",
|
|
10288
|
-
|
|
10289
|
-
|
|
10290
|
-
|
|
10291
|
-
|
|
10292
|
-
|
|
10293
|
-
|
|
10294
|
-
and redo run from the worktree step. Pause after the build as run instructs.`
|
|
10627
|
+
For "${TUTORIAL_RESTART_PROMPT}", remove nothing: the user may still want the
|
|
10628
|
+
earlier worktrees. Finish only removes the pair named in its request, so leave
|
|
10629
|
+
any earlier worktrees and tell the user they stay until they ask for each by
|
|
10630
|
+
path; never use --force for them. Reuse the clone at {base} only if its
|
|
10631
|
+
stimTutorial marker equals ${TUTORIAL_VERSION}; otherwise follow stim guide
|
|
10632
|
+
tutorial run into a fresh folder. Pause as run instructs. Stim Desktop starts
|
|
10633
|
+
over: only worktrees and builds after the restart count.`
|
|
10295
10634
|
},
|
|
10296
10635
|
manual: {
|
|
10297
|
-
summary: "
|
|
10636
|
+
summary: "The commands behind each step, for typing yourself",
|
|
10298
10637
|
body: () => `MANUAL TUTORIAL
|
|
10299
10638
|
|
|
10300
10639
|
${paths}
|
|
10301
10640
|
|
|
10302
|
-
|
|
10303
|
-
|
|
10304
|
-
|
|
10305
|
-
|
|
10306
|
-
|
|
10307
|
-
|
|
10308
|
-
|
|
10309
|
-
|
|
10310
|
-
|
|
10311
|
-
|
|
10312
|
-
|
|
10313
|
-
|
|
10314
|
-
Look at the sidebar during warm and Build during the first build (about four
|
|
10315
|
-
minutes on a cold cache). Compare cacheHit and missReason on rebuild. At Live
|
|
10316
|
-
view and control, open the device viewer and tap Log an error; without Desktop
|
|
10317
|
-
use the simulator. At App Logs, try Crash me or Slow request if wanted. A JS
|
|
10318
|
-
crash shows a red box; the slow request is a local timer, not network capture.
|
|
10319
|
-
At Watch on Your Phone, optionally open an already paired Stim phone to see
|
|
10320
|
-
the tour workspace; phone setup and machine approval stay with you.
|
|
10321
|
-
Use stim status, stim logs --errors, and stim stats without Desktop.
|
|
10322
|
-
|
|
10323
|
-
${TUTORIAL_STEPS.map((step) => `${step.title}${step.optional ? " (optional)" : ""}\n\n${step.manual.length ? `\`\`\`sh\n${step.manual.join("\n")}\n\`\`\`` : "Observe this step in Stim Desktop, or skip it without Desktop."}`).join("\n\n")}
|
|
10324
|
-
|
|
10325
|
-
Finish removes only the tour worktree. Never use --force; report a refusal.
|
|
10326
|
-
With archive enabled, find the tour under Archived in Desktop or archived[]
|
|
10327
|
-
in stim status --json. Keep the base repository and branch. To delete them,
|
|
10328
|
-
read stim guide tutorial finish for commands to review and run yourself.`
|
|
10641
|
+
Replace {base}, {tour} and {second} with absolute paths: {base} is the clone,
|
|
10642
|
+
{tour} the first worktree and {second} the second. For Agent Actions, replace
|
|
10643
|
+
{stateDir} with agentDevice.stateDir from stim ios or stim status --json and
|
|
10644
|
+
{udid} with the workspace's ios.udid. Clone with git
|
|
10645
|
+
clone https://github.com/${TUTORIAL_REPO}.git into a fresh folder outside any
|
|
10646
|
+
repository. Each change runs in its own worktree of that clone (stim guide
|
|
10647
|
+
agent); the clone itself is never run. Run each worktree on iOS with
|
|
10648
|
+
stim ios --remote local --remote-build local so it stays on this Mac.
|
|
10649
|
+
|
|
10650
|
+
${TUTORIAL_STEPS.map((step) => `${step.title}${step.optional ? " (optional)" : ""}\n\n${step.commands.length ? `\`\`\`sh\n${step.commands.join("\n")}\n\`\`\`` : "Ask your agent in your own words, or observe this step in Stim Desktop."}`).join("\n\n")}
|
|
10651
|
+
|
|
10652
|
+
Finish removes only the two tutorial worktrees, never the clone; stim guide tutorial finish says when --force is allowed for them.`
|
|
10329
10653
|
}
|
|
10330
10654
|
}
|
|
10331
10655
|
}
|
|
@@ -10409,7 +10733,7 @@ function renderIndex(version) {
|
|
|
10409
10733
|
return lines.join("\n");
|
|
10410
10734
|
}
|
|
10411
10735
|
function guideCommand(program, version, status = (running) => guideStatus({
|
|
10412
|
-
projectRoot: findProjectRoot
|
|
10736
|
+
projectRoot: findProjectRoot(process.cwd()),
|
|
10413
10737
|
running
|
|
10414
10738
|
})) {
|
|
10415
10739
|
program.command("guide [topic] [section]").description("Print reference documentation for THIS version of Stim (topics: " + topicNames().join(", ") + "). A topic with sections prints its section index; name a section to print only it, e.g. `stim guide errors STIM_NO_METRO` or `stim guide lifecycle builds`. Generated by the binary, so it cannot drift from the installed CLI.").action(async (topic, section) => {
|