Repository navigation
[agent-cli] E2E-cover the device section, the cloud-session next, and the tunnel lines of status - #77
Conversation
0b602cc to
df13e47
Compare
df13e47 to
f2b2dfc
Compare
f2b2dfc to
d522401
Compare
d522401 to
407d49c
Compare
d102fa4 to
a55ad61
Compare
a55ad61 to
05997b9
Compare
05997b9 to
bff4f33
Compare
bff4f33 to
8d1d3b3
Compare
8d1d3b3 to
d038eb5
Compare
d038eb5 to
69e6de3
Compare
| const report = await reportInAsync(projectRoot, [], env); | ||
|
|
||
| expect(report.device).toMatchObject({ state: 'unknown', deviceId: null, devices: [] }); | ||
| expect(report.device!.reason).toContain('could not be run'); |
There was a problem hiding this comment.
Android alone produces the could not be run text, so this assertion does not check iOS. The combined state is unknown when either platform's check is unknown. On macOS, if the iOS setup in stubDeviceToolsAsync (the xcrun chmod and the PATH override) stopped working, this case would still pass. On darwin, also assert the iOS part of the reason, so a broken iOS check fails this case.
There was a problem hiding this comment.
Done in 13732a7. The test now asserts the Android part by name (Android: "adb" could not be run) on every host. On darwin it also asserts iOS: Could not run "xcrun simctl". I checked it: with the PATH override removed, the state stays unknown, but the reason reads "the bound simulator is gone", and the new assertion fails.
… the tunnel lines of status The last `status` cases without an e2e were the ones that depend on what the runner has: `xcrun simctl` and `adb`. Both tools are under the test's control now — a stub `xcrun` first on PATH, a stub `adb` under an `ANDROID_HOME` of the test's own, which the resolver reads before PATH — and "cannot be run" is a PATH of the stub directory alone with the execute bit withheld, since a PATH search skips a file it cannot run and finds the machine's own tool next. Covered: an attached Android device, a booted iOS simulator by name with every device listed (F106, macOS only), `absent` with the tools' own reasons, `unknown` never rounded down to none (POSIX only), the address handed over in place of `navigate /` when no device is here, the EAS Simulator session's `smoke --ios --eas` / `navigate / --eas` rungs (K7a) including a probe that could not answer, the local path kept when a device is here, and a tunnelled dev server's `tunnel` fact and `open in` launcher URLs (K7c, K8) — plus a stale tunnel dropped once its dev server is gone. Out on purpose: the 8082–8085 port-scan rung, which needs fixed ports that collide on shared runners. Co-authored-by: kudo <46429+kudo@users.noreply.github.com>
Co-authored-by: kudo <46429+kudo@users.noreply.github.com>
69e6de3 to
58dc96e
Compare
…he runner spec (#159) Stacked on #77 (the #69 status stack). ## Why Every EAS-backed command spawned `npx --yes eas-cli@latest` (or `bunx eas-cli@latest`) unless the project pinned `eas-cli`. The `@latest` lookup is slow. ## What `src/utils/easCli.ts` now resolves the EAS CLI in three rungs: ``` project declares eas-cli -> <runner> eas-cli (pin wins, unchanged) first `eas` on PATH is eas-cli >= 25.0.0 -> eas (spawned directly) otherwise -> <runner> eas-cli (no @latest) ``` - **Global rung (`findGlobalEasCli`)**: follows the first `eas` on `PATH` through its symlink to the nearest `package.json`. The rung is used only when the package name is `eas-cli` and the version is `>= 25.0.0`. Sync, no spawn, never throws. A shell wrapper, a Volta or pnpm shim, or a Windows `.cmd` does not resolve to the package, so the runner answers (the impostor guard from wave 18 stays). - **No `@latest`**: the spec is always the bare `eas-cli`. - `EasCli` gets `global: boolean`. `mayDownloadEasCli` is false for a global install, so the auth preflight and the `status` budget treat it like a pinned CLI. - Printed command lines follow the spawn (`easCommandPrefix`): `eas …` with a recent global install, else `npx --yes eas-cli …` / `bunx eas-cli …`. - Auth passthrough has a new `global-eas` source. - LLP 0015 §Resolving the EAS CLI, the CHANGELOG, and the README are updated. ## Measurements (this machine, 2026-10-16) ### `status`, before vs after Before is `bff4f33` (#77, the base). After is `4b5b6f1`. Each case had 1 warm-up and 5 timed runs. Before each run, `.expo/agent-cli-eas-builds.json` was deleted, so every run did the real EAS build lookup. The app was a copy of a bun Expo app (SDK 57) linked to an EAS project with builds. The npm case is the same copy without `bun.lock`. `PATH` held only Homebrew and system dirs, with no global `eas` unless stated. Every run returned `ios: none · android: none`. | Project | Before (median, range) | After (median, range) | |---|---|---| | bun (`bunx`) | **10.98 s** (10.10–16.46) | **3.52 s** (2.88–3.74) | | npm (`npx`) | **3.99 s** (3.88–6.54) | **4.38 s** (4.22–5.29) | | bun + global eas-cli 25.0.0 | 10.98 s (base does not use a global install) | **2.78 s** (2.24–3.03) | | npm + global eas-cli 25.0.0 | 3.99 s (base does not use a global install) | **3.38 s** (2.48–4.40) | - bun: about 3× faster. `bunx eas-cli@latest` reinstalled on every run, and `bunx eas-cli` uses its cache. - npm: dropping `@latest` gives no gain. The difference is inside the run-to-run spread, because npx revalidates the packument for either spec. - A global `eas` is the gain for npm projects (about 0.6 s at the median), and it takes bun projects from 3.5 s to 2.8 s. ### Runner probes - `bunx eas-cli@latest --version`: registry GET + reinstall every run, 14.7–31.5 s. `bunx eas-cli --version`: no request, 2.6–5.8 s. - npx (11.17.0) revalidates the packument for both specs (~110 ms). - `agent-cli whoami`, warm: global `eas` 0.73–0.76 s vs `npx --yes eas-cli` 1.36–1.66 s. - bunx uses one scratch dir, `bunx-<uid>-eas-cli@latest`, for both the bare spec and `@latest`. On this machine that dir was broken (`Cannot find module 'tslib'`), and every bunx lookup failed until it was deleted. This also happens without this PR. ## Tests - Unit: `easCli-test` covers the global rung: >= 25.0.0, older, non-`eas-cli` package, first-on-PATH only, pin beats global, no-download, no runner. Existing expectations moved from `eas-cli@latest` to `eas-cli`. - E2E: `eas-runner-test` plants a real npm-style global layout (symlinked bin) at 25.0.0 and 24.9.0. `installStubEasRunnerAsync` now also plants a decoy `eas`, so a developer's own global `eas-cli` cannot answer in e2e. The stub runner now rejects `eas-cli@latest`. - `bun run typecheck`, `bun run format:check`, unit (5377 passed), e2e (910 passed) all green locally. - Live: with `npm i -g --prefix /tmp/geas eas-cli` (25.0.0) on PATH, `whoami` spawned `/tmp/geas/bin/eas`. Without it, `whoami` fell back to `npx --yes eas-cli`. Not run: `test:live*` suites. Those still call `npx eas-cli@latest` directly for their own setup, as does `.eas/workflows/agent-cli-cloud-e2e.yml`. This PR does not change them. --------- Co-authored-by: expo-tuft[bot] <288127324+expo-tuft[bot]@users.noreply.github.com> Co-authored-by: kudo <46429+kudo@users.noreply.github.com> Co-authored-by: Kudo Chien <kudo@expo.dev>
Stack 5/5 of the
statusplan. Based on #72. Tests only.Why
The last
statusbranches without an e2e were the ones that depend on what the runner has:xcrun simctlandadb. #72 listed them as left out; this closes them.How
xcrunin.stub-bin(first on thePATHthe run gets) answerssimctl list devices booted -jwith a booted iPhone or with none. A stubadbunder a per-testANDROID_HOME/platform-toolsanswersdevices -lwith an emulator or with none — the resolver readsANDROID_HOMEbeforePATH(src/device/adb.ts).unknown): the execute bit withheld and aPATHof the stub directory alone, because aPATHsearch skips a file it cannot run and finds the machine's ownxcrunnext.adbis spawned by path, so the bit alone suffices there.android emulator-5554); booted iOS simulator by name with both devices listed (F106; macOS only, the probe does not run elsewhere);absentwith the tools' reasons;unknown, never rounded down to none (POSIX only — a.cmdshim has no execute bit to withhold); a dev server up with nothing attached and no device → anexp://address ornavigate / --print-url, nevernavigate /; an EAS Simulator session on record →smoke --ios --easwith an app connected,navigate / --easwithout, the session still named when the tools could not answer, and the local path kept when a device is here (K7a); a tunnelled dev server (lock + detached log newer than it) →hostType: tunnel,tunnelUrl,openUrlson the tunnel host, thetunnelfact andopen in …: exp://…lines (K7c, K8); a stale tunnel dropped once its dev server is gone.Test Plan
bun run typecheck,bun run lint,bun run test:e2e -- status-test(130 pass locally on macOS; 2 cases skip on Windows, 1 on Linux by design).