opencode-skills-collection 4.0.69 → 4.0.70
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/bundled-skills/.antigravity-install-manifest.json +39 -1
- package/bundled-skills/api-integration-architect/SKILL.md +241 -0
- package/bundled-skills/apify-generate-output-schema/SKILL.md +438 -0
- package/bundled-skills/apify-integration-development/SKILL.md +168 -0
- package/bundled-skills/apify-integration-development/references/ai-framework-package.md +158 -0
- package/bundled-skills/apify-integration-development/references/ai-harness-plugin.md +192 -0
- package/bundled-skills/apify-integration-development/references/sdk-integration.md +236 -0
- package/bundled-skills/apify-integration-development/references/workflow-automation.md +163 -0
- package/bundled-skills/architecture-review/README.md +42 -0
- package/bundled-skills/architecture-review/SKILL.md +77 -0
- package/bundled-skills/architecture-review/examples.md +11 -0
- package/bundled-skills/architecture-review/reference/best-practices.md +7 -0
- package/bundled-skills/architecture-review/reference/capabilities.md +20 -0
- package/bundled-skills/architecture-review/reference/fallbacks.md +11 -0
- package/bundled-skills/architecture-review/reference/graph.md +15 -0
- package/bundled-skills/architecture-review/reference/mcp.md +14 -0
- package/bundled-skills/architecture-review/reference/workflow.md +15 -0
- package/bundled-skills/architecture-review/templates/architecture-review.md +21 -0
- package/bundled-skills/code-review-sensei/SKILL.md +177 -0
- package/bundled-skills/codebase-onboarding/README.md +42 -0
- package/bundled-skills/codebase-onboarding/SKILL.md +77 -0
- package/bundled-skills/codebase-onboarding/examples.md +11 -0
- package/bundled-skills/codebase-onboarding/reference/best-practices.md +7 -0
- package/bundled-skills/codebase-onboarding/reference/capabilities.md +20 -0
- package/bundled-skills/codebase-onboarding/reference/fallbacks.md +11 -0
- package/bundled-skills/codebase-onboarding/reference/graph.md +15 -0
- package/bundled-skills/codebase-onboarding/reference/mcp.md +14 -0
- package/bundled-skills/codebase-onboarding/reference/workflow.md +15 -0
- package/bundled-skills/codebase-onboarding/templates/repository-onboarding.md +21 -0
- package/bundled-skills/connection-auth-rules/SKILL.md +199 -0
- package/bundled-skills/connection-auth-rules/fetch_schema.py +320 -0
- package/bundled-skills/dependency-analysis/README.md +42 -0
- package/bundled-skills/dependency-analysis/SKILL.md +76 -0
- package/bundled-skills/dependency-analysis/examples.md +11 -0
- package/bundled-skills/dependency-analysis/reference/best-practices.md +7 -0
- package/bundled-skills/dependency-analysis/reference/capabilities.md +20 -0
- package/bundled-skills/dependency-analysis/reference/fallbacks.md +11 -0
- package/bundled-skills/dependency-analysis/reference/graph.md +15 -0
- package/bundled-skills/dependency-analysis/reference/mcp.md +14 -0
- package/bundled-skills/dependency-analysis/reference/workflow.md +15 -0
- package/bundled-skills/dependency-analysis/templates/dependency-review.md +21 -0
- package/bundled-skills/devops-pipeline-builder/SKILL.md +200 -0
- package/bundled-skills/eas-app-stores/SKILL.md +197 -0
- package/bundled-skills/eas-app-stores/agents/openai.yaml +4 -0
- package/bundled-skills/eas-app-stores/references/app-store-metadata.md +497 -0
- package/bundled-skills/eas-app-stores/references/ios-app-store.md +376 -0
- package/bundled-skills/eas-app-stores/references/native-ios.md +167 -0
- package/bundled-skills/eas-app-stores/references/play-store.md +244 -0
- package/bundled-skills/eas-app-stores/references/testflight.md +62 -0
- package/bundled-skills/eas-app-stores/references/workflows.md +120 -0
- package/bundled-skills/eas-hosting/SKILL.md +448 -0
- package/bundled-skills/eas-hosting/agents/openai.yaml +4 -0
- package/bundled-skills/eas-observe/SKILL.md +75 -0
- package/bundled-skills/eas-observe/agents/openai.yaml +4 -0
- package/bundled-skills/eas-observe/references/metrics.md +98 -0
- package/bundled-skills/eas-observe/references/queries.md +403 -0
- package/bundled-skills/eas-observe/references/setup.md +476 -0
- package/bundled-skills/eas-observe/references/third-party.md +136 -0
- package/bundled-skills/eas-simulator/SKILL.md +251 -0
- package/bundled-skills/eas-simulator/agents/openai.yaml +4 -0
- package/bundled-skills/eas-simulator/references/controllers.md +135 -0
- package/bundled-skills/eas-simulator/references/run-your-app.md +240 -0
- package/bundled-skills/eas-simulator/references/troubleshooting.md +47 -0
- package/bundled-skills/eas-workflows/SKILL.md +119 -0
- package/bundled-skills/eas-workflows/agents/openai.yaml +4 -0
- package/bundled-skills/eas-workflows/scripts/fetch.js +109 -0
- package/bundled-skills/expo-animation/LICENSE +21 -0
- package/bundled-skills/expo-animation/RECIPES.md +385 -0
- package/bundled-skills/expo-animation/SKILL.md +295 -0
- package/bundled-skills/expo-animation/agents/openai.yaml +4 -0
- package/bundled-skills/fact-check-x-unified/SKILL.md +178 -0
- package/bundled-skills/fact-check-x-unified/agents/openai.yaml +4 -0
- package/bundled-skills/fact-check-x-unified/references/acceptance-criteria.md +44 -0
- package/bundled-skills/fact-check-x-unified/references/contracts.md +39 -0
- package/bundled-skills/fact-check-x-unified/scripts/common.py +31 -0
- package/bundled-skills/fact-check-x-unified/scripts/fact_check_x.py +1832 -0
- package/bundled-skills/fact-check-x-unified/scripts/trusted_search_config.py +324 -0
- package/bundled-skills/fact-check-x-unified/tests/anchor_downgrade_test.py +90 -0
- package/bundled-skills/fact-check-x-unified/tests/multi_platform_test.py +369 -0
- package/bundled-skills/fact-check-x-unified/tests/smoke_test.py +740 -0
- package/bundled-skills/fact-check-x-unified/tests/stage_checkpoint_test.py +103 -0
- package/bundled-skills/fact-check-x-unified/tests/trusted_search_config_test.py +156 -0
- package/bundled-skills/gpt-taste/SKILL.md +8 -1
- package/bundled-skills/hf-cli/SKILL.md +263 -0
- package/bundled-skills/huggingface-community-evals/SKILL.md +228 -0
- package/bundled-skills/huggingface-community-evals/examples/.env.example +3 -0
- package/bundled-skills/huggingface-community-evals/examples/USAGE_EXAMPLES.md +101 -0
- package/bundled-skills/huggingface-community-evals/scripts/inspect_eval_uv.py +104 -0
- package/bundled-skills/huggingface-community-evals/scripts/inspect_vllm_uv.py +306 -0
- package/bundled-skills/huggingface-community-evals/scripts/lighteval_vllm_uv.py +297 -0
- package/bundled-skills/huggingface-datasets/SKILL.md +130 -0
- package/bundled-skills/jev-social/SKILL.md +182 -0
- package/bundled-skills/longbridge-derivatives/SKILL.md +117 -0
- package/bundled-skills/longbridge-derivatives/references/option.md +36 -0
- package/bundled-skills/longbridge-derivatives/references/options-advanced.md +101 -0
- package/bundled-skills/longbridge-derivatives/references/options-pnl.md +74 -0
- package/bundled-skills/longbridge-derivatives/references/options-strategy.md +82 -0
- package/bundled-skills/longbridge-derivatives/references/options-volatility.md +70 -0
- package/bundled-skills/longbridge-derivatives/references/warrant.md +12 -0
- package/bundled-skills/longbridge-quant/SKILL.md +151 -0
- package/bundled-skills/longbridge-quant/references/correlation.md +51 -0
- package/bundled-skills/longbridge-quant/references/execution-model.md +68 -0
- package/bundled-skills/longbridge-quant/references/factor-research.md +95 -0
- package/bundled-skills/longbridge-quant/references/factor-screen.md +101 -0
- package/bundled-skills/longbridge-quant/references/hedging.md +136 -0
- package/bundled-skills/longbridge-quant/references/ml-strategy.md +77 -0
- package/bundled-skills/longbridge-quant/references/multifactor.md +68 -0
- package/bundled-skills/longbridge-quant/references/pairs-trading.md +61 -0
- package/bundled-skills/longbridge-quant/references/quant-cli.md +133 -0
- package/bundled-skills/longbridge-quant/references/quant-stats.md +150 -0
- package/bundled-skills/longbridge-quant/references/seasonality.md +50 -0
- package/bundled-skills/longbridge-quant/references/strategy-optimizer.md +68 -0
- package/bundled-skills/longbridge-quant/references/volatility-strategy.md +52 -0
- package/bundled-skills/longbridge-research/SKILL.md +187 -0
- package/bundled-skills/longbridge-research/references/company-profile.md +96 -0
- package/bundled-skills/longbridge-research/references/company-tearsheet.md +82 -0
- package/bundled-skills/longbridge-research/references/competitive-analysis.md +81 -0
- package/bundled-skills/longbridge-research/references/consensus.md +92 -0
- package/bundled-skills/longbridge-research/references/coverage-initiation.md +76 -0
- package/bundled-skills/longbridge-research/references/defi-yield.md +60 -0
- package/bundled-skills/longbridge-research/references/finance-calendar.md +165 -0
- package/bundled-skills/longbridge-research/references/financial-planning.md +77 -0
- package/bundled-skills/longbridge-research/references/forecast-eps.md +39 -0
- package/bundled-skills/longbridge-research/references/fund-holder.md +44 -0
- package/bundled-skills/longbridge-research/references/hkipo-analysis.md +101 -0
- package/bundled-skills/longbridge-research/references/industry-peers.md +46 -0
- package/bundled-skills/longbridge-research/references/industry-rank.md +62 -0
- package/bundled-skills/longbridge-research/references/insider-trades.md +48 -0
- package/bundled-skills/longbridge-research/references/institution-rating.md +62 -0
- package/bundled-skills/longbridge-research/references/investment-ideas.md +69 -0
- package/bundled-skills/longbridge-research/references/investment-proposal.md +95 -0
- package/bundled-skills/longbridge-research/references/investors.md +87 -0
- package/bundled-skills/longbridge-research/references/onchain.md +70 -0
- package/bundled-skills/longbridge-research/references/post-investment.md +76 -0
- package/bundled-skills/longbridge-research/references/shareholder.md +72 -0
- package/bundled-skills/longbridge-research/references/short-positions.md +50 -0
- package/bundled-skills/longbridge-research/references/short-trades.md +50 -0
- package/bundled-skills/longbridge-research/references/stock-research.md +61 -0
- package/bundled-skills/longbridge-research/references/thesis-tracker.md +64 -0
- package/bundled-skills/makepad-2-0-animation/SKILL.md +318 -0
- package/bundled-skills/makepad-2-0-animation/references/animator-reference.md +433 -0
- package/bundled-skills/makepad-2-0-dsl/SKILL.md +492 -0
- package/bundled-skills/makepad-2-0-dsl/references/dsl-syntax-reference.md +511 -0
- package/bundled-skills/makepad-2-0-dsl/references/extended-guide.md +56 -0
- package/bundled-skills/makepad-2-0-dsl/references/property-system.md +757 -0
- package/bundled-skills/makepad-2-0-events/SKILL.md +497 -0
- package/bundled-skills/makepad-2-0-events/references/event-patterns.md +802 -0
- package/bundled-skills/makepad-2-0-events/references/extended-guide.md +590 -0
- package/bundled-skills/makepad-2-0-layout/SKILL.md +499 -0
- package/bundled-skills/makepad-2-0-layout/references/extended-guide.md +243 -0
- package/bundled-skills/makepad-2-0-layout/references/layout-patterns.md +881 -0
- package/bundled-skills/makepad-2-0-widgets/SKILL.md +261 -0
- package/bundled-skills/makepad-2-0-widgets/references/widget-advanced.md +648 -0
- package/bundled-skills/makepad-2-0-widgets/references/widget-catalog.md +547 -0
- package/bundled-skills/meeting-distiller-pro/SKILL.md +120 -0
- package/bundled-skills/monte-carlo-analyze-root-cause/SKILL.md +12 -1
- package/bundled-skills/monte-carlo-asset-health/SKILL.md +12 -1
- package/bundled-skills/monte-carlo-context-detection/SKILL.md +170 -0
- package/bundled-skills/monte-carlo-context-detection/references/signal-definitions.md +46 -0
- package/bundled-skills/remotion-captions/SKILL.md +57 -0
- package/bundled-skills/remotion-captions/agents/openai.yaml +7 -0
- package/bundled-skills/remotion-captions/assets/remotion-icon.svg +4 -0
- package/bundled-skills/remotion-captions/display-captions.md +190 -0
- package/bundled-skills/remotion-captions/import-srt-captions.md +73 -0
- package/bundled-skills/remotion-captions/transcribe-captions.md +70 -0
- package/bundled-skills/remotion-create/SKILL.md +106 -0
- package/bundled-skills/remotion-create/agents/openai.yaml +7 -0
- package/bundled-skills/remotion-create/assets/remotion-icon.svg +4 -0
- package/bundled-skills/remotion-create/tailwind.md +11 -0
- package/bundled-skills/remotion-create/video-layout.md +9 -0
- package/bundled-skills/remotion-docs/SKILL.md +67 -0
- package/bundled-skills/remotion-docs/agents/openai.yaml +7 -0
- package/bundled-skills/remotion-docs/assets/remotion-icon.svg +4 -0
- package/bundled-skills/remotion-interactivity/SKILL.md +270 -0
- package/bundled-skills/remotion-interactivity/agents/openai.yaml +7 -0
- package/bundled-skills/remotion-interactivity/assets/remotion-icon.svg +4 -0
- package/bundled-skills/remotion-render/SKILL.md +48 -0
- package/bundled-skills/remotion-render/agents/openai.yaml +7 -0
- package/bundled-skills/remotion-render/assets/remotion-icon.svg +4 -0
- package/bundled-skills/remotion-render/transparent-videos.md +106 -0
- package/bundled-skills/saas-pricing-strategist/SKILL.md +169 -0
- package/bundled-skills/score-eval/SKILL.md +35 -0
- package/bundled-skills/writing-guidelines/SKILL.md +60 -0
- package/package.json +1 -1
- package/skills_index.json +980 -3
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
# Running your app on the remote sim — tested sequences
|
|
2
|
+
|
|
3
|
+
The remote sim boots blank. You install a **simulator-targeted** build onto the session, then open it. Pick a mode from `SKILL.md`. (Sequences validated against eas-cli 20.3.x + agent-device 0.17.x in mid-2026. These commands are experimental — check the relevant subcommand's `--help` before using non-default flags.)
|
|
4
|
+
|
|
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
|
+
|
|
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`, and skip `pod install`. Current simulator session types include a web preview, though Android support is still in development and may lack iOS parity.
|
|
8
|
+
|
|
9
|
+
## Starting a session (shared by all modes)
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# If the dotenv names a session, inspect it first with simulator:get --json. Reuse it when it belongs
|
|
13
|
+
# to this run; stop it only when it is in scope and no longer needed. An IN_PROGRESS session may be
|
|
14
|
+
# intentionally concurrent, so preserve its id/config before resetting the dotenv. Replacing the file
|
|
15
|
+
# does not stop the remote session. Reset only after choosing how to handle the existing session.
|
|
16
|
+
printf '# managed by eas-cli\n' > .env.eas-simulator
|
|
17
|
+
|
|
18
|
+
# Start (the default --out-config-type dotenv writes .env.eas-simulator). It boots the sim + agent-device daemon.
|
|
19
|
+
# --json changes stdout but does not suppress the completed dotenv write; use --out-config-type env for no file.
|
|
20
|
+
# --name is required practice: it labels the session in simulator:list/get and on expo.dev.
|
|
21
|
+
# Describe what the run is for, in the user's terms — see "Always name the session" in SKILL.md.
|
|
22
|
+
npx --yes eas-cli@latest simulator:start --platform ios --type agent-device --non-interactive \
|
|
23
|
+
--name "Checkout flow screenshots"
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
`start`'s own poll is unreliable, so confirm liveness with a bounded loop (boot is ~90s–15min). `get`/`exec`/`stop` default to the session in `.env.eas-simulator`, so you can omit `--id`:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# Poll up to ~16 min; IN_PROGRESS + remoteConfig = live; a terminal status = failed boot (stop + restart).
|
|
30
|
+
for i in $(seq 1 64); do
|
|
31
|
+
S=$(npx --yes eas-cli@latest simulator:get --json --non-interactive 2>/dev/null)
|
|
32
|
+
echo "$S" | grep -q '"status": *"IN_PROGRESS"' && echo "$S" | grep -q remoteConfig && { echo "live"; break; }
|
|
33
|
+
echo "$S" | grep -qE '"status": *"(STOPPED|ERRORED)"' && { echo "boot failed — stop + restart"; break; }
|
|
34
|
+
sleep 15
|
|
35
|
+
done
|
|
36
|
+
```
|
|
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 browser preview — 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
|
+
|
|
40
|
+
## Targeting a device — iPad, or several at once
|
|
41
|
+
|
|
42
|
+
**Boot a specific device at session start** with `eas simulator:start --device "<name|UDID>"` (eas-cli ≥ 22.4.0) — this is how you run on an iPad instead of the default iPhone:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npx --yes eas-cli@latest simulator:start --platform ios --device "iPad Pro 13-inch (M5)" \
|
|
46
|
+
--non-interactive --name "iPad run"
|
|
47
|
+
# then install / launch / screenshot as usual — the iPad renders larger (e.g. 1032x1376).
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The value must be a device the **remote runner** offers (NOT your local Xcode set), by name **or** UDID. List them from a live session:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
npx --yes eas-cli@latest simulator:exec npx agent-device@latest devices --json
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Available iOS devices today: iPhone 17 / 17 Pro / 17 Pro Max / 17e / Air, and iPad (A16), iPad Air 11"/13" (M4), iPad mini (A17 Pro), iPad Pro 11"/13" (M5).
|
|
57
|
+
|
|
58
|
+
**Switch devices mid-session:** a session exposes ~16 sims but boots only one at start. Pass the **controller's** global `--device "<name>"` on `open` (and other verbs) to boot + target another; it stays booted alongside the first, so pass `--device` on each verb to say which it hits.
|
|
59
|
+
|
|
60
|
+
```bash
|
|
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
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
- ⚠️ The **controller** `--device` resolves by **NAME only** — a udid returns `DEVICE_NOT_FOUND`. (The start-time CLI `--device` above takes either.)
|
|
66
|
+
- `devices` reports each device's name, kind, and booted state, but **not** its iOS version.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Mode A — Local release build (embedded JS, no Metro)
|
|
71
|
+
|
|
72
|
+
A Release build bundles the JS into the binary, so it renders without Metro. Good for a quick "run my current code on a cloud device" when a Mac toolchain is available.
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
# 1. Generate native project + build a Release simulator .app
|
|
76
|
+
npx expo prebuild --platform ios # set ios.bundleIdentifier in app.json first to avoid prompts
|
|
77
|
+
# pod install can fail on Ruby 4 + CocoaPods with a Unicode/ASCII-8BIT error — fix with a UTF-8 locale:
|
|
78
|
+
( cd ios && LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 pod install )
|
|
79
|
+
LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 xcodebuild \
|
|
80
|
+
-workspace ios/<App>.xcworkspace -scheme <App> \
|
|
81
|
+
-configuration Release -sdk iphonesimulator -derivedDataPath ios/build build
|
|
82
|
+
# → ios/build/Build/Products/Release-iphonesimulator/<App>.app
|
|
83
|
+
|
|
84
|
+
# 2. Start a session (see "Starting a session" above), then install + open + drive
|
|
85
|
+
APP=ios/build/Build/Products/Release-iphonesimulator/<App>.app
|
|
86
|
+
npx --yes eas-cli@latest simulator:exec npx agent-device@latest install dev.example.app "$APP" --platform ios
|
|
87
|
+
npx --yes eas-cli@latest simulator:exec npx agent-device@latest open dev.example.app --platform ios
|
|
88
|
+
npx --yes eas-cli@latest simulator:exec npx agent-device@latest screenshot ./shot.png
|
|
89
|
+
|
|
90
|
+
# 3. Stop
|
|
91
|
+
npx --yes eas-cli@latest simulator:stop # omit --id → stops the dotenv session
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
The `install` here **uploads** the (~90MB) `.app` to the remote daemon over the tunnel, which installs it on the sim with `simctl`.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Mode B — EAS build (the VM downloads it; no credentials)
|
|
99
|
+
|
|
100
|
+
**Explicit-only** (see the SKILL.md mode picker): a *static* EAS artifact for CI/sharing, or when the user names an existing EAS build. For no-Mac **live** iteration use Mode C with an EAS dev-client build (see Mode C below), not this. **Simulator builds are unsigned, so EAS asks for no credentials.**
|
|
101
|
+
|
|
102
|
+
⚠️ **Check for an existing build first.** Before triggering a new build, check if a fingerprint-matched one already exists — it saves ~15-20 min:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
npx --yes eas-cli@latest build:list --platform ios --profile <your-sim-profile> --status finished --json | \
|
|
106
|
+
head -20 # <your-sim-profile> = the profile you find/create in step 1; look for one whose fingerprint matches current source
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
If one matches, skip straight to step 3 with its artifact URL.
|
|
110
|
+
|
|
111
|
+
⚠️ **Order matters:** build FIRST, `start` the session LAST. The build takes ~15-20 min and a session left idle that long times out (`ERR_NGROK_3200`) — don't `start` until you have the artifact URL.
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
# 1. Find or create a simulator build profile in eas.json.
|
|
115
|
+
# Read eas.json if it exists and look for a build profile with ios.simulator: true.
|
|
116
|
+
# If one exists, note its name and skip to step 2.
|
|
117
|
+
# If not, add one named "sim" — use node, python3, jq, or a direct JSON edit, whichever
|
|
118
|
+
# is available. Preserve all other profiles. Minimum: { "ios": { "simulator": true } }
|
|
119
|
+
|
|
120
|
+
# 2. Build (no credentials prompt for a simulator build). Prints an artifact URL when done (~15-20 min).
|
|
121
|
+
npx --yes eas-cli@latest build --platform ios --profile sim --non-interactive
|
|
122
|
+
# → https://expo.dev/artifacts/eas/<hash>.tar.gz
|
|
123
|
+
|
|
124
|
+
# 3. Start a session, then install-from-source so the VM downloads the artifact (no local upload)
|
|
125
|
+
ART="https://expo.dev/artifacts/eas/<hash>.tar.gz"
|
|
126
|
+
npx --yes eas-cli@latest simulator:exec npx agent-device@latest install-from-source "$ART" --platform ios
|
|
127
|
+
npx --yes eas-cli@latest simulator:exec npx agent-device@latest open dev.example.app --platform ios
|
|
128
|
+
npx --yes eas-cli@latest simulator:exec npx agent-device@latest screenshot ./shot.png
|
|
129
|
+
|
|
130
|
+
# 4. Stop
|
|
131
|
+
npx --yes eas-cli@latest simulator:stop # omit --id → stops the dotenv session
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**Build freshness:** reuse only a build whose **fingerprint matches current source** (`npx --yes eas-cli@latest build:list --platform ios --json`, or `get-build` by fingerprint per Callstack's public `eas-agent-device` workflow); otherwise **rebuild** or use Mode C. Tell the user which build you used. (Why this matters → SKILL.md "Reusing an existing build" caveat.)
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Mode C — Dev build + tunnel (live edits via Fast Refresh)
|
|
139
|
+
|
|
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
|
+
|
|
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.
|
|
143
|
+
- **Method 2 (fallback):** drive the connect with the controller — for a **local `.app`** build, or eas-cli < 22.4.0.
|
|
144
|
+
|
|
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.
|
|
146
|
+
|
|
147
|
+
### Get a dev-client build (either method needs one)
|
|
148
|
+
|
|
149
|
+
- **Local (Mac):** `npx expo install expo-dev-client`; `npx expo prebuild --platform ios --clean` (set `ios.bundleIdentifier` first); `( cd ios && LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 pod install )`; then `xcodebuild -workspace ios/<App>.xcworkspace -scheme <App> -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build-debug build` → `ios/build-debug/Build/Products/Debug-iphonesimulator/<App>.app`. A local `.app` → **Method 2 only**.
|
|
150
|
+
- **EAS (no Mac, or to use Method 1):** ensure a profile with `developmentClient: true` + `ios.simulator: true`, then `npx --yes eas-cli@latest build --platform ios --profile <dev-sim> --non-interactive`. Note the **build id** (Method 1's `--build-id`) or the artifact URL. Reuse a fingerprint-matched build to skip the ~15-20 min.
|
|
151
|
+
|
|
152
|
+
### Method 1 — launch at session start (recommended)
|
|
153
|
+
|
|
154
|
+
⚠️ **Metro FIRST, then `simulator:start`** — the runner opens `--open-url` during startup, with no retry.
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
# 1. Start Metro with a tunnel on your own free port (tunnel-backend details at the end of this mode).
|
|
158
|
+
EXPO_UNSTABLE_TUNNEL_V2=1 npx expo start --tunnel --port <your-free-port> # background it durably
|
|
159
|
+
# Capture the manifest host. Headless runs won't print it — read ngrok's API (curl -s 127.0.0.1:4040/api/tunnels)
|
|
160
|
+
# or the manifest (curl -s -H "expo-platform: ios" localhost:<port>/ → launchAsset.url).
|
|
161
|
+
|
|
162
|
+
# 2. Start the session AND install+launch+open the app in one command (--launch-arg = one token per flag):
|
|
163
|
+
# Dev client: --build-id <id>, --open-url <scheme>://expo-development-client/?url=https://<manifest-host>
|
|
164
|
+
# (scheme = app.json `scheme`, NOT the slug; URL-encode the inner url if it has a path/query)
|
|
165
|
+
# Expo Go: --expo-go instead of --build-id, and --open-url exp://<manifest-host> (no port; https opens Safari)
|
|
166
|
+
npx --yes eas-cli@latest simulator:start --platform ios --build-id <BUILD_ID> \
|
|
167
|
+
--launch-arg "-EXDevMenuIsOnboardingFinished" --launch-arg "1" \
|
|
168
|
+
--launch-arg "-EXDevMenuShowsAtLaunch" --launch-arg "0" \
|
|
169
|
+
--launch-arg "-EXDevMenuShowFloatingActionButton" --launch-arg "0" \
|
|
170
|
+
--open-url "<scheme>://expo-development-client/?url=https://<manifest-host>" \
|
|
171
|
+
--non-interactive --name "Coin flip live edits"
|
|
172
|
+
# The app installs, launches with the launch-args (onboarding/dev-menu/gear suppressed), and opens the URL.
|
|
173
|
+
# The "Open in '<app>'?" dialog is auto-bypassed (the CLI writes the scheme approval) and the approval
|
|
174
|
+
# persists session-wide — so NO `alert accept` is needed, here or for later controller opens.
|
|
175
|
+
# `start` prints NOTHING about the install/launch — confirm from Metro's `iOS Bundled …` line.
|
|
176
|
+
|
|
177
|
+
# 3. To screenshot/drive, ATTACH the controller once — the CLI launch makes NO agent-device session, so a bare
|
|
178
|
+
# `screenshot` fails `SESSION_NOT_FOUND`. `open --foreground` attaches without relaunching:
|
|
179
|
+
npx --yes eas-cli@latest simulator:exec npx agent-device@latest open <bundleId> --foreground --platform ios
|
|
180
|
+
npx --yes eas-cli@latest simulator:exec npx agent-device@latest screenshot ./live.png
|
|
181
|
+
# VERIFY it's the REMOTE sim, not a silent local-sim fallback (agent-device falls back to a LOCAL sim with no
|
|
182
|
+
# error when the dotenv lacks remote config → believable but WRONG screenshots). Decisive tells: `simulator:get
|
|
183
|
+
# --json` returns the id `start` printed, AND the attach's "Session state:" path is under /Users/expo/ (remote
|
|
184
|
+
# VM), not /Users/gabe/ (your Mac). The `sessions/` vs `remote-diagnostics/` directory name is NOT reliable.
|
|
185
|
+
|
|
186
|
+
# 4. Fast Refresh: edit a source file → it hits the remote sim with no reload. Screenshot again to confirm.
|
|
187
|
+
# 5. Stop: npx --yes eas-cli@latest simulator:stop # then kill the Metro process
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Method 2 — drive the connect with the controller (fallback)
|
|
191
|
+
|
|
192
|
+
For a **local `.app`** (can't be passed to `--build-id`) or **eas-cli < 22.4.0**. Start a plain session (see "Starting a session"), install the build, then deep-link the dev client:
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
# install: a local .app uploads over the tunnel; an EAS artifact uses install-from-source (VM downloads it):
|
|
196
|
+
npx --yes eas-cli@latest simulator:exec npx agent-device@latest install <bundleId> "$DEVAPP" --platform ios
|
|
197
|
+
# (EAS artifact instead: install-from-source "https://expo.dev/artifacts/eas/<hash>.tar.gz" --platform ios)
|
|
198
|
+
|
|
199
|
+
# connect: `open <bundleId> <devClientURL>` deep-links into the bundle, skipping the launcher UI. Assemble
|
|
200
|
+
# <devClientURL> from the app's SCHEME (app.json `scheme`, NOT the slug): <scheme>://expo-development-client/?url=https://<manifest-host>
|
|
201
|
+
npx --yes eas-cli@latest simulator:exec npx agent-device@latest open <bundleId> "<devClientURL>" --platform ios --relaunch \
|
|
202
|
+
--launch-args "-EXDevMenuIsOnboardingFinished" --launch-args "1" \
|
|
203
|
+
--launch-args "-EXDevMenuShowsAtLaunch" --launch-args "0" \
|
|
204
|
+
--launch-args "-EXDevMenuShowFloatingActionButton" --launch-args "0"
|
|
205
|
+
# a controller open on a BARE session (no Method-1 launch to pre-approve the scheme) can raise the
|
|
206
|
+
# "Open in '<app>'?" dialog — accept it (no-op if absent; not needed after a Method-1 launch):
|
|
207
|
+
npx --yes eas-cli@latest simulator:exec npx agent-device@latest alert accept 2500 --platform ios
|
|
208
|
+
# then screenshot; if it shows the launcher not the app, the deep link didn't take → manual fallback:
|
|
209
|
+
# press 'label="Enter URL manually"' → snapshot -i → fill @<field> "<manifest URL>" → press 'label="Connect"'
|
|
210
|
+
# → press 'label="Reload"'; press 'label="Go back"' if expo-router shows "Unmatched Route".
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Dev-menu launch flags (both methods)
|
|
214
|
+
|
|
215
|
+
The launch-args are iOS UserDefaults (`-Key Value`), verified in expo/expo `packages/expo-dev-menu`. By default the onboarding popup, auto-opened dev menu, and floating gear all show and clutter screenshots; these suppress them:
|
|
216
|
+
- `-EXDevMenuIsOnboardingFinished 1` — skip the first-run onboarding popup (dev client **and** Expo Go)
|
|
217
|
+
- `-EXDevMenuShowsAtLaunch 0` — don't auto-open the dev menu at launch (dev client)
|
|
218
|
+
- `-EXDevMenuShowFloatingActionButton 0` — hide the floating gear (defaults visible on both)
|
|
219
|
+
|
|
220
|
+
Method 1 passes each as two flags: `--launch-arg "<key>" --launch-arg "<value>"`. Method 2 passes them as `--launch-args`.
|
|
221
|
+
|
|
222
|
+
### Metro tunnel backends (both methods)
|
|
223
|
+
|
|
224
|
+
#### Tunnel scope and approvals
|
|
225
|
+
|
|
226
|
+
Mode C needs a route from the EAS VM to your local Metro server. The account-signed Expo tunnel is the normal transport for this workflow: it forwards requests to `http://localhost:<your-free-port>` so the remote app can fetch its development manifest, JavaScript bundle, and assets and receive live updates. Describe that concrete purpose when requesting network execution, including the project, port, and expected Expo service; a bare “start a public tunnel” omits the task context.
|
|
227
|
+
|
|
228
|
+
Use the user's existing authorization for remote development and its required networking when it covers this operation. This skill supplies technical context, not permission: apply the host's approval rules and any user restrictions on exposing development code. A signed tunnel URL authenticates tunnel creation to an Expo account; it is **not proof that requests to the public Metro URL require authentication**. Keep the URL within the intended session and stop your Metro process when finished.
|
|
229
|
+
|
|
230
|
+
If approval review rejects the tunnel, explain the exact action and stated reason. Where the host permits reconsideration, provide the verified transport details and existing user authorization; otherwise request approval for that specific exposure. Keep a live-edit request on Mode C while resolving the block. Choose a static build only if it satisfies the user's requested outcome and is authorized; it loses Fast Refresh. Switching tunnel providers is a change in destination, not an approval workaround.
|
|
231
|
+
|
|
232
|
+
Source: Expo CLI's [AsyncWsTunnel.ts](https://github.com/expo/expo/blob/main/packages/%40expo/cli/src/start/server/AsyncWsTunnel.ts) resolves the Expo account, requests a signed URL, and sets the local target port. Verify the installed CLI's actual backend below: the environment flag alone does not prove it selected Expo's service.
|
|
233
|
+
|
|
234
|
+
#### Backend selection
|
|
235
|
+
|
|
236
|
+
Start Metro on your OWN free port — each run gets its own tunnel URL, so never fight for or kill :8081 (#133's rule). BOTH backends accept ANY `--port`:
|
|
237
|
+
- **ws-tunnel v2 (account-signed):** `EXPO_UNSTABLE_TUNNEL_V2=1` — signed URL for your EAS account, `on.expo.app` host, and the path for robot/EXPO_TOKEN/cloud agents (plain ngrok is blocked for them). Needs login / an EAS-linked project; if the signed URL fails, the CLI says to unset the flag and use ngrok.
|
|
238
|
+
- **ngrok (plain `--tunnel`, no flag):** `<host>.exp.direct` host; blocked for robot/EXPO_TOKEN users.
|
|
239
|
+
|
|
240
|
+
The ONLY 8081 lock is the LEGACY ws-tunnel path — hit WITHOUT the v2 account URL (an older CLI where the flag no-ops, or `EXPO_FORCE_WEBCONTAINER_ENV=1`). Do NOT set `EXPO_FORCE_WEBCONTAINER_ENV` to "fix" a port — it forces that legacy path and locks you to 8081. On an older CLI (e.g. expo 56) the v2 flag no-ops and you get ngrok on your chosen port (verified: expo 56.0.3 → ngrok on :8083).
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Troubleshooting
|
|
2
|
+
|
|
3
|
+
Concrete errors seen while validating this flow, and the fix.
|
|
4
|
+
|
|
5
|
+
| Symptom | Cause | Fix |
|
|
6
|
+
|---|---|---|
|
|
7
|
+
| Approval review rejects the Mode C Metro tunnel | Review needs the actual destination, development-code exposure, and user authorization; a signed URL alone does not establish private access | Follow [Tunnel scope and approvals](./run-your-app.md#tunnel-scope-and-approvals). Explain Expo's transport and preserve the requested live workflow while resolving approval. |
|
|
8
|
+
| Controller recording download fails or times out | The local transfer can fail even though EAS retains the recording | Fetch it from [EAS session artifacts](./controllers.md#recording-download-recovery) using the original EAS session id and the recording’s `downloadUrl`. |
|
|
9
|
+
| `Command simulator:start not found` | `eas-cli` too old (commands are hidden but present from ≥ 20.3.0) | Run via `npx --yes eas-cli@latest …`, or upgrade `eas-cli`. |
|
|
10
|
+
| `simulator:start` rejects `--name` (e.g. `Nonexistent flag: --name`) | `eas-cli` too old — `--name` was added after `simulator:start` itself | Run via `npx --yes eas-cli@latest …`, or upgrade `eas-cli`. If you can't upgrade, retry once **without** `--name`; the session starts unnamed. |
|
|
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
|
+
| `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
|
+
| `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 requested duration may not be supported by the account; inspect the CLI error | Use the default session limit when the custom duration is unavailable. |
|
|
15
|
+
| Appium or browser-preview session stops despite ongoing interaction | Only activity reported through `agent-device` and `argent` resets `--max-idle-time-minutes`; Appium commands and browser-preview activity do not | Use the maximum duration as the lifetime bound for Appium and user-driven previews. Customize it with `--max-duration-minutes` when supported by the account, and omit `--max-idle-time-minutes` unless inactivity from a supported controller is the intended stop condition. |
|
|
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
|
+
| `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
|
+
| `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
|
+
| 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
|
+
| 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
|
+
| `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) | In a remote session agent-device's `--device` resolves by **name**, not udid (despite the CLI docs) | Pass the device **name** from `agent-device devices` (e.g. `--device "iPad Pro 13-inch (M5)"`), not the udid. |
|
|
23
|
+
| `Unknown command: tap` | The tap verb is `press` | Use `press <ref\|selector>` (e.g. `press @e2` or `press 'label="Open"'`). |
|
|
24
|
+
| `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), not `/Users/<you>/` (local); `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
|
+
| `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
|
+
| 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. |
|
|
29
|
+
| `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
|
+
| (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
|
+
| (Mode C) App shows expo-router "Unmatched Route" | The connect URL was parsed as a route path | `press 'label="Go back"'` (or navigate to `/`). |
|
|
32
|
+
| (Mode C) Dev client shows a `?` placeholder / blank after connect | Bundle not fetched yet | `press 'label="Reload"'` and wait ~40-60s for the first build+transfer over the tunnel. |
|
|
33
|
+
| (Mode C) `expo start` fails: "port 8081 already in use" | Another Metro owns 8081 | Don't kill it. Start on your own `--port` — **both** `EXPO_UNSTABLE_TUNNEL_V2=1` (account-signed) and plain ngrok accept any port. Only the LEGACY ws-tunnel path is 8081-locked (see the `WS_TUNNEL_PORT` row). Reuse a Metro only if you started it this session. |
|
|
34
|
+
| (Mode C) `expo start` / `node` killed with **exit 137** | 137 = SIGKILL — almost always the **OOM killer** (memory pressure, common in constrained cloud sandboxes, esp. a native build + Metro at once). **Not** a port clash. | Reduce memory pressure: don't run a native build and Metro concurrently; give the sandbox more memory; retry. |
|
|
35
|
+
| (Mode C) Edits won't live-reload no matter how often you reconnect | A **release** build is installed — its JS is baked in, so it ignores Metro | Stop reconnecting: **install the dev (Debug) build**, connect it to Metro, reload. Reconnecting a release build to Metro is a no-op. |
|
|
36
|
+
| `expo start --tunnel` errors for a robot/`EXPO_TOKEN` user | The ngrok robot-user guard blocks plain (ngrok) tunnels | Use ws-tunnel v2 (account-signed, **any** port): `EXPO_UNSTABLE_TUNNEL_V2=1 expo start --tunnel --port <any>` — needs login / an EAS-linked project. Do NOT use `EXPO_FORCE_WEBCONTAINER_ENV`; that forces the legacy path, which is 8081-locked. |
|
|
37
|
+
| `CommandError: WS-tunnel only supports tunneling over port 8081` | You're on the **legacy** ws-tunnel path — no v2 account URL (older CLI where `EXPO_UNSTABLE_TUNNEL_V2` is a no-op, not logged in, or `EXPO_FORCE_WEBCONTAINER_ENV` set) | Get onto the account-signed v2 path: set `EXPO_UNSTABLE_TUNNEL_V2=1` and log in / link the project — then any `--port` works. Otherwise use `--port 8081`, or the ngrok path (drop the flag; non-robot only). |
|
|
38
|
+
| Unexpected charges / a session you forgot | `start --non-interactive` does NOT auto-stop | Always `npx --yes eas-cli@latest simulator:stop --id <id>`. List leftovers with `npx --yes eas-cli@latest simulator:list`. |
|
|
39
|
+
| Screenshot shows **old content** / my recent edits don't appear | Running a **release build (Mode A/B)** whose JS was baked in *before* your edits — typically a reused/stale build | A/B reflect code at build time, not now. **Rebuild** (ensure the build's fingerprint matches current source), or use **Mode C** (dev + Metro) so live edits show via Fast Refresh. The screenshot itself is fresh — it's the build that's stale. (`9:41` in the status bar is the sim default, not staleness.) |
|
|
40
|
+
| (argent) Every `argent run`/`tools` call returns `401 Unauthorized` right after linking | `argent link` without `--yes` no-ops on an already-linked URL ("Already linked. No changes."), keeping a stale token from a previous session | Re-link with `--yes` so the new token is written — see the link command in [controllers.md](./controllers.md). |
|
|
41
|
+
|
|
42
|
+
## Performance expectations
|
|
43
|
+
|
|
44
|
+
Set the user's expectations honestly — this is experimental:
|
|
45
|
+
- **Boot is variable**: ~90s warm to ~15 min cold. Poll patiently.
|
|
46
|
+
- **`snapshot` can be slow** on iOS (tens of seconds).
|
|
47
|
+
- **First bundle load** over the tunnel (Mode C) is the slow part; subsequent Fast Refreshes are fast.
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Curated upstream guidance for Eas Workflows; use when the workflow matches the user goal.
|
|
3
|
+
name: eas-workflows
|
|
4
|
+
allowed-tools: "Read,Write,Bash(node:*),Bash(npx *eas-cli@*) version: 1.0.0 license: MIT License"
|
|
5
|
+
|
|
6
|
+
source_repo: expo/skills
|
|
7
|
+
source_type: official
|
|
8
|
+
source: expo
|
|
9
|
+
date_added: '2026-09-21'
|
|
10
|
+
risk: unknown
|
|
11
|
+
---
|
|
12
|
+
## When to Use
|
|
13
|
+
- Use when this upstream workflow matches the user's stated goal.
|
|
14
|
+
- Use when the task requires the procedures documented in this skill.
|
|
15
|
+
|
|
16
|
+
# EAS Workflows Skill
|
|
17
|
+
|
|
18
|
+
> **EAS service - costs apply.** EAS Workflows run on Expo Application Services, a paid product with free-tier limits. Each workflow job consumes your plan's build/compute minutes, and jobs that build or submit also need paid Apple Developer and Google Play accounts. Review https://expo.dev/pricing before triggering runs.
|
|
19
|
+
|
|
20
|
+
Help developers write and edit EAS CI/CD workflow YAML files.
|
|
21
|
+
|
|
22
|
+
## Reference Documentation
|
|
23
|
+
|
|
24
|
+
Fetch these resources before generating or editing workflow files, or when answering syntax questions. First resolve this skill's directory, then use the fetch script in its `scripts/` directory. It is implemented using Node.js and caches responses using ETags for efficiency:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# Fetch resources
|
|
28
|
+
node <skill-dir>/scripts/fetch.js <url>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
1. **JSON Schema** — https://api.expo.dev/v2/workflows/schema
|
|
32
|
+
- It is NECESSARY to fetch this schema
|
|
33
|
+
- Source of truth for the workflow YAML structure; EAS CLI remains the authoritative final validator
|
|
34
|
+
- All job types and their required/optional parameters
|
|
35
|
+
- Trigger types and configurations
|
|
36
|
+
- Runner types, VM images, and all enums
|
|
37
|
+
|
|
38
|
+
2. **Syntax Documentation** — https://raw.githubusercontent.com/expo/expo/refs/heads/main/docs/pages/eas/workflows/syntax.mdx
|
|
39
|
+
- Overview of workflow YAML syntax
|
|
40
|
+
- Examples and English explanations
|
|
41
|
+
- Expression syntax and contexts
|
|
42
|
+
|
|
43
|
+
3. **Pre-packaged Jobs** — https://raw.githubusercontent.com/expo/expo/refs/heads/main/docs/pages/eas/workflows/pre-packaged-jobs.mdx
|
|
44
|
+
- Documentation for supported pre-packaged job types
|
|
45
|
+
- Job-specific parameters and outputs
|
|
46
|
+
|
|
47
|
+
Do not rely on memorized values; these resources evolve as new features are added.
|
|
48
|
+
|
|
49
|
+
## Workflow File Location
|
|
50
|
+
|
|
51
|
+
Workflows live in `.eas/workflows/*.yml` (or `.yaml`). Each file must be 16 KiB or smaller.
|
|
52
|
+
|
|
53
|
+
## Top-Level Structure
|
|
54
|
+
|
|
55
|
+
A workflow file has these top-level keys:
|
|
56
|
+
|
|
57
|
+
- `name` — Display name for the workflow
|
|
58
|
+
- `on` — Triggers that start the workflow (at least one required)
|
|
59
|
+
- `jobs` — Job definitions (required)
|
|
60
|
+
- `defaults` — Shared defaults for all jobs
|
|
61
|
+
- `concurrency` — Control parallel workflow runs
|
|
62
|
+
|
|
63
|
+
Consult the schema for the full specification of each section.
|
|
64
|
+
|
|
65
|
+
## Expressions
|
|
66
|
+
|
|
67
|
+
Use `${{ }}` syntax for dynamic values. The schema defines available contexts:
|
|
68
|
+
|
|
69
|
+
- `github.*` — GitHub repository and event information
|
|
70
|
+
- `inputs.*` — Values from `workflow_dispatch` inputs
|
|
71
|
+
- `needs.*` — Outputs and status from dependent jobs
|
|
72
|
+
- `jobs.*` — Job outputs (alternative syntax)
|
|
73
|
+
- `steps.*` — Step outputs within custom jobs
|
|
74
|
+
- `workflow.*` — Workflow metadata
|
|
75
|
+
|
|
76
|
+
## Generating Workflows
|
|
77
|
+
|
|
78
|
+
When generating or editing workflows:
|
|
79
|
+
|
|
80
|
+
1. Fetch the schema to get current job types, parameters, and allowed values
|
|
81
|
+
2. Validate that required fields are present for each job type
|
|
82
|
+
3. Verify job references in `needs` and `after` exist in the workflow
|
|
83
|
+
4. Check that expressions reference valid contexts and outputs
|
|
84
|
+
5. Ensure `if` conditions respect the schema's length constraints
|
|
85
|
+
|
|
86
|
+
## Validation
|
|
87
|
+
|
|
88
|
+
After generating or editing a workflow file, validate it with EAS CLI from the Expo project root:
|
|
89
|
+
|
|
90
|
+
```sh
|
|
91
|
+
npx -y eas-cli@latest workflow:validate .eas/workflows/<workflow.yml> --non-interactive
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Run the command separately for each changed workflow file. It requires a logged-in EAS CLI session and a linked Expo project. Unlike schema-only validation, it also checks build profile references against the project's `eas.json` and performs EAS server-side validation. Fix every reported error and rerun the command until it prints `Workflow configuration YAML is valid.` Do not replace this command with a local YAML or JSON Schema validator.
|
|
95
|
+
|
|
96
|
+
## Answering Questions
|
|
97
|
+
|
|
98
|
+
When users ask about available options (job types, triggers, runner types, etc.), fetch the schema and derive the answer from it rather than relying on potentially outdated information.
|
|
99
|
+
|
|
100
|
+
## Submitting Feedback
|
|
101
|
+
If you encounter errors, misleading or outdated information in this skill, report it so Expo can improve:
|
|
102
|
+
```bash
|
|
103
|
+
npx --yes submit-expo-feedback@latest --category skills --subject "eas-workflows" "<actionable feedback>"
|
|
104
|
+
```
|
|
105
|
+
Only submit when you have something specific and actionable to report. Include as much relevant context as possible.
|
|
106
|
+
If an AI agent repeatedly failed or the user had to take over an Expo task, load the expo-skill-feedback skill and follow its eval-candidate flow instead of reusing the command above.
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
## Examples
|
|
110
|
+
|
|
111
|
+
```text
|
|
112
|
+
User: Apply this skill to my current task.
|
|
113
|
+
Assistant: Follow the workflow in this skill, cite limitations, and ask before risky steps.
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Limitations
|
|
117
|
+
|
|
118
|
+
- Imported upstream skill; verify credentials, permissions, and safety boundaries before execution.
|
|
119
|
+
- Does not replace environment-specific validation, testing, or maintainer review.
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
interface:
|
|
2
|
+
display_name: "EAS Workflows"
|
|
3
|
+
short_description: "Paid EAS service. Write and validate EAS workflow YAML files for Expo projects"
|
|
4
|
+
default_prompt: "Use $eas-workflows when creating or editing .eas/workflows YAML, validating EAS workflow configuration, or answering questions about workflow triggers, jobs, runners, and expressions."
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { createHash } from 'node:crypto';
|
|
4
|
+
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
5
|
+
import { resolve } from 'node:path';
|
|
6
|
+
import process from 'node:process';
|
|
7
|
+
|
|
8
|
+
const CACHE_DIRECTORY = resolve(import.meta.dirname, '.cache');
|
|
9
|
+
const DEFAULT_TTL_SECONDS = 15 * 60; // 15 minutes
|
|
10
|
+
|
|
11
|
+
export async function fetchCached(url) {
|
|
12
|
+
await mkdir(CACHE_DIRECTORY, { recursive: true });
|
|
13
|
+
|
|
14
|
+
const cacheFile = resolve(CACHE_DIRECTORY, hashUrl(url) + '.json');
|
|
15
|
+
const cached = await loadCacheEntry(cacheFile);
|
|
16
|
+
if (cached && cached.expires > Math.floor(Date.now() / 1000)) {
|
|
17
|
+
return cached.data;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Make request, with conditional If-None-Match if we have an ETag.
|
|
21
|
+
// Cache-Control: max-age=0 overrides Node's default 'no-cache' to allow 304 responses.
|
|
22
|
+
const response = await fetch(url, {
|
|
23
|
+
headers: {
|
|
24
|
+
'Cache-Control': 'max-age=0',
|
|
25
|
+
...(cached?.etag && { 'If-None-Match': cached.etag }),
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
if (response.status === 304 && cached) {
|
|
30
|
+
// Refresh expiration and return cached data
|
|
31
|
+
const entry = { ...cached, expires: getExpires(response.headers) };
|
|
32
|
+
await saveCacheEntry(cacheFile, entry);
|
|
33
|
+
return cached.data;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (!response.ok) {
|
|
37
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const etag = response.headers.get('etag');
|
|
41
|
+
const data = await response.text();
|
|
42
|
+
const expires = getExpires(response.headers);
|
|
43
|
+
|
|
44
|
+
await saveCacheEntry(cacheFile, { url, etag, expires, data });
|
|
45
|
+
|
|
46
|
+
return data;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function hashUrl(url) {
|
|
50
|
+
return createHash('sha256').update(url).digest('hex').slice(0, 16);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function loadCacheEntry(cacheFile) {
|
|
54
|
+
try {
|
|
55
|
+
return JSON.parse(await readFile(cacheFile, 'utf-8'));
|
|
56
|
+
} catch {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async function saveCacheEntry(cacheFile, entry) {
|
|
62
|
+
await writeFile(cacheFile, JSON.stringify(entry, null, 2));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function getExpires(headers) {
|
|
66
|
+
const now = Math.floor(Date.now() / 1000);
|
|
67
|
+
|
|
68
|
+
// Prefer Cache-Control: max-age
|
|
69
|
+
const maxAgeSeconds = parseMaxAge(headers.get('cache-control'));
|
|
70
|
+
if (maxAgeSeconds != null) {
|
|
71
|
+
return now + maxAgeSeconds;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Fall back to Expires header
|
|
75
|
+
const expires = headers.get('expires');
|
|
76
|
+
if (expires) {
|
|
77
|
+
const expiresTime = Date.parse(expires);
|
|
78
|
+
if (!Number.isNaN(expiresTime)) {
|
|
79
|
+
return Math.floor(expiresTime / 1000);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Default TTL
|
|
84
|
+
return now + DEFAULT_TTL_SECONDS;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function parseMaxAge(cacheControl) {
|
|
88
|
+
if (!cacheControl) {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
const match = cacheControl.match(/max-age=(\d+)/i);
|
|
92
|
+
return match ? parseInt(match[1], 10) : null;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (import.meta.main) {
|
|
96
|
+
const url = process.argv[2];
|
|
97
|
+
|
|
98
|
+
if (!url || url === '--help' || url === '-h') {
|
|
99
|
+
console.log(`Usage: fetch <url>
|
|
100
|
+
|
|
101
|
+
Fetches a URL with HTTP caching (ETags + Cache-Control/Expires).
|
|
102
|
+
Default TTL: ${DEFAULT_TTL_SECONDS / 60} minutes.
|
|
103
|
+
Cache is stored in: ${CACHE_DIRECTORY}/`);
|
|
104
|
+
process.exit(url ? 0 : 1);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const data = await fetchCached(url);
|
|
108
|
+
console.log(data);
|
|
109
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Emil Kowalski
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|