Skip to content

[eas-cli] add eas simulator:start command#3625

Merged
szdziedzic merged 1 commit intomainfrom
04-23-_eas-cli_add_eas_simulator_start_command
Apr 23, 2026
Merged

[eas-cli] add eas simulator:start command#3625
szdziedzic merged 1 commit intomainfrom
04-23-_eas-cli_add_eas_simulator_start_command

Conversation

@szdziedzic
Copy link
Copy Markdown
Contributor

@szdziedzic szdziedzic commented Apr 23, 2026

Why

Part of ENG-20714

Add hidden and experimental eas simulator:start command that starts remote agent device session on EAS server and outputs exportend env vars that allow to connect with it.

How

Use createDeviceSessionRun to start the session. Wait until our job run outputs the exports in the logs and forward them to the user. This is quite hacky but good for v-1 so we can start playing with it now internally.

Test Plan

Test manually

Copy link
Copy Markdown
Contributor Author

szdziedzic commented Apr 23, 2026

This stack of pull requests is managed by Graphite. Learn more about stacking.

@linear
Copy link
Copy Markdown

linear Bot commented Apr 23, 2026

@szdziedzic szdziedzic added the no changelog PR that doesn't require a changelog entry label Apr 23, 2026 — with Graphite App
@szdziedzic szdziedzic force-pushed the 04-23-_eas-cli_add_eas_simulator_start_command branch from ed5e0bd to b188388 Compare April 23, 2026 13:52
@szdziedzic szdziedzic requested review from Copilot and sjchmiela April 23, 2026 13:53
@szdziedzic szdziedzic marked this pull request as ready for review April 23, 2026 13:53
@github-actions
Copy link
Copy Markdown

Subscribed to pull request

