vybekiit 0.7.32 → 0.7.34
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/dist/bin.js +303 -85
- package/dist/global-skills/aws-serverless/SKILL.md +168 -32
- package/dist/global-skills/aws-serverless/references/api-gateway.md +17 -0
- package/dist/global-skills/aws-serverless/references/architecture.md +9 -13
- package/dist/global-skills/aws-serverless/references/lambda.md +3 -3
- package/dist/global-skills/aws-serverless/references/orchestration.md +46 -20
- package/dist/global-skills/aws-serverless/references/production.md +1 -1
- package/dist/global-skills/eas-simulator/SKILL.md +15 -15
- package/dist/global-skills/eas-simulator/references/controllers.md +11 -7
- package/dist/global-skills/eas-simulator/references/run-your-app.md +8 -8
- package/dist/global-skills/eas-simulator/references/troubleshooting.md +10 -6
- package/dist/global-skills/email-best-practices/references/sending-reliability.md +17 -22
- package/dist/global-skills/extension-to-functions-codebase/SKILL.md +1 -0
- package/dist/global-skills/firebase-ai-logic-basics/SKILL.md +161 -76
- package/dist/global-skills/firebase-ai-logic-basics/references/flutter_setup.md +37 -0
- package/dist/global-skills/firebase-ai-logic-basics/references/ios_setup.md +97 -3
- package/dist/global-skills/firebase-ai-logic-basics/references/usage_patterns_android.md +88 -3
- package/dist/global-skills/firebase-ai-logic-basics/references/usage_patterns_web.md +91 -3
- package/dist/global-skills/firebase-app-hosting-basics/SKILL.md +5 -1
- package/dist/global-skills/firebase-auth-basics/SKILL.md +1 -0
- package/dist/global-skills/firebase-auth-basics/references/client_sdk_android.md +9 -9
- package/dist/global-skills/firebase-auth-basics/references/client_sdk_web.md +3 -3
- package/dist/global-skills/firebase-auth-basics/references/flutter_setup.md +22 -19
- package/dist/global-skills/firebase-auth-basics/references/security_rules.md +2 -2
- package/dist/global-skills/firebase-basics/SKILL.md +6 -2
- package/dist/global-skills/firebase-basics/references/android_setup.md +101 -37
- package/dist/global-skills/firebase-basics/references/ios_setup.md +57 -0
- package/dist/global-skills/firebase-basics/references/web_setup.md +52 -0
- package/dist/global-skills/firebase-crashlytics/SKILL.md +1 -0
- package/dist/global-skills/firebase-crashlytics/references/android_setup.md +84 -84
- package/dist/global-skills/firebase-crashlytics/references/ios_setup.md +1 -0
- package/dist/global-skills/firebase-data-connect/SKILL.md +1 -0
- package/dist/global-skills/firebase-data-connect/reference/config.md +8 -8
- package/dist/global-skills/firebase-data-connect/reference/realtime.md +4 -1
- package/dist/global-skills/firebase-data-connect/reference/sdk_android.md +33 -34
- package/dist/global-skills/firebase-data-connect/reference/sdk_web.md +8 -3
- package/dist/global-skills/firebase-data-connect/reference/security.md +13 -13
- package/dist/global-skills/firebase-firestore/SKILL.md +17 -7
- package/dist/global-skills/firebase-firestore/references/enterprise/android_sdk_usage.md +32 -32
- package/dist/global-skills/firebase-firestore/references/enterprise/indexes.md +2 -1
- package/dist/global-skills/firebase-firestore/references/standard/android_sdk_usage.md +14 -14
- package/dist/global-skills/firebase-firestore/references/standard/indexes.md +2 -1
- package/dist/global-skills/firebase-hosting-basics/SKILL.md +1 -0
- package/dist/global-skills/firebase-remote-config-basics/SKILL.md +2 -1
- package/dist/global-skills/firebase-remote-config-basics/references/android_setup.md +36 -37
- package/dist/global-skills/firebase-security-rules-auditor/SKILL.md +7 -6
- package/dist/global-skills/firestore-rules-creation/SKILL.md +22 -10
- package/dist/global-skills/manifest.json +2 -1
- package/dist/global-skills/neon/SKILL.md +31 -10
- package/dist/global-skills/neon-ai-gateway/SKILL.md +43 -14
- package/dist/global-skills/neon-functions/SKILL.md +12 -11
- package/dist/global-skills/neon-functions/references/sse.md +2 -2
- package/dist/global-skills/neon-object-storage/SKILL.md +5 -4
- package/dist/global-skills/neon-postgres/SKILL.md +5 -2
- package/dist/global-skills/neon-postgres/references/full-text-search.md +27 -17
- package/dist/global-skills/neon-postgres/references/hybrid-search.md +19 -15
- package/dist/global-skills/neon-postgres/references/lakebase-search-drizzle.md +99 -14
- package/dist/global-skills/neon-postgres/references/vector-search.md +93 -10
- package/dist/global-skills/neon-realtime/SKILL.md +207 -0
- package/dist/global-skills/neon-realtime/references/mutations.md +743 -0
- package/dist/global-skills/neon-realtime/references/queries.md +509 -0
- package/dist/global-skills/neon-realtime/references/reactivity.md +407 -0
- package/dist/global-skills/neon-realtime/references/ssr.md +695 -0
- package/dist/global-skills/neon-realtime/references/subscribing.md +485 -0
- package/dist/global-skills/resend/SKILL.md +7 -16
- package/dist/global-skills/resend/references/domains.md +1 -1
- package/dist/global-skills/resend/references/inboxes.md +349 -0
- package/dist/global-skills/resend/references/installation.md +3 -3
- package/dist/global-skills/resend/references/sending/best-practices.md +3 -3
- package/dist/global-skills/resend/references/sending/single-email-examples.md +3 -3
- package/dist/global-skills/resend/references/webhooks.md +9 -0
- package/dist/global-skills/stripe-best-practices/SKILL.md +18 -18
- package/dist/global-skills/stripe-best-practices/references/tax.md +26 -14
- package/dist/global-skills/use-railway/SKILL.md +6 -6
- package/dist/global-skills/use-railway/references/iac.md +2 -1
- package/dist/global-skills/use-railway/references/tracing.md +13 -5
- package/dist/global-skills/workers-best-practices/SKILL.md +1 -1
- package/dist/global-skills/wrangler/SKILL.md +3 -3
- package/dist/global-skills/xcode-project-setup/SKILL.md +1 -0
- package/package.json +8 -8
|
@@ -9,7 +9,7 @@ disable-model-invocation: true
|
|
|
9
9
|
|
|
10
10
|
# EAS Simulator
|
|
11
11
|
|
|
12
|
-
> **EAS service - costs apply.**
|
|
12
|
+
> **EAS service - costs apply.** Sessions count toward your account's pricing and limits and stop at their maximum duration. Stop a session with `eas simulator:stop` when the task is done. See https://expo.dev/pricing for current terms.
|
|
13
13
|
|
|
14
14
|
EAS Simulator runs a remote iOS simulator or Android emulator on EAS infrastructure that you drive from your machine — from the CLI, from an AI agent (via `agent-device`), and from a browser preview. It's the unlock for **environments that can't run a simulator locally** (Linux boxes, cloud/background agents like Cursor Cloud), and for letting an agent *verify* a change on a real device instead of only reasoning about code.
|
|
15
15
|
|
|
@@ -25,9 +25,9 @@ The frontmatter `description` carries the trigger phrases. In short: use this to
|
|
|
25
25
|
- **Generic simulator request:** use a suitable local simulator when available. If the host cannot run the requested simulator (for example, iOS on Linux or a cloud sandbox), use EAS Simulator after checking access. A non-macOS host may still support a local Android emulator.
|
|
26
26
|
- Honor an explicit local choice; hand off to `expo run:ios` / Xcode / Android Studio as appropriate. Clarify only when the requested environment remains ambiguous and affects the task.
|
|
27
27
|
|
|
28
|
-
When the user
|
|
29
|
-
|
|
30
|
-
the
|
|
28
|
+
When the user asks for EAS Simulator or a cloud simulator, start the session and do the
|
|
29
|
+
requested work without asking again. Stop the session when the work is done. Only check in
|
|
30
|
+
if the user set a limit you would go past, or if the work grows beyond what they asked for.
|
|
31
31
|
|
|
32
32
|
## Prerequisites
|
|
33
33
|
|
|
@@ -40,9 +40,9 @@ the session. Ask before exceeding a stated budget or expanding beyond the reques
|
|
|
40
40
|
|
|
41
41
|
## Session lifetime
|
|
42
42
|
|
|
43
|
-
- `--max-duration-minutes N` is the hard automatic-stop deadline.
|
|
43
|
+
- `--max-duration-minutes N` is the hard automatic-stop deadline. Any plan can set it, up to the plan limit (40 minutes on Free, 115 on paid plans). The timer starts when the session is ready.
|
|
44
44
|
- `--max-idle-time-minutes N` stops a session after that many inactive minutes. Omitted means **no idle timeout**: the session runs until its maximum duration or an explicit stop.
|
|
45
|
-
- **
|
|
45
|
+
- **Controller activity resets the idle timer** (`agent-device`, `argent`, and Appium commands, which are recorded as session events with producer `appium`). **Browser-preview activity does not reset it.** For a user-driven browser preview, rely on the maximum duration, not idle time, to bound the session.
|
|
46
46
|
|
|
47
47
|
## Check availability first
|
|
48
48
|
|
|
@@ -79,7 +79,7 @@ npx --yes eas-cli@latest simulator:start --platform ios --type agent-device --no
|
|
|
79
79
|
# agent-device runs on demand via npx — nothing installed globally.
|
|
80
80
|
npx --yes eas-cli@latest simulator:exec npx agent-device@latest open <app-or-url> --platform ios
|
|
81
81
|
npx --yes eas-cli@latest simulator:exec npx agent-device@latest snapshot -i # interactive UI tree → @e1, @e2 refs
|
|
82
|
-
npx --yes eas-cli@latest simulator:exec npx agent-device@latest press @e2 # tap a ref (
|
|
82
|
+
npx --yes eas-cli@latest simulator:exec npx agent-device@latest press @e2 # tap a ref (use 'press' or 'click')
|
|
83
83
|
npx --yes eas-cli@latest simulator:exec npx agent-device@latest screenshot ./shot.png
|
|
84
84
|
|
|
85
85
|
# 3. Stop the session and reset the dotenv. Omit --id to target the dotenv session.
|
|
@@ -87,11 +87,11 @@ npx --yes eas-cli@latest simulator:stop
|
|
|
87
87
|
printf '# managed by eas-cli\n' > .env.eas-simulator
|
|
88
88
|
```
|
|
89
89
|
|
|
90
|
-
To **watch** it live, hand the user the `webPreviewUrl` that `start` prints. All current session types include a browser preview; `agent-device`, `appium`, and `argent` also provide automation, while `web-preview-only` provides no automation interface. **This URL is for the *user's* browser — you cannot open it for them, and it must never touch the sim:**
|
|
90
|
+
To **watch** it live, hand the user the `webPreviewUrl` that `start` prints (in `--json`, `remoteConfig.webPreviewUrl`; for `web-preview-only` sessions, `remoteConfig.previewUrl`). All current session types include a browser preview, on iOS and Android; `agent-device`, `appium`, and `argent` also provide automation, while `web-preview-only` provides no automation interface. On Android, the expo.dev session page does not show the preview inline yet: **Open preview** opens it in a new tab. Android support is in development, so some iOS features may not work there. **This URL is for the *user's* browser — you cannot open it for them, and it must never touch the sim:**
|
|
91
91
|
- **"Open it here" (Cursor/VS Code)** → print the URL on its own line and tell the user to open Simple Browser (`Cmd/Ctrl+Shift+P` → "Simple Browser: Show") and paste it. Then **stop**: do not shell out to a system browser or a Cursor/VS Code URL handler, and do not ask "did a tab appear?" — you can't confirm it, the handoff is done.
|
|
92
92
|
- **Never `open` the `webPreviewUrl` on the sim.** It's a browser preview, not a deep link and not an `agent-device open` argument; routing it to the device renders a browser-in-a-browser (a real past failure).
|
|
93
93
|
- **Headless agent** (no display) → just return the URL as the deliverable.
|
|
94
|
-
- **Keeping it alive for the user to drive** → use `--max-duration-minutes N`
|
|
94
|
+
- **Keeping it alive for the user to drive** → use `--max-duration-minutes N` (up to the plan limit). Browser-preview activity does not reset `--max-idle-time-minutes`, so idle timeout is not a reliable lifetime bound for this case. Tell the user when the session expires, using the CLI's reported duration or expiry. Keep it running for the requested preview; stop sessions created for one-shot tasks when the task finishes.
|
|
95
95
|
|
|
96
96
|
`start` also prints a job-run URL.
|
|
97
97
|
|
|
@@ -135,7 +135,7 @@ copy of the CLI surface. Keep non-obvious behavioral guidance from this skill—
|
|
|
135
135
|
| Command | Purpose |
|
|
136
136
|
|---|---|
|
|
137
137
|
| `npx --yes eas-cli@latest simulator:availability [--json] [--non-interactive]` | Check access without creating a session. |
|
|
138
|
-
| `npx --yes eas-cli@latest simulator:start --platform ios\|android --name "<description>" [flags]` | Create a session; boot the sim + selected interface; write `.env.eas-simulator` by default; print the preview + job-run URLs. **Always pass `--name`**. `--json` does not suppress the dotenv; use `--out-config-type env` when no file should be written. |
|
|
138
|
+
| `npx --yes eas-cli@latest simulator:start --platform ios\|android --name "<description>" [flags]` | Create a session; boot the sim + selected interface; write `.env.eas-simulator` by default; print the preview + job-run URLs. **Always pass `--name`**. `--json` does not suppress the dotenv; use `--out-config-type env` when no file should be written (it prints only the controller `export` lines, without `EAS_SIMULATOR_SESSION_ID`, so pass `--id` to `get`/`stop`/`events`). |
|
|
139
139
|
| `npx --yes eas-cli@latest simulator:exec <cmd> [args…]` | Load `.env.eas-simulator`, then run `<cmd>` with that env. The bridge to the controller. |
|
|
140
140
|
| `npx --yes eas-cli@latest simulator:get [--id <id>] [--json] [--non-interactive]` | Session status + connection details, including the session name. **Use this to confirm readiness** (see *Operating principles*). |
|
|
141
141
|
| `npx --yes eas-cli@latest simulator:list [filters] [--limit N] [--after <cursor>] [--json]` | List and paginate project sessions; filter by status, type, platform, name prefix, and tags. |
|
|
@@ -178,10 +178,10 @@ If a controller fails to download a recording, retrieve it from [EAS session art
|
|
|
178
178
|
| `install-from-source <url> --platform ios` | Install from a URL — the VM downloads it (use for EAS artifacts) |
|
|
179
179
|
| `open <appId\|deep-link> --platform ios` | Launch an app (bundle id) or follow an app **deep link** (`exp+slug://…`). A first-time deep link raises a system **"Open in '<app>'?"** dialog — expect it (don't burn a snapshot discovering it) and `press 'label="Open"'` to hand off; it can be slow, so bound it with agent-device's own `--timeout` (e.g. `press 'label="Open"' --timeout 120000`) — **not** a shell `timeout` wrapper (macOS has no `timeout` binary). (Mode C sidesteps this dialog for the Metro-connect link via "Enter URL manually" — see run-your-app.md.) **Not** for the `webPreviewUrl` — that's a browser preview for the user, never the device. |
|
|
180
180
|
| `snapshot -i` | Interactive accessibility tree → `@e1`-style refs |
|
|
181
|
-
| `press <ref\|selector>` | Tap (e.g. `press @e2` or `press 'label="Open"'`)
|
|
181
|
+
| `press <ref\|selector>` | Tap (e.g. `press @e2` or `press 'label="Open"'`). `click <target>` also works. Use `press` or `click`: `tap` is a hidden alias that older versions reject |
|
|
182
182
|
| `fill <ref> "text"` | Type into a field |
|
|
183
|
-
| `screenshot <path>` | Capture the screen to a local PNG (downloaded from the daemon) — requires an app to be open (`open` first) |
|
|
184
|
-
| `record start` / `record stop
|
|
183
|
+
| `screenshot <path>` | Capture the screen to a local PNG (downloaded from the daemon) — requires an app to be open (`open` first). On iOS the default is 1x logical points (402x874 on iPhone 17); add `--pixel-density 3` for full resolution |
|
|
184
|
+
| `record start [path]` / `record stop` | Record the screen to a video at the `record start` path (`record stop` takes no path) — use this for **motion** (animations, gestures, transitions, timing), which a single screenshot can't capture |
|
|
185
185
|
| `metro prepare` / `metro reload` | Point a dev client at Metro / reload (Mode C) |
|
|
186
186
|
|
|
187
187
|
**Screenshots vs. video.** Default to `screenshot` for static state, but for anything that *moves* — an animation, a transition, a gesture, a timing/jank question — **record a video and inspect the frames** instead; a still can't prove motion. Both controllers record (agent-device `record start`/`stop`, argent `screen-recording-start`/`stop`). Recordings sample at ~30fps — enough to see visible jank, not to prove sub-frame 60/120Hz hitches. For **timing** specifically, argent drops static frames by default (turn `trimStatic` off) — that plus other per-controller gotchas are in [references/controllers.md](./references/controllers.md).
|
|
@@ -196,7 +196,7 @@ When the app crashes or closes on launch, read the iOS session's crash reports a
|
|
|
196
196
|
|
|
197
197
|
## Operating principles
|
|
198
198
|
|
|
199
|
-
The non-obvious mental model worth internalizing. Specific error→fix lookups (hung verbs, `tap
|
|
199
|
+
The non-obvious mental model worth internalizing. Specific error→fix lookups (hung verbs, `tap` rejected, `--platform`, `--json`, `pod install` locale, orphaned sessions, boot variability) live in [references/troubleshooting.md](./references/troubleshooting.md).
|
|
200
200
|
|
|
201
201
|
1. **Establish ground truth, then reset — don't patch-loop.** Never assume an existing session or Metro is yours or healthy. Before driving, confirm:
|
|
202
202
|
- **cwd** — you're in the intended Expo project dir (a misdirected `start`/`exec` sessions the *wrong app* + drops a stray `.env.eas-simulator`; `pwd` / check `app.json`).
|
|
@@ -227,7 +227,7 @@ printf '# managed by eas-cli\n' > .env.eas-simulator # clear the stale session
|
|
|
227
227
|
- [references/logs-and-crashes.md](./references/logs-and-crashes.md) — device logs and crash reports from an iOS session (read when the app crashes or misbehaves).
|
|
228
228
|
- [references/troubleshooting.md](./references/troubleshooting.md) — concrete errors and fixes.
|
|
229
229
|
|
|
230
|
-
Source of truth: Expo docs and the `eas` / `agent-device` CLIs (`npx --yes eas-cli@latest simulator:* --help`, `agent-device
|
|
230
|
+
Source of truth: Expo docs and the `eas` / `agent-device` CLIs (`npx --yes eas-cli@latest simulator:* --help`, `npx --yes eas-cli@latest simulator:exec npx agent-device@latest help [topic]`; `--help` after `simulator:exec` shows the EAS CLI help instead). This skill teaches how to apply them; it doesn't replace them.
|
|
231
231
|
|
|
232
232
|
## Submitting Feedback
|
|
233
233
|
If you encounter errors, misleading or outdated information in this skill, report it so Expo can improve:
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
- `argent` (Software Mansion) — a capable alternative controller; check its license for your use.
|
|
8
8
|
- `web-preview-only` — browser preview with no programmatic control.
|
|
9
9
|
|
|
10
|
-
All four types include a web preview. Before setting `--max-idle-time-minutes`, follow [Session lifetime](../SKILL.md#session-lifetime); activity does not reset the timer
|
|
10
|
+
All four types include a web preview. Before setting `--max-idle-time-minutes`, follow [Session lifetime](../SKILL.md#session-lifetime); browser-preview activity does not reset the timer.
|
|
11
11
|
|
|
12
12
|
## Appium
|
|
13
13
|
|
|
@@ -19,7 +19,7 @@ npx --yes eas-cli@latest simulator:start --platform ios --type appium --non-inte
|
|
|
19
19
|
npx --yes eas-cli@latest simulator:exec <appium-client> [args...]
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
The start flags `--build-id`, `--build-fingerprint`, `--application-archive-url`, or `--expo-go` (with `--launch-arg` and `--open-url`) install and launch the app in an Appium session too. Appium commands are recorded as session events with producer `appium`: they appear in `simulator:events` and reset the idle timer.
|
|
23
23
|
|
|
24
24
|
## agent-device verbs (run via `npx --yes eas-cli@latest simulator:exec npx agent-device@latest <verb>`)
|
|
25
25
|
|
|
@@ -28,16 +28,20 @@ agent-device is a thin **client** talking to a **daemon** (the daemon runs on th
|
|
|
28
28
|
The CLI help is written for agents and is the source of truth — run these for the full verb set and agentic loop guidance:
|
|
29
29
|
|
|
30
30
|
```bash
|
|
31
|
-
npx --yes eas-cli@latest simulator:exec npx agent-device@latest
|
|
31
|
+
npx --yes eas-cli@latest simulator:exec npx agent-device@latest help
|
|
32
32
|
npx --yes eas-cli@latest simulator:exec npx agent-device@latest help workflow
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
+
Use `help [topic]`, not `--help`: oclif catches `--help` after `simulator:exec` and prints the EAS CLI help.
|
|
36
|
+
|
|
35
37
|
EAS-specific notes:
|
|
36
38
|
|
|
37
|
-
-
|
|
39
|
+
- **Tap with `press` or `click`.** `tap` is a hidden alias of `press` (not in `help commands`), and older agent-device versions reject it.
|
|
38
40
|
- **`snapshot -i` is slow on iOS** — tens of seconds is normal; wait for it.
|
|
39
41
|
- **`install` uploads** a local binary to the daemon; **`install-from-source`** has the VM download from a URL (use for EAS artifacts — avoids a large upload).
|
|
40
|
-
- **Exercised against a live session:** `apps`, `install`, `install-from-source`, `open`, `snapshot -i`, `press`, `fill`, `screenshot`, `scroll`, `gesture` (needs a preset, e.g. `gesture swipe left`), `logs`, `record` (`start`/`stop
|
|
42
|
+
- **Exercised against a live session:** `apps`, `install`, `install-from-source`, `open`, `snapshot -i`, `press`, `fill`, `screenshot`, `scroll`, `gesture` (needs a preset, e.g. `gesture swipe left`), `logs`, `record` (`start [path]`/`stop`), `network`, `perf`.
|
|
43
|
+
- **Recording:** `record start ./clip.mp4`, then `record stop` (no path). The file goes to the `record start` path, with a `.gesture-telemetry.json` next to it, and the clip also uploads as a session artifact. If `record stop` times out while the remote device exports, run it again; add `--platform ios` if it cannot find the recording. Separately, EAS uploads a whole-session screen recording after the session stops (iOS and Android).
|
|
44
|
+
- **Remote proof:** `open` prints `Session state: /Users/expo/...` (iOS) or `/home/expo/...` (Android) on the remote device. `session state-dir` prints the local path, so it does not prove remote use. `metro` (`prepare`/`reload`) is the Mode C dev-client bridge. Pass `--platform ios`; run `<verb>` with no args to see its required subcommand/args.
|
|
41
45
|
|
|
42
46
|
## Recording download recovery
|
|
43
47
|
|
|
@@ -49,7 +53,7 @@ npx --yes eas-cli@latest simulator:get --id <session-id> --json
|
|
|
49
53
|
curl --fail --location --max-time 600 --output ./capture.mp4 '<downloadUrl>'
|
|
50
54
|
```
|
|
51
55
|
|
|
52
|
-
Use the URL returned by EAS, not a path on the simulator or a controller artifact id. If the recording has not appeared yet, poll the same session with a bounded wait for upload completion. Already-uploaded artifacts can be retrieved after the session stops using its explicit id.
|
|
56
|
+
Use the URL returned by EAS, not a path on the simulator or a controller artifact id. If the recording has not appeared yet, poll the same session with a bounded wait for upload completion. Already-uploaded artifacts can be retrieved after the session stops using its explicit id; they stay until the session is deleted. The `downloadUrl` is stable and needs no auth: each request redirects to a new signed URL that is valid for 1 hour, so if a download fails, request the same `downloadUrl` again. Give the download command more than 10 minutes in the outer runner, increase `--max-time` for larger files, and verify the downloaded video before reporting success.
|
|
53
57
|
|
|
54
58
|
Source: EAS CLI [simulator:get](https://github.com/expo/eas-cli/blob/main/packages/eas-cli/src/commands/simulator/get.ts) exposes `artifacts[].{id,name,filename,metadata,downloadUrl}`.
|
|
55
59
|
|
|
@@ -95,7 +99,7 @@ Where argent is weaker than agent-device Mode C — so it's **capable, not as fa
|
|
|
95
99
|
|
|
96
100
|
**Screenshot resolution and token cost.** Screenshots cost context tokens once the agent reads them, so resolution is a real tradeoff. **argent's `screenshot` has two independent levers.** `scale` sets the image resolution and defaults **low** (too coarse to judge layout), so pass a larger scale when you need to **read** the UI. `includeImageInContext:false` keeps an image **out of the agent's context entirely** (zero token cost) — use that for a baseline you'll only **diff** later, and keep *that* one at full resolution so the pixel diff stays accurate. So: scale down images you actually read; drop unread ones with `includeImageInContext`, don't just shrink them. Exact flags and the current default: argent's help.
|
|
97
101
|
|
|
98
|
-
**agent-device** screenshots default to
|
|
102
|
+
**agent-device** screenshots on iOS simulators default to 1x logical points (402x874 on iPhone 17); pass `--pixel-density 3` for full resolution when you need fine detail or a pixel-diff baseline, so match the capture to the question. From **v0.20.6** it gains the same lever argent has and drops the old one: `screenshot --scale <0.01–1>` proportionally resizes both dimensions (`1` = full resolution), with a token-conscious default via `AGENT_DEVICE_SCREENSHOT_SCALE` (or `screenshotScale` in config) that an explicit `--scale` overrides — keep it unset or `1` for pixel-diff baselines; the former `--max-size` is removed (older calls refused with migration guidance). Verify the version with `agent-device --version`. One caveat for remote sessions: the resize runs on the daemon, so a newer client against an older EAS session daemon can have `--scale` silently ignored and get full-res back.
|
|
99
103
|
|
|
100
104
|
**Connecting via MCP (Cursor, Claude Code, Codex, and others).** Install the CLI globally first — the package is `@swmansion/argent`, not `argent`:
|
|
101
105
|
|
|
@@ -4,7 +4,7 @@ The remote sim boots blank. You install a **simulator-targeted** build onto the
|
|
|
4
4
|
|
|
5
5
|
In all modes, the session is started the same way and driven through `npx --yes eas-cli@latest simulator:exec`. Replace `dev.example.app` with the app's iOS `bundleIdentifier` (from `app.json` → `ios.bundleIdentifier`), and run from the project directory.
|
|
6
6
|
|
|
7
|
-
> These sequences are **iOS**. For **Android**: build via `npx --yes eas-cli@latest build --platform android` (or local Gradle), `install` the `.apk` instead of an `.app
|
|
7
|
+
> These sequences are **iOS**. For **Android**: build via `npx --yes eas-cli@latest build --platform android` (or local Gradle), `install` the `.apk` instead of an `.app` (`.aab` fails), and skip `pod install`. Android sessions include a browser preview (`webPreviewUrl`), which the expo.dev session page opens in a new tab with **Open preview**. Android support is still in development, so some iOS features may not work.
|
|
8
8
|
|
|
9
9
|
## Starting a session (shared by all modes)
|
|
10
10
|
|
|
@@ -35,7 +35,7 @@ for i in $(seq 1 64); do
|
|
|
35
35
|
done
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
If you need the id explicitly, it's `EAS_SIMULATOR_SESSION_ID` in `.env.eas-simulator`. `start` also prints a `webPreviewUrl` (iOS-only
|
|
38
|
+
If you need the id explicitly, it's `EAS_SIMULATOR_SESSION_ID` in `.env.eas-simulator`. `start` also prints a `webPreviewUrl` (browser preview on iOS and Android; `remoteConfig.previewUrl` for `web-preview-only` sessions — surface it per the SKILL.md "watch it live" rules) and a job-run URL. Once live, the session env is in `.env.eas-simulator`, so `simulator:exec` works.
|
|
39
39
|
|
|
40
40
|
## Targeting a device — iPad, or several at once
|
|
41
41
|
|
|
@@ -53,16 +53,16 @@ The value must be a device the **remote runner** offers (NOT your local Xcode se
|
|
|
53
53
|
npx --yes eas-cli@latest simulator:exec npx agent-device@latest devices --json
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
-
Available iOS devices today: iPhone 17 / 17 Pro / 17 Pro Max / 17e / Air
|
|
56
|
+
Available iOS devices today: iPhone 17 (the default) / 17 Pro / 17 Pro Max / 17e / Air; iPad (A16), iPad Air 11-inch (M4), iPad Air 13-inch (M4), iPad mini (A17 Pro), iPad Pro 11-inch (M5), iPad Pro 13-inch (M5); plus Vision Pro and Apple TV. On Android, `--device` takes an AVD hardware profile id (e.g. `pixel_7`); all profiles render at 720x1600, density 300.
|
|
57
57
|
|
|
58
|
-
**
|
|
58
|
+
**Add a second simulator mid-session:** a session boots only one simulator at start. Use a separate agent-device session for the second one: pass `--session <name> --device "<name>"` (boot takes about 46 seconds), and pass `--session <name>` on each later verb for that device. Passing `--device` in the default session fails with `INVALID_ARGS` "already bound".
|
|
59
59
|
|
|
60
60
|
```bash
|
|
61
61
|
npx --yes eas-cli@latest simulator:exec npx agent-device@latest open <bundleId> "<devClientURL>" \
|
|
62
|
-
--platform ios --device "iPad Pro 13-inch (M5)" --relaunch
|
|
62
|
+
--platform ios --session ipad --device "iPad Pro 13-inch (M5)" --relaunch
|
|
63
63
|
```
|
|
64
64
|
|
|
65
|
-
- ⚠️ The **controller** `--device`
|
|
65
|
+
- ⚠️ The **controller** `--device` takes a **name only** — a UDID returns `DEVICE_NOT_FOUND`; use `--udid` for a UDID. (The start-time CLI `--device` above takes either.)
|
|
66
66
|
- `devices` reports each device's name, kind, and booted state, but **not** its iOS version.
|
|
67
67
|
|
|
68
68
|
---
|
|
@@ -139,7 +139,7 @@ npx --yes eas-cli@latest simulator:stop # omit --id → stops the doten
|
|
|
139
139
|
|
|
140
140
|
The agentic edit-and-see loop: a **dev (Debug) build** loads JS from your **Metro** over a tunnel, so edits appear on the remote sim via Fast Refresh. Two ways to connect the dev client to Metro:
|
|
141
141
|
|
|
142
|
-
- **Method 1 (recommended, eas-cli ≥ 22.4.0):** launch at session start — `simulator:start` installs the build, applies launch-args, and opens the Metro URL in one command, and the "Open in?" dialog is auto-handled. Needs a **remote** build source (`--build-id`, `--application-archive-url`, or `--expo-go`); a local `.app` can't be passed here.
|
|
142
|
+
- **Method 1 (recommended, eas-cli ≥ 22.4.0):** launch at session start — `simulator:start` installs the build, applies launch-args, and opens the Metro URL in one command, and the "Open in?" dialog is auto-handled. Needs a **remote** build source (`--build-id`, `--build-fingerprint`, `--application-archive-url`, or `--expo-go`); a local `.app` can't be passed here. `--build-fingerprint` selects the most recent finished, non-expired build with that hash (iOS: it must be a simulator build; Android: any distribution type can match, so use an APK profile). An iOS `--application-archive-url` must be a `.tar.gz` or `.tgz` that contains a `.app` (`.zip`, `.app.zip`, and `.ipa` fail); Android needs an `.apk`.
|
|
143
143
|
- **Method 2 (fallback):** drive the connect with the controller — for a **local `.app`** build, or eas-cli < 22.4.0.
|
|
144
144
|
|
|
145
145
|
⚠️ **Don't install a release build as a "quick interim" and screenshot it** — it shows stale, build-time code. Use a dev build + Metro; screenshot only after the dev client is connected.
|
|
@@ -181,7 +181,7 @@ npx --yes eas-cli@latest simulator:exec npx agent-device@latest screenshot ./liv
|
|
|
181
181
|
# VERIFY it's the REMOTE sim, not a silent local-sim fallback (agent-device falls back to a LOCAL sim with no
|
|
182
182
|
# error when the dotenv lacks remote config → believable but WRONG screenshots). Decisive tells: `simulator:get
|
|
183
183
|
# --json` returns the id `start` printed, AND the attach's "Session state:" path is under /Users/expo/ (remote
|
|
184
|
-
# VM), not /Users
|
|
184
|
+
# VM), not /Users/<you>/ (your Mac). The `sessions/` vs `remote-diagnostics/` directory name is NOT reliable.
|
|
185
185
|
|
|
186
186
|
# 4. Fast Refresh: edit a source file → it hits the remote sim with no reload. Screenshot again to confirm.
|
|
187
187
|
# 5. Stop: npx --yes eas-cli@latest simulator:stop # then kill the Metro process
|
|
@@ -11,21 +11,25 @@ Concrete errors seen while validating this flow, and the fix.
|
|
|
11
11
|
| `An Expo user account is required` / `whoami` shows logged-out | No browser login on a cloud/CI/headless box, or `EXPO_TOKEN` unset/invalid | Set **`EXPO_TOKEN`** (expo.dev → Account → Access Tokens) in the env; verify `npx --yes eas-cli@latest whoami`. (Interactive machines can `eas login`.) |
|
|
12
12
|
| `simulator:start`/`build`: no linked project / missing `projectId` | A fresh `create-expo-app` isn't linked to EAS | `npx --yes eas-cli@latest init` to create/link it (writes `extra.eas.projectId`). |
|
|
13
13
|
| `prebuild`/`eas build` prompts for or fails on a missing **iOS bundle identifier** | A fresh app often has no `ios.bundleIdentifier` | Set it in app config (e.g. `dev.<owner>.<slug>`); confirm via `npx expo config --json` (may live in `app.config.js`). |
|
|
14
|
-
| `--max-duration-minutes` rejected | The
|
|
15
|
-
|
|
|
14
|
+
| `--max-duration-minutes` rejected | The value is above the plan limit (40 minutes on Free, 115 on paid plans); inspect the CLI error | Pass a value within the plan limit, or omit the flag to use the default. |
|
|
15
|
+
| Browser-preview session stops despite ongoing interaction | Browser-preview activity does not reset `--max-idle-time-minutes`; only controller activity (`agent-device`, `argent`, Appium) does | Use the maximum duration as the lifetime bound for user-driven previews. Set it with `--max-duration-minutes`, and omit `--max-idle-time-minutes` unless controller inactivity is the intended stop condition. |
|
|
16
16
|
| `simulator:start` fails with `not enabled for this account` / not-allowlisted | EAS Simulator is limited-access and isn't enabled for this account | Don't retry. Confirm with `simulator:availability`, then hand off gracefully — tell the user and fall back to a local sim / EAS Build (see SKILL.md *Check availability first*). |
|
|
17
17
|
| `start` keeps "Waiting for … session to be ready" but it never returns | `start`'s readiness poll can miss a session that's actually live | Don't rely on it — poll `npx --yes eas-cli@latest simulator:get --id <id> --json` for `status: IN_PROGRESS` + a populated `remoteConfig`. |
|
|
18
18
|
| `ERR_NGROK_3200` / endpoint offline; `Remote daemon is unavailable` | The session's tunnel/daemon dropped — left idle and timed out, or the VM was torn down | A drop invalidates the **whole** session (installed app, `@e` refs, Metro). **Don't retry the failed verb** — start a fresh session, reset the dotenv, and re-run install→open→drive from the top, acting immediately. |
|
|
19
19
|
| Two sessions running / orphaned session | A second `start` (e.g. to "retry" a slow boot) creates another session and overwrites the dotenv id, orphaning the first | Poll the existing session instead. Find orphans with `simulator:list --status in-progress` and stop those you created with `simulator:stop --id <id>`. |
|
|
20
20
|
| A device verb hangs (no return for a minute+) | Slow daemon; `press`/`screenshot` can block ~90s | Bound it with agent-device's own `--timeout <ms>` (e.g. `--timeout 120000`) — **not** a shell `timeout` wrapper (macOS has no `timeout` binary, so `timeout 120 …` fails with `command not found` and skips the verb). On timeout `snapshot -i` to see if the action landed before retrying (taps can double-fire). Don't blind-retry. |
|
|
21
21
|
| `install requires an active session or an explicit device selector` | `install` can't infer the device | Pass `--platform ios` (or `open` something first to establish a session). |
|
|
22
|
-
| `DEVICE_NOT_FOUND: No device named <udid>` when targeting a non-default device (iPad, second sim) |
|
|
23
|
-
| `
|
|
22
|
+
| `DEVICE_NOT_FOUND: No device named <udid>` when targeting a non-default device (iPad, second sim) | agent-device's `--device` takes a **name** only | Pass the device **name** from `agent-device devices` (e.g. `--device "iPad Pro 13-inch (M5)"`), or pass a UDID with `--udid`. |
|
|
23
|
+
| `INVALID_ARGS` "already bound" when passing `--device` | The default agent-device session is already bound to the first simulator | Use a separate agent-device session for the second simulator: `--session <name> --device "<name>"` (see run-your-app.md). |
|
|
24
|
+
| `Unknown command: tap` | An older agent-device version; `tap` is now a hidden alias of `press` | Use `press <ref\|selector>` (e.g. `press @e2` or `press 'label="Open"'`) or `click <target>`. |
|
|
25
|
+
| `record stop` times out | The remote device is still exporting the clip | Run `record stop` again; add `--platform ios` if it cannot find the recording. The clip also uploads as a session artifact (see [controllers.md](./controllers.md#recording-download-recovery)). |
|
|
26
|
+
| `--application-archive-url` install fails | Unsupported archive type | iOS needs a `.tar.gz` or `.tgz` that contains a `.app` (`.zip`, `.app.zip`, and `.ipa` fail). Android needs an `.apk` (`.aab` fails). |
|
|
27
|
+
| `agent-device@latest --help` through `simulator:exec` shows the EAS CLI help | oclif catches `--help` | Use `... agent-device@latest help [topic]`. |
|
|
24
28
|
| `SESSION_NOT_FOUND: No active session. Run open first.` | A verb (e.g. `screenshot`) ran before any app/session was opened — **or** you used Method 1 (`simulator:start --open-url`), which launches the app but creates NO agent-device session | `open <app\|url>` first (or pass `--platform ios`). After a Method-1 launch, attach without relaunching: `agent-device open <bundleId> --foreground --platform ios` (pass the bundle id — `--foreground` alone fails `AMBIGUOUS_MATCH`), then screenshot. |
|
|
25
|
-
| Screenshot looks plausible but the session/UI is wrong (e.g. Safari, an iPhone shot when you booted an iPad, or "incompatible Expo Go SDK") | agent-device **silently falls back to a LOCAL simulator** when `.env.eas-simulator` has no remote config — no error, believable-but-wrong output. Common cause: a **concurrent `simulator:start`** on the same account/machine overwrote the shared dotenv with its own id (the dotenv is a single file, NOT concurrency-safe). | Confirm you're on the REMOTE VM: `simulator:get --json` returns the id `start` printed, AND the verb's "Session state:" path is under **`/Users/expo/`** (remote
|
|
29
|
+
| Screenshot looks plausible but the session/UI is wrong (e.g. Safari, an iPhone shot when you booted an iPad, or "incompatible Expo Go SDK") | agent-device **silently falls back to a LOCAL simulator** when `.env.eas-simulator` has no remote config — no error, believable-but-wrong output. Common cause: a **concurrent `simulator:start`** on the same account/machine overwrote the shared dotenv with its own id (the dotenv is a single file, NOT concurrency-safe). | Confirm you're on the REMOTE VM: `simulator:get --json` returns the id `start` printed, AND the verb's "Session state:" path is under **`/Users/expo/`** (iOS) or **`/home/expo/`** (Android) on the remote device, not `/Users/<you>/` (local). `session state-dir` prints the local path, so it is not proof; `devices --json` host is a `turtle-worker-*`. The `sessions/` vs `remote-diagnostics/` directory name is NOT a reliable tell. If concurrency is possible, drive by explicit id — load the daemon vars from `simulator:get --id <id> --json` — instead of trusting the dotenv. |
|
|
26
30
|
| `simulator:exec` / `build` / `simulator:stop`: "Run this command inside a project directory." | Run from the wrong cwd | Run from the Expo project directory (where `app.json`/`eas.json` live). |
|
|
27
31
|
| New session's id shows as the *previous* one; "Overwriting previous simulator session (id: …)" | `.env.eas-simulator` names an earlier session | Inspect it with `simulator:get --json`. Reuse it when it belongs to this run; stop it only when it is in scope and no longer needed. An `IN_PROGRESS` session may be intentionally concurrent, so preserve its id/config before resetting the dotenv and drive sessions by explicit id/config. Replacing the file does not stop the remote session. |
|
|
28
|
-
| No `.env.eas-simulator` written after `start` | `--out-config-type env` was selected, or the CLI reported a file-write failure | Use the default `--out-config-type dotenv` for the `exec` flow. `--json` changes output and implies non-interactive mode, but does not by itself suppress the completed dotenv write. |
|
|
32
|
+
| No `.env.eas-simulator` written after `start` | `--out-config-type env` was selected, or the CLI reported a file-write failure | Use the default `--out-config-type dotenv` for the `exec` flow. `--json` changes output and implies non-interactive mode, but does not by itself suppress the completed dotenv write. `--out-config-type env` prints only the controller `export` lines and no `EAS_SIMULATOR_SESSION_ID`, so pass `--id` to `get`, `stop`, and `events`. |
|
|
29
33
|
| `pod install` fails: `Unicode Normalization not appropriate for ASCII-8BIT` | Ruby 4 + CocoaPods with a non-UTF-8 locale | Re-run with `LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 pod install`. |
|
|
30
34
|
| (Mode C) Deep-link `open` lands on the dev-client launcher, not the app | The "Open in '<app>'?" system dialog wasn't accepted, so the deep link didn't take | Accept the dialog with `agent-device alert accept 2500 --platform ios` (not a UI tap). If it still lands on the launcher, fall back to "Enter URL manually" → `fill` the `https://<host>.on.expo.app` manifest URL → "Connect" (see run-your-app.md Mode C). |
|
|
31
35
|
| (Mode C) App shows expo-router "Unmatched Route" | The connect URL was parsed as a route path | `press 'label="Go back"'` (or navigate to `/`). |
|
|
@@ -59,24 +59,23 @@ Handle transient failures with exponential backoff.
|
|
|
59
59
|
### Exponential Backoff
|
|
60
60
|
|
|
61
61
|
```typescript
|
|
62
|
-
async function sendWithRetry(emailData, maxRetries =
|
|
62
|
+
async function sendWithRetry(emailData, maxRetries = 5) {
|
|
63
63
|
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
if (!isRetryable(error) || attempt === maxRetries - 1) {
|
|
68
|
-
throw error;
|
|
69
|
-
}
|
|
70
|
-
const delay = Math.min(1000 * Math.pow(2, attempt), 30000);
|
|
71
|
-
await sleep(delay + Math.random() * 1000); // Add jitter
|
|
64
|
+
const { data, error } = await resend.emails.send(emailData);
|
|
65
|
+
if (!error) {
|
|
66
|
+
return data;
|
|
72
67
|
}
|
|
68
|
+
if (!isRetryable(error) || attempt === maxRetries - 1) {
|
|
69
|
+
throw error;
|
|
70
|
+
}
|
|
71
|
+
const delay = Math.min(1000 * Math.pow(2, attempt), 30000);
|
|
72
|
+
await sleep(delay + Math.random() * 1000); // Add jitter
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
function isRetryable(error) {
|
|
77
77
|
return error.statusCode >= 500 ||
|
|
78
|
-
error.statusCode === 429
|
|
79
|
-
error.code === 'ETIMEDOUT';
|
|
78
|
+
error.statusCode === 429;
|
|
80
79
|
}
|
|
81
80
|
```
|
|
82
81
|
|
|
@@ -100,10 +99,9 @@ function isRetryable(error) {
|
|
|
100
99
|
### Error Handling Pattern
|
|
101
100
|
|
|
102
101
|
```typescript
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
} catch (error) {
|
|
102
|
+
const { data, error } = await resend.emails.send(emailData);
|
|
103
|
+
|
|
104
|
+
if (error) {
|
|
107
105
|
if (error.statusCode === 429) {
|
|
108
106
|
await queueForRetry(emailData, error.retryAfter);
|
|
109
107
|
} else if (error.statusCode >= 500) {
|
|
@@ -112,6 +110,8 @@ try {
|
|
|
112
110
|
await logFailure(error, emailData);
|
|
113
111
|
await alertOnCriticalEmail(emailData); // For password resets, etc.
|
|
114
112
|
}
|
|
113
|
+
} else {
|
|
114
|
+
await logSuccess(data.id, emailData);
|
|
115
115
|
}
|
|
116
116
|
```
|
|
117
117
|
|
|
@@ -137,14 +137,9 @@ For critical emails, use a queue to ensure delivery even if the initial send fai
|
|
|
137
137
|
Set appropriate timeouts to avoid hanging requests.
|
|
138
138
|
|
|
139
139
|
```typescript
|
|
140
|
-
const
|
|
141
|
-
const timeout = setTimeout(() => controller.abort(), 10000);
|
|
140
|
+
const signal = new AbortSignal.timeout(10000);
|
|
142
141
|
|
|
143
|
-
|
|
144
|
-
await resend.emails.send(emailData, { signal: controller.signal });
|
|
145
|
-
} finally {
|
|
146
|
-
clearTimeout(timeout);
|
|
147
|
-
}
|
|
142
|
+
await resend.emails.send(emailData, { signal });
|
|
148
143
|
```
|
|
149
144
|
|
|
150
145
|
**Recommended:** 10-30 seconds for email API calls.
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
name: extension-to-functions-codebase
|
|
3
3
|
description: Skill for converting an installed Firebase Extension (or extension source) into a standalone Cloud Functions for Firebase codebase or publishable npm package, including V1 to V2 trigger upgrades, lifecycle hooks, and declarative security
|
|
4
4
|
metadata:
|
|
5
|
+
author: Google LLC
|
|
5
6
|
category: Serverless
|
|
6
7
|
disable-model-invocation: true
|
|
7
8
|
---
|