File Patterns Mentions
**/* @douglowder
packages/eas-cli/src/build/** @sjchmiela

Generated by CodeMention

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an (hidden) experimental eas simulator:start command to create a remote device run session on EAS, poll the job run logs until connection env vars appear, and present connection details to the user.

Changes:

  • Add GraphQL mutation/query wrappers for creating and fetching DeviceRunSession + regenerate GraphQL types/schema.
  • Introduce eas simulator:start command with polling + log parsing to extract exported env vars.
  • Add getJobRunUrl helper for linking to job runs in the Expo website UI.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
packages/eas-cli/src/graphql/queries/DeviceRunSessionQuery.ts Adds query for fetching a device run session (including turtle job run status/log URLs).
packages/eas-cli/src/graphql/mutations/DeviceRunSessionMutation.ts Adds mutation for creating a device run session.
packages/eas-cli/src/graphql/generated.ts Regenerates GraphQL types to include device run session schema additions.
packages/eas-cli/src/commands/simulator/start.ts New experimental command implementing session creation, polling, and log parsing to surface env vars.
packages/eas-cli/src/build/utils/url.ts Adds getJobRunUrl for deep-linking to job run pages.
packages/eas-cli/graphql.schema.json Updates schema introspection to include new server fields/types.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/eas-cli/src/commands/simulator/start.ts
Comment thread packages/eas-cli/src/commands/simulator/start.ts
Comment thread packages/eas-cli/src/commands/simulator/start.ts Outdated
Comment on lines +154 to +158
if (!baseUrl || !authToken) {
pollSpinner.fail(`Timed out waiting for ${flags.type} daemon to start`);
throw new Error(
`Timed out after ${Math.round(
POLL_TIMEOUT_MS / 1000
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On timeout/failure this command throws without attempting to stop the created device run session, which may leave a remote session running and consuming resources. Consider a best-effort cleanup (e.g. call the stopDeviceRunSession mutation in a finally/error path, or at least print the session id with guidance on how to stop it).

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will do it as follow up

Comment thread packages/eas-cli/src/commands/simulator/start.ts
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 23, 2026

Codecov Report

❌ Patch coverage is 22.76423% with 190 lines in your changes missing coverage. Please review.
✅ Project coverage is 55.48%. Comparing base (900ad76) to head (e7fc28b).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
packages/eas-cli/src/commands/simulator/start.ts 19.17% 97 Missing ⚠️
...c/steps/functions/startAgentDeviceRemoteSession.ts 16.67% 85 Missing ⚠️
.../src/graphql/mutations/DeviceRunSessionMutation.ts 50.00% 3 Missing ⚠️
...s-cli/src/graphql/queries/DeviceRunSessionQuery.ts 50.00% 3 Missing ⚠️
packages/eas-cli/src/build/utils/url.ts 33.34% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3625      +/-   ##
==========================================
- Coverage   55.70%   55.48%   -0.22%     
==========================================
  Files         852      856       +4     
  Lines       36549    36795     +246     
  Branches     7642     7645       +3     
==========================================
+ Hits        20356    20412      +56     
- Misses      14774    16288    +1514     
+ Partials     1419       95    -1324     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@szdziedzic szdziedzic force-pushed the 04-23-_eas-cli_add_eas_simulator_start_command branch from b188388 to e6ad3f5 Compare April 23, 2026 14:15
Comment thread packages/eas-cli/src/build/utils/url.ts Outdated
).toString();
}

export function getJobRunUrl(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
export function getJobRunUrl(
export function getBareJobRunUrl(

I remember whipping up that page as a temporary measure before adding we had workflow run page. Maybe this will make it clear it's not to be used in general (especially not if workflow run is available)? Or maybe we want to mark it as deprecated?

Comment on lines +24 to +26
function toTypeFlagValue(type: DeviceRunSessionType): string {
return type.toLowerCase().replaceAll('_', '-');
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use a Record<DeviceRunSessionType, string> instead? Or Record<string, DeviceRunSessionType>, whatever makes sense.

export default class SimulatorStart extends EasCommand {
static override hidden = true;
static override description =
'[EXPERIMENTAL] start a remote simulator session on an EAS VM and get the credentials to connect to it with the CLI tool of your choice';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
'[EXPERIMENTAL] start a remote simulator session on an EAS VM and get the credentials to connect to it with the CLI tool of your choice';
'[EXPERIMENTAL] start a remote simulator session on EAS and get the credentials to connect to it with the CLI tool of your choice';


static override flags = {
platform: Flags.option({
description: 'Platform to start the simulator session for',
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
description: 'Platform to start the simulator session for',
description: 'Device platform',

?

platform: Flags.option({
description: 'Platform to start the simulator session for',
options: ['android', 'ios'] as const,
default: 'ios',
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
default: 'ios',

hmmmm not sure

jobRunStatus === JobRunStatus.Finished
) {
throw new Error(
`Turtle job run for device run session ${deviceRunSessionId} is ${jobRunStatus.toLowerCase()} before the ${flags.type} daemon was ready.`
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
`Turtle job run for device run session ${deviceRunSessionId} is ${jobRunStatus.toLowerCase()} before the ${flags.type} daemon was ready.`
`Turtle job run for device run session ${deviceRunSessionId} ${jobRunStatus.toLowerCase()} before the ${flags.type} daemon was ready.`

Comment on lines +21 to +22
const BASE_URL_ENV_VAR = 'AGENT_DEVICE_DAEMON_BASE_URL';
const AUTH_TOKEN_ENV_VAR = 'AGENT_DEVICE_DAEMON_AUTH_TOKEN';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It feels like in this file we mix being ready to support multiple backends (extractor for type) and hardcoding agent-device (these consts).

Maybe it would be simpler if the extractor was returning { ready, message } and if ready we stop polling and print message? Then all agent-device, agent-simulator-specific config would be inside that one function?

): Promise<{ baseUrl?: string; authToken?: string }> {
let text: string;
try {
const response = await fetch(url);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

until we move to the nicer way of providing these which we discussed in slack I think fetching and parsing logs is going to be common for all backends so we might want to do it before extraction

}

Log.newLine();
Log.log(`🔑 Run the following in your shell to attach the ${flags.type} to the EAS VM:`);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Log.log(`🔑 Run the following in your shell to attach the ${flags.type} to the EAS VM:`);
Log.log(`🔑 Run the following in your shell to attach to ${flags.type}:`);

return line;
}

function extractExportedEnvValue(text: string, varName: string): string | undefined {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i wonder if we shouldn't parse this in the eas function…

@szdziedzic szdziedzic force-pushed the 04-23-_eas-cli_add_eas_simulator_start_command branch 3 times, most recently from 6e20797 to d07eb7f Compare April 23, 2026 14:58
@szdziedzic szdziedzic requested a review from sjchmiela April 23, 2026 15:13
@szdziedzic szdziedzic force-pushed the 04-23-_eas-cli_add_eas_simulator_start_command branch 2 times, most recently from 9a5e1dc to ebbe177 Compare April 23, 2026 15:44
await cloneAgentDeviceAsync({ packageVersion, env, logger });

logger.info('Installing agent-device dependencies.');
await spawn('npm', ['install', '--omit=dev', '--no-audit', '--no-fund'], {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we try using bun as package manager and runner? Might be faster?

await fs.promises.mkdir(RUN_DIR, { recursive: true });

logger.info('Ensuring cloudflared is installed.');
await ensureCloudflaredInstalledAsync({ env, logger });
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it would be nicer to have had these as separate EAS functions (for this to be a function group) but for v-1 it's ok i guess

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will come back to it in follow up

child.unref();
logger.info(`Started detached process (pid ${child.pid}).`);
} finally {
fs.closeSync(fd);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I presume closing this does not prevent the command from writing to this file?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

});

logger.info('Waiting for the daemon to report its HTTP port.');
const daemonPort = await waitForMatchInLogAsync({
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think port is gettable from the file too

@szdziedzic szdziedzic force-pushed the 04-23-_eas-cli_add_eas_simulator_start_command branch from ebbe177 to e7fc28b Compare April 23, 2026 15:52
@github-actions
Copy link
Copy Markdown

⏩ The changelog entry check has been skipped since the "no changelog" label is present.

@szdziedzic szdziedzic enabled auto-merge (squash) April 23, 2026 15:54
@szdziedzic szdziedzic merged commit bec6e67 into main Apr 23, 2026
7 checks passed
@szdziedzic szdziedzic deleted the 04-23-_eas-cli_add_eas_simulator_start_command branch April 23, 2026 15:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no changelog PR that doesn't require a changelog entry

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants