mirror of
https://github.com/callstack/agent-device.git
synced 2026-09-14 20:06:34 +08:00
598 lines
164 KiB
HTML
598 lines
164 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head><meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>Node.js API - agent-device</title>
|
|
<script>{;const saved = localStorage.getItem('rspress-theme-appearance');const preferDark = window.matchMedia('(prefers-color-scheme: dark)').matches;const isDark = !saved || saved === 'auto' ? preferDark : saved === 'dark';document.documentElement.classList.toggle('dark', isDark);document.documentElement.classList.toggle('rp-dark', isDark);document.documentElement.style.colorScheme = isDark ? 'dark' : 'light';}</script>
|
|
<link href="/agent-device/static/css/styles.cf5e9ab9a4.css" rel="stylesheet">
|
|
<script defer src="/agent-device/static/js/styles.308ea4bafe.js"></script>
|
|
<script defer src="/agent-device/static/js/lib-react.e84adf13b9.js"></script>
|
|
<script defer src="/agent-device/static/js/lib-router.270f17bfa6.js"></script>
|
|
<script defer src="/agent-device/static/js/476.52ed165336.js"></script>
|
|
<script defer src="/agent-device/static/js/index.8722046b0d.js"></script>
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
<meta name="generator" content="Rspress v2.0.12">
|
|
<meta property="og:url" content="https://oss.callstack.com/agent-device">
|
|
<meta property="og:type" content="website">
|
|
<meta property="og:title" content="Node.js API - agent-device">
|
|
<meta property="og:image" content="https://oss.callstack.com/agent-device/og-image.jpg">
|
|
<meta property="og:description" content="Use createAgentDeviceClient() for typed, deterministic device automation from Node.js instead of shelling out to the CLI. Building an agent? Start with the dedicated AI SDK or Eve integration.">
|
|
<link rel="icon" href="/agent-device/logo.svg" type="image/svg+xml">
|
|
<meta name="description" content="Use createAgentDeviceClient() for typed, deterministic device automation from Node.js instead of shelling out to the CLI. Building an agent? Start with the dedicated AI SDK or Eve integration."></head>
|
|
|
|
<body>
|
|
<div id="__rspress_root"><link rel="preload" as="image" href="/agent-device/logo-light.svg"/><link rel="preload" as="image" href="/agent-device/logo-dark.svg"/><link rel="preload" as="image" href="/agent-device/static/image/abstract-atom.4eca0300ff.avif"/><header class="rp-nav"><div class="rp-nav__left"><div class="rp-nav__title"><a href="/agent-device/" class="rp-nav__title__link rp-link"><div class="rp-nav__title__logo"><img src="/agent-device/logo-light.svg" alt="logo" id="logo" class="rspress-logo rp-nav__title__logo-image rp-nav__title__logo-image--light"/><img src="/agent-device/logo-dark.svg" alt="logo" id="logo" class="rspress-logo rp-nav__title__logo-image rp-nav__title__logo-image--dark"/></div></a></div></div><div class="rp-nav__right"><button class="rp-search-button"><div class="rp-search-button__content"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16" class="rp-search-button__icon"><path fill="#838289" d="M14.667 14.666h-1.333v-1.333h1.332zm-1.333-1.333H12V12h1.333zm-4-1.333H4v-1.334h5.334zM12 12h-1.335v-1.334h1.335zm-8-1.334H2.665V9.333H4zm6.665 0H9.334V9.333h1.332zm-8-1.333H1.335V4h1.333zm9.335 0h-1.335V4h1.335zM4 4H2.665V2.666H4zm6.665 0H9.334V2.666h1.332zM9.334 2.666H4V1.333h5.334z"></path></svg><span class="rp-search-button__word">Search</span></div><div class="rp-search-button__hotkey" style="opacity:0"><span></span><span>K</span></div></button><div class="rp-search-button--mobile"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16"><path fill="#838289" d="M14.667 14.666h-1.333v-1.333h1.332zm-1.333-1.333H12V12h1.333zm-4-1.333H4v-1.334h5.334zM12 12h-1.335v-1.334h1.335zm-8-1.334H2.665V9.333H4zm6.665 0H9.334V9.333h1.332zm-8-1.333H1.335V4h1.333zm9.335 0h-1.335V4h1.335zM4 4H2.665V2.666H4zm6.665 0H9.334V2.666h1.332zM9.334 2.666H4V1.333h5.334z"></path></svg></div><ul class="rp-nav-menu rp-nav-menu--right"><li class="rp-nav-menu__item"><a href="/agent-device/docs/introduction" class="rp-nav-menu__item__container rp-link">Docs</a></li></ul><div class="rp-nav__others"><div class="rp-nav-menu__divider"></div><div role="button" tabindex="0" class="rspress-nav-appearance"><div class="rp-p-1 rp-border rp-border-solid rp-border-gray-300 rp-text-gray-400 rp-cursor-pointer rp-rounded-md rp-transition-all rp-duration-300 rp-w-7 rp-h-7"><svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="currentColor" viewBox="0 0 24 24"><path fill="currentColor" d="M18 22H8v-2h10zM8 20H6v-2h2zm12 0h-2v-2h2zM6 18H4v-2h2zm16 0h-2v-4h-2v-2h2v-2h2zM4 16H2V6h2zm14 0h-6v-2h6zm-6-2h-2v-2h2zm-2-2H8V6h2zM6 6H4V4h2zm8-2h-2v2h-2V4H6V2h8z"></path></svg></div></div><div class="rp-social-links"><a href="https://github.com/callstack/agent-device" target="_blank" rel="noopener noreferrer" class="rp-social-links__item"><div class="rp-social-links__icon"><div class="rp-social-links__icon"><svg xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 24 24"><path fill="currentColor" d="M12 .297c-6.63 0-12 5.373-12 12c0 5.303 3.438 9.8 8.205 11.385c.6.113.82-.258.82-.577c0-.285-.01-1.04-.015-2.04c-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729c1.205.084 1.838 1.236 1.838 1.236c1.07 1.835 2.809 1.305 3.495.998c.108-.776.417-1.305.76-1.605c-2.665-.3-5.466-1.332-5.466-5.93c0-1.31.465-2.38 1.235-3.22c-.135-.303-.54-1.523.105-3.176c0 0 1.005-.322 3.3 1.23c.96-.267 1.98-.399 3-.405c1.02.006 2.04.138 3 .405c2.28-1.552 3.285-1.23 3.285-1.23c.645 1.653.24 2.873.12 3.176c.765.84 1.23 1.91 1.23 3.22c0 4.61-2.805 5.625-5.475 5.92c.42.36.81 1.096.81 2.22c0 1.606-.015 2.896-.015 3.286c0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></div></div></a><a href="https://discord.gg/eYapw6F3" target="_blank" rel="noopener noreferrer" class="rp-social-links__item"><div class="rp-social-links__icon"><div class="rp-social-links__icon"><svg xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 24 24"><path fill="currentColor" d="M20.317 4.37a19.8 19.8 0 0 0-4.885-1.515a.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.3 18.3 0 0 0-5.487 0a13 13 0 0 0-.617-1.25a.08.08 0 0 0-.079-.037A19.7 19.7 0 0 0 3.677 4.37a.1.1 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.08.08 0 0 0 .031.057a19.9 19.9 0 0 0 5.993 3.03a.08.08 0 0 0 .084-.028a14 14 0 0 0 1.226-1.994a.076.076 0 0 0-.041-.106a13 13 0 0 1-1.872-.892a.077.077 0 0 1-.008-.128a10 10 0 0 0 .372-.292a.07.07 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.07.07 0 0 1 .078.01q.181.149.373.292a.077.077 0 0 1-.006.127a12.3 12.3 0 0 1-1.873.892a.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.08.08 0 0 0 .084.028a19.8 19.8 0 0 0 6.002-3.03a.08.08 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.06.06 0 0 0-.031-.03M8.02 15.33c-1.182 0-2.157-1.085-2.157-2.419c0-1.333.956-2.419 2.157-2.419c1.21 0 2.176 1.096 2.157 2.42c0 1.333-.956 2.418-2.157 2.418m7.975 0c-1.183 0-2.157-1.085-2.157-2.419c0-1.333.955-2.419 2.157-2.419c1.21 0 2.176 1.096 2.157 2.42c0 1.333-.946 2.418-2.157 2.418"/></svg></div></div></a><ul class="rp-hover-group rp-hover-group--hidden rp-hover-group--right"></ul></div></div><button aria-label="mobile hamburger" class="rp-nav-hamburger rp-nav-hamburger__sm"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path fill="#838289" fill-rule="evenodd" d="M1 9h6v6H1zm2 2v2h2v-2zm6-2h6v6H9zm2 2v2h2v-2zm6-2h6v6h-6zm2 2v2h2v-2z" clip-rule="evenodd"></path></svg></button><button aria-label="mobile hamburger" class="rp-nav-hamburger rp-nav-hamburger__md"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path fill="#838289" fill-rule="evenodd" d="M1 9h6v6H1zm2 2v2h2v-2zm6-2h6v6H9zm2 2v2h2v-2zm6-2h6v6h-6zm2 2v2h2v-2z" clip-rule="evenodd"></path></svg><ul class="rp-hover-group rp-hover-group--hidden rp-hover-group--right"><div class="rp-nav-menu__others-mobile__container"><div class="rp-nav-hamburger__md__hover-group"><div class="rp-nav-screen-appearance"><div class="rp-nav-screen-appearance__left">Theme</div><div class="rp-nav-screen-appearance__right"></div></div><div class="rp-nav-screen-divider"></div><div class="rp-social-links"><a href="https://github.com/callstack/agent-device" target="_blank" rel="noopener noreferrer" class="rp-social-links__item"><div class="rp-social-links__icon"><div class="rp-social-links__icon"><svg xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 24 24"><path fill="currentColor" d="M12 .297c-6.63 0-12 5.373-12 12c0 5.303 3.438 9.8 8.205 11.385c.6.113.82-.258.82-.577c0-.285-.01-1.04-.015-2.04c-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729c1.205.084 1.838 1.236 1.838 1.236c1.07 1.835 2.809 1.305 3.495.998c.108-.776.417-1.305.76-1.605c-2.665-.3-5.466-1.332-5.466-5.93c0-1.31.465-2.38 1.235-3.22c-.135-.303-.54-1.523.105-3.176c0 0 1.005-.322 3.3 1.23c.96-.267 1.98-.399 3-.405c1.02.006 2.04.138 3 .405c2.28-1.552 3.285-1.23 3.285-1.23c.645 1.653.24 2.873.12 3.176c.765.84 1.23 1.91 1.23 3.22c0 4.61-2.805 5.625-5.475 5.92c.42.36.81 1.096.81 2.22c0 1.606-.015 2.896-.015 3.286c0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></div></div></a><a href="https://discord.gg/eYapw6F3" target="_blank" rel="noopener noreferrer" class="rp-social-links__item"><div class="rp-social-links__icon"><div class="rp-social-links__icon"><svg xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 24 24"><path fill="currentColor" d="M20.317 4.37a19.8 19.8 0 0 0-4.885-1.515a.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.3 18.3 0 0 0-5.487 0a13 13 0 0 0-.617-1.25a.08.08 0 0 0-.079-.037A19.7 19.7 0 0 0 3.677 4.37a.1.1 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.08.08 0 0 0 .031.057a19.9 19.9 0 0 0 5.993 3.03a.08.08 0 0 0 .084-.028a14 14 0 0 0 1.226-1.994a.076.076 0 0 0-.041-.106a13 13 0 0 1-1.872-.892a.077.077 0 0 1-.008-.128a10 10 0 0 0 .372-.292a.07.07 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.07.07 0 0 1 .078.01q.181.149.373.292a.077.077 0 0 1-.006.127a12.3 12.3 0 0 1-1.873.892a.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.08.08 0 0 0 .084.028a19.8 19.8 0 0 0 6.002-3.03a.08.08 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.06.06 0 0 0-.031-.03M8.02 15.33c-1.182 0-2.157-1.085-2.157-2.419c0-1.333.956-2.419 2.157-2.419c1.21 0 2.176 1.096 2.157 2.42c0 1.333-.956 2.418-2.157 2.418m7.975 0c-1.183 0-2.157-1.085-2.157-2.419c0-1.333.955-2.419 2.157-2.419c1.21 0 2.176 1.096 2.157 2.42c0 1.333-.946 2.418-2.157 2.418"/></svg></div></div></a><ul class="rp-hover-group rp-hover-group--hidden rp-hover-group--right"></ul></div></div></div></ul></button></div></header><div class="rp-doc-layout__menu"><div class="rp-sidebar-menu"><button type="button" class="rp-sidebar-menu__left"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path fill="#838289" d="M20 18H4v-2h16zm0-5H4v-2h16zm0-5H4V6h16z"></path></svg><span>Menu</span></button><button type="button" class="rp-sidebar-menu__right"><span class="rp-sidebar-menu__right__text">Contents</span><svg width="14" height="14" class="rp-progress-circle"><circle cx="7" cy="7" r="6" stroke-linecap="round" fill="none" stroke="var(--rp-c-divider-light)" stroke-width="2"></circle><circle cx="7" cy="7" r="6" stroke-linecap="round" fill="none" stroke="var(--rp-c-brand)" stroke-width="2" stroke-dasharray="37.69911184307752" stroke-dashoffset="37.69911184307752" transform="rotate(-90 7 7)" style="transition:stroke-dashoffset 0.3s"></circle></svg><svg xmlns="http://www.w3.org/2000/svg" width="12" height="13" fill="none" viewBox="0 0 12 13" class="rp-sidebar-menu__right__icon" style="transform:rotate(0deg);transition:transform 0.2s ease-out"><path fill="#BCBBC2" d="M6.5 4.5h1v-1h-1v-1h-1v1h-1v1h1v6h1zm-2 0h-1v1h1zm4 0h-1v1h1zm-5 2v-1h-1v1zm6-1h-1v1h1z"></path></svg></button></div></div><div class="rp-doc-layout__container"><aside class="rp-doc-layout__sidebar rp-scrollbar"><div class="rp-sidebar-item rp-sidebar-group" style="padding-left:12px" data-depth="0"><div class="rp-sidebar-item__left"><span class="rp-doc">Getting Started</span></div><div class="rp-sidebar-item__right"></div></div><div style="display:grid;grid-template-rows:1fr;transition:grid-template-rows 0.2s ease-out"><div style="overflow:hidden"><a href="/agent-device/docs/introduction" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">Introduction</span></div><div class="rp-sidebar-item__right"></div></a><a href="/agent-device/docs/installation" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">Installation</span></div><div class="rp-sidebar-item__right"></div></a><a href="/agent-device/docs/agent-setup" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">AI Agent Setup</span></div><div class="rp-sidebar-item__right"></div></a><a href="/agent-device/docs/quick-start" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">Quick Start</span></div><div class="rp-sidebar-item__right"></div></a></div></div><div class="rp-sidebar-item rp-sidebar-group" style="padding-left:12px" data-depth="0"><div class="rp-sidebar-item__left"><span class="rp-doc">Using agent-device</span></div><div class="rp-sidebar-item__right"></div></div><div style="display:grid;grid-template-rows:1fr;transition:grid-template-rows 0.2s ease-out"><div style="overflow:hidden"><a href="/agent-device/docs/commands" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">Commands</span></div><div class="rp-sidebar-item__right"></div></a><a href="/agent-device/docs/configuration" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">Configuration</span></div><div class="rp-sidebar-item__right"></div></a><a href="/agent-device/docs/selectors" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">Selectors</span></div><div class="rp-sidebar-item__right"></div></a><a href="/agent-device/docs/sessions" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">Sessions</span></div><div class="rp-sidebar-item__right"></div></a><a href="/agent-device/docs/batching" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">Batching</span></div><div class="rp-sidebar-item__right"></div></a><a href="/agent-device/docs/snapshots" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">Snapshots</span></div><div class="rp-sidebar-item__right"></div></a><a href="/agent-device/docs/replay-e2e" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">Replay & E2E testing</span></div><div class="rp-sidebar-item__right"></div></a><a href="/agent-device/docs/debugging-profiling" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">Debugging & Profiling</span></div><div class="rp-sidebar-item__right"></div></a></div></div><div class="rp-sidebar-item rp-sidebar-group" style="padding-left:12px" data-depth="0"><div class="rp-sidebar-item__left"><span class="rp-doc">Integrations</span></div><div class="rp-sidebar-item__right"></div></div><div style="display:grid;grid-template-rows:1fr;transition:grid-template-rows 0.2s ease-out"><div style="overflow:hidden"><a href="/agent-device/docs/client-api" class="rp-sidebar-item rp-sidebar-item--active rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">Node.js API</span></div><div class="rp-sidebar-item__right"></div></a><a href="/agent-device/docs/ai-sdk" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">AI SDK</span></div><div class="rp-sidebar-item__right"></div></a><a href="/agent-device/docs/eve" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">Eve</span></div><div class="rp-sidebar-item__right"></div></a><a href="/agent-device/docs/remote-proxy" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">Remote Proxy</span></div><div class="rp-sidebar-item__right"></div></a><a href="/agent-device/docs/device-clouds" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">Device Clouds</span></div><div class="rp-sidebar-item__right"></div></a><a href="/agent-device/docs/browserstack" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">BrowserStack</span></div><div class="rp-sidebar-item__right"></div></a><a href="/agent-device/docs/aws-device-farm" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">AWS Device Farm</span></div><div class="rp-sidebar-item__right"></div></a><a href="/agent-device/docs/limrun" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">Limrun</span></div><div class="rp-sidebar-item__right"></div></a></div></div><div class="rp-sidebar-item rp-sidebar-group" style="padding-left:12px" data-depth="0"><div class="rp-sidebar-item__left"><span class="rp-doc">Reference</span></div><div class="rp-sidebar-item__right"></div></div><div style="display:grid;grid-template-rows:1fr;transition:grid-template-rows 0.2s ease-out"><div style="overflow:hidden"><a href="/agent-device/docs/security-trust" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">Security & Trust</span></div><div class="rp-sidebar-item__right"></div></a><a href="/agent-device/docs/known-limitations" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">Known Limitations</span></div><div class="rp-sidebar-item__right"></div></a><a href="/agent-device/docs/migrating-gestures" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">Migrating Gestures</span></div><div class="rp-sidebar-item__right"></div></a></div></div></aside><div class="rp-doc-layout__doc"><main class="rp-doc-layout__doc-container"><div class="rp-doc rspress-doc"><!--$--><h1 class="rp-toc-include" id="nodejs-api"><a href="#nodejs-api" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Node.js API<!-- --> </h1><div class="rp-not-doc rp-llms-container"><button class="rp-not-doc rp-llms-button rp-llms-copy-button"><div class="rp-llms-copy-button__icon-wrapper"><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-llms-copy-button__icon-success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-llms-copy-button__icon-copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg></div><span>Copy Markdown</span></button><button class="rp-llms-button rp-llms-view-options__trigger "><svg xmlns="http://www.w3.org/2000/svg" width="12" height="13" viewBox="0 0 12 13" class="rp-llms-view-options__arrow "><path fill="currentColor" d="M6.5 8.5h1v1h-1v1h-1v-1h-1v-1h1v-6h1zm-2 0h-1v-1h1zm4 0h-1v-1h1zm-5-2v1h-1v-1zm6 1h-1v-1h1z"></path></svg></button></div>
|
|
<p>Use <code>createAgentDeviceClient()</code> for typed, deterministic device automation from Node.js instead of shelling out to the CLI.</p>
|
|
<p>Building an agent? Start with the dedicated <a href="/agent-device/docs/ai-sdk" class="rp-link">AI SDK</a> or <a href="/agent-device/docs/eve" class="rp-link">Eve</a> integration.</p>
|
|
<h2 class="rp-toc-include" id="runnable-examples"><a href="#runnable-examples" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Runnable examples</h2>
|
|
<p>The repository includes <a href="https://github.com/callstack/agent-device/tree/main/examples/sdk" target="_blank" rel="noopener noreferrer" class="rp-link">runnable, typechecked Node.js examples</a> that import the same published <code>agent-device/*</code> entry points used by consumers:</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<div class="rp-table-scroll-container rp-scrollbar"><table><thead><tr><th>Example</th><th>Demonstrates</th></tr></thead><tbody><tr><td><a href="https://github.com/callstack/agent-device/blob/main/examples/sdk/client-session.ts" target="_blank" rel="noopener noreferrer" class="rp-link"><code>client-session.ts</code></a></td><td>Open, snapshot, interact, handle typed errors, and always close the session</td></tr><tr><td><a href="https://github.com/callstack/agent-device/blob/main/examples/sdk/contracts-result.ts" target="_blank" rel="noopener noreferrer" class="rp-link"><code>contracts-result.ts</code></a></td><td>Consume snapshot results with helpers from <code>agent-device/contracts</code></td></tr><tr><td><a href="https://github.com/callstack/agent-device/blob/main/examples/sdk/batch-orchestration.ts" target="_blank" rel="noopener noreferrer" class="rp-link"><code>batch-orchestration.ts</code></a></td><td>Run a batch through a custom transport</td></tr><tr><td><a href="https://github.com/callstack/agent-device/blob/main/examples/sdk/metro-runtime.ts" target="_blank" rel="noopener noreferrer" class="rp-link"><code>metro-runtime.ts</code></a></td><td>Normalize a Metro URL and resolve runtime transport hints</td></tr></tbody></table></div>
|
|
<p>The examples are checked against the source SDK using their dedicated <a href="https://github.com/callstack/agent-device/blob/main/examples/sdk/tsconfig.json" target="_blank" rel="noopener noreferrer" class="rp-link"><code>tsconfig.json</code></a>. After building the package with <code>pnpm build</code>, run an example directly with Node:</p>
|
|
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">node</span><span style="color:var(--shiki-token-string)"> --experimental-strip-types</span><span style="color:var(--shiki-token-string)"> examples/sdk/client-session.ts</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
|
<h2 class="rp-toc-include" id="api-reference"><a href="#api-reference" class="rp-header-anchor rp-link" aria-hidden="true">#</a>API reference</h2>
|
|
<p>Supported public entry points for Node consumers:</p>
|
|
<ul>
|
|
<li><code>agent-device</code>
|
|
<ul>
|
|
<li><code>createAgentDeviceClient(options?)</code></li>
|
|
<li><code>createLocalArtifactAdapter(options?)</code></li>
|
|
<li><code>AppError</code>, <code>isAgentDeviceError(error)</code>, <code>normalizeAgentDeviceError(error)</code></li>
|
|
<li><code>centerOfRect(rect)</code></li>
|
|
</ul>
|
|
</li>
|
|
<li><code>agent-device/io</code>
|
|
<ul>
|
|
<li><code>createLocalArtifactAdapter(options?)</code></li>
|
|
<li>types: <code>ArtifactAdapter</code>, <code>ArtifactDescriptor</code>, <code>CreateTempFileOptions</code>, <code>FileInputRef</code>,
|
|
<code>FileOutputRef</code>, <code>LocalArtifactAdapterOptions</code>, <code>OutputVisibility</code>, <code>ReserveOutputOptions</code>,
|
|
<code>ReservedOutputFile</code>, <code>ResolveInputOptions</code>, <code>ResolvedInputFile</code>, <code>TemporaryFile</code></li>
|
|
</ul>
|
|
</li>
|
|
<li><code>agent-device/metro</code>
|
|
<ul>
|
|
<li><code>buildBundleUrl(baseUrl, platform)</code></li>
|
|
<li><code>normalizeBaseUrl(baseUrl)</code></li>
|
|
<li><code>resolveRuntimeTransport(runtime)</code></li>
|
|
<li><code>prepareMetroRuntime(options?)</code>, <code>reloadMetro(options?)</code>, <code>stopMetroTunnel(options)</code></li>
|
|
<li>types: <code>MetroBridgeDescriptor</code>, <code>MetroTunnelRequestMessage</code>, <code>MetroTunnelResponseMessage</code></li>
|
|
</ul>
|
|
</li>
|
|
<li><code>agent-device/batch</code>
|
|
<ul>
|
|
<li><code>runBatch(req, sessionName, invoke)</code></li>
|
|
</ul>
|
|
</li>
|
|
<li><code>agent-device/remote-config</code>
|
|
<ul>
|
|
<li><code>resolveRemoteConfigProfile(options)</code></li>
|
|
<li>types: <code>RemoteConfigProfile</code></li>
|
|
</ul>
|
|
</li>
|
|
<li><code>agent-device/contracts</code>
|
|
<ul>
|
|
<li><code>centerOfRect(rect)</code></li>
|
|
<li><code>defaultHintForCode(code)</code>, <code>normalizeError(error)</code></li>
|
|
<li>types: <code>DaemonError</code>, <code>DaemonInstallSource</code>, <code>DaemonRequest</code>, <code>DaemonResponse</code>, <code>DaemonResponseData</code>, <code>JsonRpcId</code>, <code>JsonRpcRequestEnvelope</code>, <code>LeaseBackend</code>, <code>SessionRuntimeHints</code></li>
|
|
</ul>
|
|
</li>
|
|
<li><code>agent-device/selectors</code>
|
|
<ul>
|
|
<li><code>parseSelectorChain(expression)</code></li>
|
|
<li><code>tryParseSelectorChain(expression)</code></li>
|
|
<li><code>resolveSelectorChain(nodes, chain, options)</code></li>
|
|
<li><code>findSelectorChainMatch(nodes, chain, options)</code></li>
|
|
<li><code>formatSelectorFailure(chain, diagnostics, options)</code></li>
|
|
<li><code>isNodeVisible(node)</code></li>
|
|
<li><code>isSelectorToken(token)</code></li>
|
|
<li><code>isNodeEditable(node, platform)</code></li>
|
|
<li>types: <code>SelectorChain</code>, <code>SelectorDiagnostics</code></li>
|
|
</ul>
|
|
</li>
|
|
<li><code>agent-device/finders</code>
|
|
<ul>
|
|
<li><code>findBestMatchesByLocator(nodes, locator, query, requireRectOrOptions)</code></li>
|
|
<li><code>parseFindArgs(args)</code></li>
|
|
<li>types: <code>FindMatchOptions</code></li>
|
|
</ul>
|
|
</li>
|
|
<li><code>agent-device/install-source</code>
|
|
<ul>
|
|
<li><code>ARCHIVE_EXTENSIONS</code></li>
|
|
<li><code>isTrustedInstallSourceUrl(sourceUrl)</code></li>
|
|
<li><code>validateDownloadSourceUrl(url)</code></li>
|
|
<li>types: <code>MaterializeInstallSource</code></li>
|
|
</ul>
|
|
</li>
|
|
<li><code>agent-device/artifacts</code>
|
|
<ul>
|
|
<li><code>resolveAndroidArchivePackageName(archivePath)</code></li>
|
|
</ul>
|
|
</li>
|
|
<li><code>agent-device/android-adb</code>
|
|
<ul>
|
|
<li><code>createAndroidPortReverseManager(provider)</code></li>
|
|
<li><code>captureAndroidLogcatWithAdb(executor, options?)</code></li>
|
|
<li><code>readAndroidClipboardWithAdb(executor)</code> / <code>writeAndroidClipboardWithAdb(executor, text)</code></li>
|
|
<li><code>getAndroidKeyboardStatusWithAdb(executor)</code> / <code>dismissAndroidKeyboardWithAdb(executor)</code></li>
|
|
<li><code>openAndroidAppWithAdb(executor, packageName)</code></li>
|
|
<li><code>forceStopAndroidAppWithAdb(executor, packageName)</code></li>
|
|
<li><code>listAndroidAppsWithAdb(executor)</code></li>
|
|
<li><code>getAndroidAppStateWithAdb(executor)</code></li>
|
|
<li>types: <code>AndroidAdbExecutor</code>, <code>AndroidAdbExecutorOptions</code>, <code>AndroidAdbProvider</code>,
|
|
<code>AndroidKeyboardState</code>, <code>AndroidKeyboardDismissResult</code>, <code>AndroidPortReverseEndpoint</code></li>
|
|
</ul>
|
|
</li>
|
|
<li><code>agent-device/limrun</code>
|
|
<ul>
|
|
<li><code>new LimrunRuntime(options)</code></li>
|
|
<li><code>runtime.getDeviceSession(device)</code></li>
|
|
<li>types: <code>LimrunRuntimeOptions</code>, <code>LimrunDeviceSession</code>, <code>LimrunAndroidDeviceSession</code>,
|
|
<code>LimrunIosDeviceSession</code>, <code>LimrunIosCommandExecution</code></li>
|
|
</ul>
|
|
</li>
|
|
<li><code>agent-device/ai-sdk</code>
|
|
<ul>
|
|
<li><code>createAgentDeviceTools(options)</code></li>
|
|
<li>types: <code>AgentDeviceToolSet</code>, <code>AgentDeviceTools</code>, <code>CreateAgentDeviceToolsOptions</code></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<h2 class="rp-toc-include" id="basic-usage"><a href="#basic-usage" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Basic usage</h2>
|
|
<p>The canonical client example is embedded below. It is also runnable from <a href="https://github.com/callstack/agent-device/blob/main/examples/sdk/client-session.ts" target="_blank" rel="noopener noreferrer" class="rp-link"><code>examples/sdk/client-session.ts</code></a>.</p>
|
|
<div class="rp-codeblock language-ts"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="ts"><code><span class="line"><span style="color:var(--shiki-token-comment)">/**</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-comment)"> * Root client session: create a client, open an app, capture a snapshot, tap</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-comment)"> * a node, then close the session — with typed error handling via the</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-comment)"> * exported error helpers.</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-comment)"> *</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-comment)"> * Demonstrates: `createAgentDeviceClient`, `AppError`, `isAgentDeviceError`,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-comment)"> * and `normalizeAgentDeviceError` from the `agent-device` root export.</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-comment)"> *</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-comment)"> * Prerequisites: an `agent-device` daemon target (a booted iOS simulator).</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-comment)"> * This file typechecks without one; running it for real also requires</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-comment)"> * `pnpm build` first, so the package resolves at runtime.</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-comment)"> *</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-comment)"> * Run: node --experimental-strip-types examples/sdk/client-session.ts</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-comment)"> */</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">import</span><span style="color:var(--shiki-foreground)"> {</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> AppError</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> createAgentDeviceClient</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> isAgentDeviceError</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> normalizeAgentDeviceError</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)">} </span><span style="color:var(--shiki-token-keyword)">from</span><span style="color:var(--shiki-token-string-expression)"> 'agent-device'</span><span style="color:var(--shiki-foreground)">;</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">async</span><span style="color:var(--shiki-token-keyword)"> function</span><span style="color:var(--shiki-token-function)"> resolveSnapshotCapableIosDevice</span><span style="color:var(--shiki-foreground)">(client</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-function)"> ReturnType</span><span style="color:var(--shiki-foreground)"><</span><span style="color:var(--shiki-token-keyword)">typeof</span><span style="color:var(--shiki-foreground)"> createAgentDeviceClient>) {</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)"> const</span><span style="color:var(--shiki-token-constant)"> devices</span><span style="color:var(--shiki-token-keyword)"> =</span><span style="color:var(--shiki-token-keyword)"> await</span><span style="color:var(--shiki-token-constant)"> client</span><span style="color:var(--shiki-token-function)">.</span><span style="color:var(--shiki-token-constant)">devices</span><span style="color:var(--shiki-token-function)">.list</span><span style="color:var(--shiki-foreground)">({ platform</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'ios'</span><span style="color:var(--shiki-foreground)"> });</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)"> const</span><span style="color:var(--shiki-token-constant)"> device</span><span style="color:var(--shiki-token-keyword)"> =</span><span style="color:var(--shiki-foreground)"> devices[</span><span style="color:var(--shiki-token-constant)">0</span><span style="color:var(--shiki-foreground)">];</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)"> if</span><span style="color:var(--shiki-foreground)"> (</span><span style="color:var(--shiki-token-keyword)">!</span><span style="color:var(--shiki-foreground)">device) {</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)"> throw</span><span style="color:var(--shiki-token-keyword)"> new</span><span style="color:var(--shiki-token-function)"> AppError</span><span style="color:var(--shiki-foreground)">(</span><span style="color:var(--shiki-token-string-expression)">'DEVICE_NOT_FOUND'</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-string-expression)"> 'No iOS device available'</span><span style="color:var(--shiki-foreground)">);</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> }</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)"> const</span><span style="color:var(--shiki-token-constant)"> capabilities</span><span style="color:var(--shiki-token-keyword)"> =</span><span style="color:var(--shiki-token-keyword)"> await</span><span style="color:var(--shiki-token-constant)"> client</span><span style="color:var(--shiki-token-function)">.</span><span style="color:var(--shiki-token-constant)">devices</span><span style="color:var(--shiki-token-function)">.capabilities</span><span style="color:var(--shiki-foreground)">({ platform</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'ios'</span><span style="color:var(--shiki-foreground)"> });</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)"> if</span><span style="color:var(--shiki-foreground)"> (</span><span style="color:var(--shiki-token-keyword)">!</span><span style="color:var(--shiki-token-constant)">capabilities</span><span style="color:var(--shiki-token-function)">.</span><span style="color:var(--shiki-token-constant)">availableCommands</span><span style="color:var(--shiki-token-function)">.includes</span><span style="color:var(--shiki-foreground)">(</span><span style="color:var(--shiki-token-string-expression)">'snapshot'</span><span style="color:var(--shiki-foreground)">)) {</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)"> throw</span><span style="color:var(--shiki-token-keyword)"> new</span><span style="color:var(--shiki-token-function)"> AppError</span><span style="color:var(--shiki-foreground)">(</span><span style="color:var(--shiki-token-string-expression)">'UNSUPPORTED_OPERATION'</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-string-expression)"> 'Selected target does not support snapshots'</span><span style="color:var(--shiki-foreground)">);</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> }</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)"> return</span><span style="color:var(--shiki-foreground)"> device;</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)">}</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">function</span><span style="color:var(--shiki-token-function)"> reportAgentDeviceError</span><span style="color:var(--shiki-foreground)">(error</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-constant)"> unknown</span><span style="color:var(--shiki-foreground)">)</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-constant)"> void</span><span style="color:var(--shiki-foreground)"> {</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)"> const</span><span style="color:var(--shiki-token-constant)"> normalized</span><span style="color:var(--shiki-token-keyword)"> =</span><span style="color:var(--shiki-token-function)"> normalizeAgentDeviceError</span><span style="color:var(--shiki-foreground)">(error);</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-constant)"> console</span><span style="color:var(--shiki-token-function)">.error</span><span style="color:var(--shiki-foreground)">(</span><span style="color:var(--shiki-token-string-expression)">`agent-device error [</span><span style="color:var(--shiki-token-keyword)">${</span><span style="color:var(--shiki-token-constant)">normalized</span><span style="color:var(--shiki-foreground)">.code</span><span style="color:var(--shiki-token-keyword)">}</span><span style="color:var(--shiki-token-string-expression)">]: </span><span style="color:var(--shiki-token-keyword)">${</span><span style="color:var(--shiki-token-constant)">normalized</span><span style="color:var(--shiki-foreground)">.message</span><span style="color:var(--shiki-token-keyword)">}</span><span style="color:var(--shiki-token-string-expression)">`</span><span style="color:var(--shiki-foreground)">);</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)"> if</span><span style="color:var(--shiki-foreground)"> (</span><span style="color:var(--shiki-token-constant)">normalized</span><span style="color:var(--shiki-foreground)">.hint) {</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-constant)"> console</span><span style="color:var(--shiki-token-function)">.error</span><span style="color:var(--shiki-foreground)">(</span><span style="color:var(--shiki-token-string-expression)">`hint: </span><span style="color:var(--shiki-token-keyword)">${</span><span style="color:var(--shiki-token-constant)">normalized</span><span style="color:var(--shiki-foreground)">.hint</span><span style="color:var(--shiki-token-keyword)">}</span><span style="color:var(--shiki-token-string-expression)">`</span><span style="color:var(--shiki-foreground)">);</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> }</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-constant)"> process</span><span style="color:var(--shiki-foreground)">.exitCode </span><span style="color:var(--shiki-token-keyword)">=</span><span style="color:var(--shiki-token-constant)"> 1</span><span style="color:var(--shiki-foreground)">;</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)">}</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">async</span><span style="color:var(--shiki-token-keyword)"> function</span><span style="color:var(--shiki-token-function)"> main</span><span style="color:var(--shiki-foreground)">()</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-function)"> Promise</span><span style="color:var(--shiki-foreground)"><</span><span style="color:var(--shiki-token-constant)">void</span><span style="color:var(--shiki-foreground)">> {</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)"> const</span><span style="color:var(--shiki-token-constant)"> client</span><span style="color:var(--shiki-token-keyword)"> =</span><span style="color:var(--shiki-token-function)"> createAgentDeviceClient</span><span style="color:var(--shiki-foreground)">({</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> session</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'sdk-example'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> lockPolicy</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'reject'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> lockPlatform</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'ios'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> });</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)"> try</span><span style="color:var(--shiki-foreground)"> {</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)"> const</span><span style="color:var(--shiki-token-constant)"> device</span><span style="color:var(--shiki-token-keyword)"> =</span><span style="color:var(--shiki-token-keyword)"> await</span><span style="color:var(--shiki-token-function)"> resolveSnapshotCapableIosDevice</span><span style="color:var(--shiki-foreground)">(client);</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)"> await</span><span style="color:var(--shiki-token-constant)"> client</span><span style="color:var(--shiki-token-function)">.</span><span style="color:var(--shiki-token-constant)">apps</span><span style="color:var(--shiki-token-function)">.open</span><span style="color:var(--shiki-foreground)">({</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> app</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'com.apple.Preferences'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> platform</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'ios'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> udid</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-constant)"> device</span><span style="color:var(--shiki-foreground)">.id</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> });</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)"> const</span><span style="color:var(--shiki-token-constant)"> snapshot</span><span style="color:var(--shiki-token-keyword)"> =</span><span style="color:var(--shiki-token-keyword)"> await</span><span style="color:var(--shiki-token-constant)"> client</span><span style="color:var(--shiki-token-function)">.</span><span style="color:var(--shiki-token-constant)">capture</span><span style="color:var(--shiki-token-function)">.snapshot</span><span style="color:var(--shiki-foreground)">({ interactiveOnly</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-constant)"> true</span><span style="color:var(--shiki-foreground)"> });</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)"> const</span><span style="color:var(--shiki-token-constant)"> target</span><span style="color:var(--shiki-token-keyword)"> =</span><span style="color:var(--shiki-token-constant)"> snapshot</span><span style="color:var(--shiki-token-function)">.</span><span style="color:var(--shiki-token-constant)">nodes</span><span style="color:var(--shiki-token-function)">.find</span><span style="color:var(--shiki-foreground)">((node) </span><span style="color:var(--shiki-token-keyword)">=></span><span style="color:var(--shiki-token-constant)"> node</span><span style="color:var(--shiki-foreground)">.role </span><span style="color:var(--shiki-token-keyword)">===</span><span style="color:var(--shiki-token-string-expression)"> 'button'</span><span style="color:var(--shiki-foreground)">);</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)"> if</span><span style="color:var(--shiki-foreground)"> (target) {</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)"> await</span><span style="color:var(--shiki-token-constant)"> client</span><span style="color:var(--shiki-token-function)">.</span><span style="color:var(--shiki-token-constant)">interactions</span><span style="color:var(--shiki-token-function)">.press</span><span style="color:var(--shiki-foreground)">({ ref</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-constant)"> target</span><span style="color:var(--shiki-foreground)">.ref });</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> }</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> } </span><span style="color:var(--shiki-token-keyword)">catch</span><span style="color:var(--shiki-foreground)"> (error) {</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)"> if</span><span style="color:var(--shiki-foreground)"> (</span><span style="color:var(--shiki-token-keyword)">!</span><span style="color:var(--shiki-token-function)">isAgentDeviceError</span><span style="color:var(--shiki-foreground)">(error)) </span><span style="color:var(--shiki-token-keyword)">throw</span><span style="color:var(--shiki-foreground)"> error;</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-function)"> reportAgentDeviceError</span><span style="color:var(--shiki-foreground)">(error);</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> } </span><span style="color:var(--shiki-token-keyword)">finally</span><span style="color:var(--shiki-foreground)"> {</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)"> await</span><span style="color:var(--shiki-token-constant)"> client</span><span style="color:var(--shiki-token-function)">.</span><span style="color:var(--shiki-token-constant)">sessions</span><span style="color:var(--shiki-token-function)">.close</span><span style="color:var(--shiki-foreground)">();</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> }</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)">}</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">await</span><span style="color:var(--shiki-token-function)"> main</span><span style="color:var(--shiki-foreground)">();</span></span>
|
|
<span class="line"></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
|
<p><code>client.devices.capabilities()</code> returns <code>{ device, availableCommands }</code>, using the same capability matrix as the CLI. Use it when a dynamic integration needs to decide which command names are valid for the selected target.</p>
|
|
<p>For direct iOS simulator app launches, <code>client.apps.open({ app, platform: 'ios', launchConsole: './artifacts/app.console.log' })</code> captures launch-time
|
|
stdout/stderr. The option mirrors <code>open --launch-console</code> and is not valid for URL opens or non-simulator targets.</p>
|
|
<p>When surfacing Apple simulators, <code>client.apps.open({ deviceHub: true })</code> mirrors <code>open --device-hub</code> and uses Xcode Device Hub instead of the
|
|
standalone Simulator app.</p>
|
|
<p><code>client.sessions.stateDir()</code> mirrors <code>session state-dir</code> and returns the resolved daemon state directory as a pure local resolution — it never starts
|
|
or contacts the daemon. Pass <code>{ stateDir }</code> to resolve an explicit override the same way the CLI resolves <code>--state-dir</code>.</p>
|
|
<p><code>client.sessions.artifacts({ provider, providerSessionId })</code> mirrors <code>artifacts --provider ... --provider-session ...</code> and returns provider-hosted <code>cloudArtifacts</code>.
|
|
Use it for BrowserStack or AWS Device Farm session videos/logs after a cloud session has stopped, or omit <code>providerSessionId</code> when an embedding host has registered a provider runtime that can infer the active lease. Limrun does not currently expose provider artifacts through this command.</p>
|
|
<div class="rp-codeblock language-ts"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="ts"><code><span class="line"><span style="color:var(--shiki-token-keyword)">const</span><span style="color:var(--shiki-token-constant)"> result</span><span style="color:var(--shiki-token-keyword)"> =</span><span style="color:var(--shiki-token-keyword)"> await</span><span style="color:var(--shiki-token-constant)"> client</span><span style="color:var(--shiki-token-function)">.</span><span style="color:var(--shiki-token-constant)">sessions</span><span style="color:var(--shiki-token-function)">.artifacts</span><span style="color:var(--shiki-foreground)">({</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> provider</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'aws-device-farm'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> providerSessionId</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'arn:aws:devicefarm:us-west-2:123:session/project/session/00000'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)">});</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">if</span><span style="color:var(--shiki-foreground)"> (</span><span style="color:var(--shiki-token-string-expression)">'cloudArtifacts'</span><span style="color:var(--shiki-token-keyword)"> in</span><span style="color:var(--shiki-foreground)"> result) {</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)"> for</span><span style="color:var(--shiki-foreground)"> (</span><span style="color:var(--shiki-token-keyword)">const</span><span style="color:var(--shiki-token-constant)"> artifact</span><span style="color:var(--shiki-token-keyword)"> of</span><span style="color:var(--shiki-token-constant)"> result</span><span style="color:var(--shiki-foreground)">.cloudArtifacts) {</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-constant)"> console</span><span style="color:var(--shiki-token-function)">.log</span><span style="color:var(--shiki-foreground)">(</span><span style="color:var(--shiki-token-constant)">artifact</span><span style="color:var(--shiki-foreground)">.kind</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-constant)"> artifact</span><span style="color:var(--shiki-foreground)">.name</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-constant)"> artifact</span><span style="color:var(--shiki-foreground)">.url);</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> }</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)">}</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
|
<h2 class="rp-toc-include" id="device-cloud-sessions"><a href="#device-cloud-sessions" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Device cloud sessions</h2>
|
|
<p>Limrun, BrowserStack, and AWS Device Farm can be driven through the normal typed client methods. Use the corresponding CLI <code>connect</code> flow when you want persisted local connection state. Use direct client config when a Node integration already owns credentials and provider selectors.</p>
|
|
<div class="rp-codeblock language-ts"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="ts"><code><span class="line"><span style="color:var(--shiki-token-keyword)">import</span><span style="color:var(--shiki-foreground)"> { createAgentDeviceClient } </span><span style="color:var(--shiki-token-keyword)">from</span><span style="color:var(--shiki-token-string-expression)"> 'agent-device'</span><span style="color:var(--shiki-foreground)">;</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">const</span><span style="color:var(--shiki-token-constant)"> client</span><span style="color:var(--shiki-token-keyword)"> =</span><span style="color:var(--shiki-token-function)"> createAgentDeviceClient</span><span style="color:var(--shiki-foreground)">({</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> leaseProvider</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'browserstack'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> providerOsVersion</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> '14.0'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> providerApp</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'bs://app-id'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-comment)"> // Optional hosted device features, applied when the session is created.</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> providerDeviceOrientation</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'portrait'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> providerTimezone</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'New_York'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)">});</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">await</span><span style="color:var(--shiki-token-constant)"> client</span><span style="color:var(--shiki-token-function)">.</span><span style="color:var(--shiki-token-constant)">apps</span><span style="color:var(--shiki-token-function)">.open</span><span style="color:var(--shiki-foreground)">({ app</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'com.example.app'</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-foreground)"> platform</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'android'</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-foreground)"> device</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'Google Pixel 8'</span><span style="color:var(--shiki-foreground)"> });</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">await</span><span style="color:var(--shiki-token-constant)"> client</span><span style="color:var(--shiki-token-function)">.</span><span style="color:var(--shiki-token-constant)">capture</span><span style="color:var(--shiki-token-function)">.snapshot</span><span style="color:var(--shiki-foreground)">({ interactiveOnly</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-constant)"> true</span><span style="color:var(--shiki-foreground)"> });</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">const</span><span style="color:var(--shiki-token-constant)"> closed</span><span style="color:var(--shiki-token-keyword)"> =</span><span style="color:var(--shiki-token-keyword)"> await</span><span style="color:var(--shiki-token-constant)"> client</span><span style="color:var(--shiki-token-function)">.</span><span style="color:var(--shiki-token-constant)">sessions</span><span style="color:var(--shiki-token-function)">.close</span><span style="color:var(--shiki-foreground)">();</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
|
<p><code>apps.open</code> also returns a response-level <code>selection</code> record describing whether the target came
|
|
from an explicit selector, an existing session, one local booted/bootable candidate, the one booted
|
|
simulator with the app installed, or one provider-owned candidate. Ambiguous requests fail with
|
|
structured retry selectors instead of silently retargeting.</p>
|
|
<p>Use <code>client.sessions.artifacts({ provider, providerSessionId })</code> with <code>closed.provider?.providerSessionId</code> to fetch provider-hosted video and log URLs after close. See the <a href="/agent-device/docs/browserstack" class="rp-link">BrowserStack</a>, <a href="/agent-device/docs/aws-device-farm" class="rp-link">AWS Device Farm</a>, and <a href="/agent-device/docs/limrun" class="rp-link">Limrun</a> guides for provider-specific setup.</p>
|
|
<h2 class="rp-toc-include" id="web-sessions"><a href="#web-sessions" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Web sessions</h2>
|
|
<p>Typed client commands can target browser sessions with the same command methods by passing
|
|
<code>platform: 'web'</code>. The managed web backend is set up through the CLI, not through a typed client
|
|
method, so run <code>agent-device web setup</code> before first use in the same effective state directory. Use
|
|
<code>agent-device web doctor</code> when you need to verify backend health.</p>
|
|
<div class="rp-codeblock language-ts"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="ts"><code><span class="line"><span style="color:var(--shiki-token-keyword)">await</span><span style="color:var(--shiki-token-constant)"> client</span><span style="color:var(--shiki-token-function)">.</span><span style="color:var(--shiki-token-constant)">apps</span><span style="color:var(--shiki-token-function)">.open</span><span style="color:var(--shiki-foreground)">({ url</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'https://example.com'</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-foreground)"> platform</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'web'</span><span style="color:var(--shiki-foreground)"> });</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">await</span><span style="color:var(--shiki-token-constant)"> client</span><span style="color:var(--shiki-token-function)">.</span><span style="color:var(--shiki-token-constant)">capture</span><span style="color:var(--shiki-token-function)">.snapshot</span><span style="color:var(--shiki-foreground)">({ platform</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'web'</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-foreground)"> interactiveOnly</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-constant)"> true</span><span style="color:var(--shiki-foreground)"> });</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">await</span><span style="color:var(--shiki-token-constant)"> client</span><span style="color:var(--shiki-token-function)">.</span><span style="color:var(--shiki-token-constant)">interactions</span><span style="color:var(--shiki-token-function)">.fill</span><span style="color:var(--shiki-foreground)">({ platform</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'web'</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-foreground)"> ref</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> '@e12'</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-foreground)"> text</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'test@example.com'</span><span style="color:var(--shiki-foreground)"> });</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">await</span><span style="color:var(--shiki-token-constant)"> client</span><span style="color:var(--shiki-token-function)">.</span><span style="color:var(--shiki-token-constant)">command</span><span style="color:var(--shiki-token-function)">.wait</span><span style="color:var(--shiki-foreground)">({ platform</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'web'</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-foreground)"> text</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'Welcome'</span><span style="color:var(--shiki-foreground)"> });</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">await</span><span style="color:var(--shiki-token-constant)"> client</span><span style="color:var(--shiki-token-function)">.</span><span style="color:var(--shiki-token-constant)">observability</span><span style="color:var(--shiki-token-function)">.network</span><span style="color:var(--shiki-foreground)">({ platform</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'web'</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-foreground)"> include</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'headers'</span><span style="color:var(--shiki-foreground)"> });</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">await</span><span style="color:var(--shiki-token-constant)"> client</span><span style="color:var(--shiki-token-function)">.</span><span style="color:var(--shiki-token-constant)">observability</span><span style="color:var(--shiki-token-function)">.audio</span><span style="color:var(--shiki-foreground)">({</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> platform</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'web'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> action</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'probe'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> probeAction</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'start'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> durationMs</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-constant)"> 10_000</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> bucketMs</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-constant)"> 1_000</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)">});</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">await</span><span style="color:var(--shiki-token-constant)"> client</span><span style="color:var(--shiki-token-function)">.</span><span style="color:var(--shiki-token-constant)">sessions</span><span style="color:var(--shiki-token-function)">.close</span><span style="color:var(--shiki-foreground)">();</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
|
<p>Web automation requires Node 24+. MCP tools use the same command contracts, so they can target
|
|
<code>platform: 'web'</code> after setup, but local setup/doctor remains a CLI-only workflow. Web network
|
|
inspection adapts managed <code>agent-browser</code> request history to the existing network result shape;
|
|
request and response bodies are not exposed by that backend path. Web audio probes sample HTML
|
|
media elements and return compact dBFS buckets.</p>
|
|
<h2 class="rp-toc-include" id="android-adb-providers"><a href="#android-adb-providers" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Android ADB providers</h2>
|
|
<p>Use <code>agent-device/android-adb</code> when a bridge owns Android device access but wants upstream command
|
|
behavior for ADB-shaped operations. Executors receive arguments after <code>adb</code>, so remote bridges can
|
|
route the same argument arrays through an ADB tunnel, websocket API, or another remote transport.</p>
|
|
<p>The public helpers accept an executor directly and do not expose the daemon's scoped adb
|
|
interception internals. Use <code>captureAndroidLogcatWithAdb(executor, options?)</code> when a bridge needs a
|
|
bounded logcat capture.</p>
|
|
<p>Providers can also expose <code>reverse</code> for first-class port reverse ownership. Plain executors do not
|
|
advertise reverse support automatically; call <code>createAndroidPortReverseManager(providerOrExecutor)</code>
|
|
only when the provider supports <code>adb reverse</code> argument semantics. The manager makes duplicate setup
|
|
idempotent for the same owner and rejects conflicting owners for the same local endpoint.</p>
|
|
<div class="rp-codeblock language-ts"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="ts"><code><span class="line"><span style="color:var(--shiki-token-keyword)">import</span><span style="color:var(--shiki-foreground)"> { getAndroidAppStateWithAdb</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-foreground)"> listAndroidAppsWithAdb } </span><span style="color:var(--shiki-token-keyword)">from</span><span style="color:var(--shiki-token-string-expression)"> 'agent-device/android-adb'</span><span style="color:var(--shiki-foreground)">;</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">import</span><span style="color:var(--shiki-token-keyword)"> type</span><span style="color:var(--shiki-foreground)"> { AndroidAdbExecutorOptions } </span><span style="color:var(--shiki-token-keyword)">from</span><span style="color:var(--shiki-token-string-expression)"> 'agent-device/android-adb'</span><span style="color:var(--shiki-foreground)">;</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">const</span><span style="color:var(--shiki-token-constant)"> provider</span><span style="color:var(--shiki-token-keyword)"> =</span><span style="color:var(--shiki-foreground)"> {</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-function)"> exec</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-keyword)"> async</span><span style="color:var(--shiki-foreground)"> (args</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-constant)"> string</span><span style="color:var(--shiki-foreground)">[]</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-foreground)"> options</span><span style="color:var(--shiki-token-keyword)">?:</span><span style="color:var(--shiki-token-function)"> AndroidAdbExecutorOptions</span><span style="color:var(--shiki-foreground)">) </span><span style="color:var(--shiki-token-keyword)">=></span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)"> await</span><span style="color:var(--shiki-token-function)"> runAdbThroughRemoteTunnel</span><span style="color:var(--shiki-foreground)">(args</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-foreground)"> options)</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)">};</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">const</span><span style="color:var(--shiki-token-constant)"> apps</span><span style="color:var(--shiki-token-keyword)"> =</span><span style="color:var(--shiki-token-keyword)"> await</span><span style="color:var(--shiki-token-function)"> listAndroidAppsWithAdb</span><span style="color:var(--shiki-foreground)">(</span><span style="color:var(--shiki-token-constant)">provider</span><span style="color:var(--shiki-foreground)">.exec); </span><span style="color:var(--shiki-token-comment)">// user-installed apps by default</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">const</span><span style="color:var(--shiki-token-constant)"> foreground</span><span style="color:var(--shiki-token-keyword)"> =</span><span style="color:var(--shiki-token-keyword)"> await</span><span style="color:var(--shiki-token-function)"> getAndroidAppStateWithAdb</span><span style="color:var(--shiki-foreground)">(</span><span style="color:var(--shiki-token-constant)">provider</span><span style="color:var(--shiki-foreground)">.exec);</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
|
<h2 class="rp-toc-include" id="command-methods"><a href="#command-methods" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Command methods</h2>
|
|
<p>Use <code>client.command.<method>()</code> for command-level device actions. It uses the same daemon transport path as the higher-level client methods, including session metadata, tenant/run/lease fields, normalized daemon errors, and remote artifact handling.</p>
|
|
<p>Results are daemon-shaped objects with typed known fields, so command semantics stay aligned with the CLI.</p>
|
|
<div class="rp-codeblock language-ts"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="ts"><code><span class="line"><span style="color:var(--shiki-token-keyword)">await</span><span style="color:var(--shiki-token-constant)"> client</span><span style="color:var(--shiki-token-function)">.</span><span style="color:var(--shiki-token-constant)">command</span><span style="color:var(--shiki-token-function)">.wait</span><span style="color:var(--shiki-foreground)">({</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> text</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'Continue'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> timeoutMs</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-constant)"> 5_000</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)">});</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">await</span><span style="color:var(--shiki-token-constant)"> client</span><span style="color:var(--shiki-token-function)">.</span><span style="color:var(--shiki-token-constant)">command</span><span style="color:var(--shiki-token-function)">.keyboard</span><span style="color:var(--shiki-foreground)">({</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> action</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'dismiss'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)">});</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">await</span><span style="color:var(--shiki-token-constant)"> client</span><span style="color:var(--shiki-token-function)">.</span><span style="color:var(--shiki-token-constant)">command</span><span style="color:var(--shiki-token-function)">.clipboard</span><span style="color:var(--shiki-foreground)">({</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> action</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'write'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> text</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'hello from Node'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)">});</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">await</span><span style="color:var(--shiki-token-constant)"> client</span><span style="color:var(--shiki-token-function)">.</span><span style="color:var(--shiki-token-constant)">command</span><span style="color:var(--shiki-token-function)">.back</span><span style="color:var(--shiki-foreground)">({</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> mode</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'system'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)">});</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">await</span><span style="color:var(--shiki-token-constant)"> client</span><span style="color:var(--shiki-token-function)">.</span><span style="color:var(--shiki-token-constant)">command</span><span style="color:var(--shiki-token-function)">.tvRemote</span><span style="color:var(--shiki-foreground)">({</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> platform</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'android'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> target</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'tv'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> button</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'down'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)">});</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">await</span><span style="color:var(--shiki-token-constant)"> client</span><span style="color:var(--shiki-token-function)">.</span><span style="color:var(--shiki-token-constant)">command</span><span style="color:var(--shiki-token-function)">.tvRemote</span><span style="color:var(--shiki-foreground)">({</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> platform</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'ios'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> target</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'tv'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> button</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'select'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)">});</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">await</span><span style="color:var(--shiki-token-constant)"> client</span><span style="color:var(--shiki-token-function)">.</span><span style="color:var(--shiki-token-constant)">command</span><span style="color:var(--shiki-token-function)">.tvRemote</span><span style="color:var(--shiki-foreground)">({</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> platform</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'vega'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> target</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'tv'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> serial</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'VirtualDevice'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> button</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'select'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> durationMs</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-constant)"> 900</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)">});</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">await</span><span style="color:var(--shiki-token-constant)"> client</span><span style="color:var(--shiki-token-function)">.</span><span style="color:var(--shiki-token-constant)">command</span><span style="color:var(--shiki-token-function)">.appSwitcher</span><span style="color:var(--shiki-foreground)">();</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
|
<p>Vega OS client support is currently VVD-only and covers device discovery, app open/close, <code>back</code>, <code>home</code>, and <code>tvRemote</code>. Physical Fire TV, capture, selector, install, logging, and performance methods report unsupported for Vega targets.</p>
|
|
<p>Supported command methods:</p>
|
|
<ul>
|
|
<li><code>wait</code></li>
|
|
<li><code>alert</code></li>
|
|
<li><code>appState</code></li>
|
|
<li><code>back</code></li>
|
|
<li><code>home</code></li>
|
|
<li><code>orientation</code></li>
|
|
<li><code>appSwitcher</code></li>
|
|
<li><code>keyboard</code></li>
|
|
<li><code>clipboard</code></li>
|
|
<li><code>tvRemote</code></li>
|
|
<li><code>reactNative</code></li>
|
|
<li><code>doctor</code></li>
|
|
<li><code>prepare</code></li>
|
|
<li><code>viewport</code></li>
|
|
</ul>
|
|
<p>The deprecated <code>rotate()</code> alias remains available for compatibility; use <code>orientation()</code> in new integrations.</p>
|
|
<p>The complete domain-client method map is:</p>
|
|
<ul>
|
|
<li><code>client.devices.list()</code>, <code>capabilities()</code>, <code>boot()</code>, <code>shutdown()</code></li>
|
|
<li><code>client.sessions.list()</code>, <code>stateDir()</code>, <code>close()</code>, <code>saveScript()</code>, <code>artifacts()</code></li>
|
|
<li><code>client.apps.install()</code>, <code>reinstall()</code>, <code>installFromSource()</code>, <code>list()</code>, <code>open()</code>, <code>close()</code>, <code>push()</code>, <code>triggerEvent()</code></li>
|
|
<li><code>client.materializations.release()</code></li>
|
|
<li><code>client.leases.allocate()</code>, <code>heartbeat()</code>, <code>release()</code></li>
|
|
<li><code>client.metro.prepare()</code>, <code>reload()</code></li>
|
|
<li><code>client.capture.snapshot()</code>, <code>screenshot()</code>, <code>diff()</code></li>
|
|
<li><code>client.interactions.click()</code>, <code>press()</code>, <code>longPress()</code>, <code>swipe()</code>, <code>pan()</code>, <code>drag()</code>, <code>fling()</code>, <code>swipeGesture()</code>, <code>focus()</code>, <code>type()</code>, <code>fill()</code>, <code>scroll()</code>, <code>pinch()</code>, <code>rotateGesture()</code>, <code>transformGesture()</code>, <code>get()</code>, <code>is()</code>, <code>find()</code></li>
|
|
<li><code>client.replay.run()</code> and <code>client.replay.test()</code></li>
|
|
<li><code>client.batch.run()</code></li>
|
|
<li><code>client.observability.perf(options)</code>, <code>logs()</code>, <code>events()</code>, <code>network()</code>, and <code>audio()</code></li>
|
|
<li><code>client.debug.symbols()</code></li>
|
|
<li><code>client.recording.record()</code> and <code>client.recording.trace()</code></li>
|
|
<li><code>client.settings.update()</code></li>
|
|
</ul>
|
|
<p><code>client.observability.events({ cursor, limit })</code> reads the session event timeline as paged JSON entries. Use <code>nextCursor</code> from the previous page to continue from the daemon-owned <code>events.ndjson</code> file without replaying already uploaded/displayed events. Cursors are absolute and survive the file's size rotation; a cursor older than the retained window rejects with <code>COMMAND_FAILED</code>, <code>details.reason: "EVENT_LOG_CURSOR_EXPIRED"</code>, and <code>details.earliestCursor</code> to resume from.
|
|
The event timeline keeps operational context such as command/status/timing, paths, session/device/app identifiers, refs/selectors, and coordinates. Typed text, clipboard writes, push/event payloads, raw unknown command arguments, and matching raw message fragments are replaced with length-only placeholders.</p>
|
|
<p><code>client.observability.audio()</code> mirrors <code>audio probe start|status|stop</code>. Use it to collect compact RMS/peak dBFS buckets while other session actions continue:</p>
|
|
<div class="rp-codeblock language-ts"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="ts"><code><span class="line"><span style="color:var(--shiki-token-keyword)">await</span><span style="color:var(--shiki-token-constant)"> client</span><span style="color:var(--shiki-token-function)">.</span><span style="color:var(--shiki-token-constant)">observability</span><span style="color:var(--shiki-token-function)">.audio</span><span style="color:var(--shiki-foreground)">({</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> platform</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'web'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> action</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'probe'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> probeAction</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'start'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> durationMs</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-constant)"> 10_000</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> bucketMs</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-constant)"> 1_000</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)">});</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">await</span><span style="color:var(--shiki-token-constant)"> client</span><span style="color:var(--shiki-token-function)">.</span><span style="color:var(--shiki-token-constant)">interactions</span><span style="color:var(--shiki-token-function)">.click</span><span style="color:var(--shiki-foreground)">({ platform</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'web'</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-foreground)"> ref</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> '@e4'</span><span style="color:var(--shiki-foreground)"> });</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">const</span><span style="color:var(--shiki-token-constant)"> audio</span><span style="color:var(--shiki-token-keyword)"> =</span><span style="color:var(--shiki-token-keyword)"> await</span><span style="color:var(--shiki-token-constant)"> client</span><span style="color:var(--shiki-token-function)">.</span><span style="color:var(--shiki-token-constant)">observability</span><span style="color:var(--shiki-token-function)">.audio</span><span style="color:var(--shiki-foreground)">({</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> platform</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'web'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> action</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'probe'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> probeAction</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'status'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)">});</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">await</span><span style="color:var(--shiki-token-constant)"> client</span><span style="color:var(--shiki-token-function)">.</span><span style="color:var(--shiki-token-constant)">observability</span><span style="color:var(--shiki-token-function)">.audio</span><span style="color:var(--shiki-foreground)">({ platform</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'web'</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-foreground)"> action</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'probe'</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-foreground)"> probeAction</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'stop'</span><span style="color:var(--shiki-foreground)"> });</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
|
<p>Web probes sample HTML media elements. Host-system probes use <code>platform: 'macos'</code>, <code>platform: 'ios'</code> for iOS simulators, or <code>platform: 'android'</code> for Android emulators on macOS hosts. They sample host system audio through ScreenCaptureKit and require Screen Recording permission. Physical iOS and Android app audio are not exposed by this command.</p>
|
|
<p>Pass an explicit area to <code>client.observability.perf()</code> so each request stays focused; options and <code>area</code> are required. The removed optionless call and <code>area: 'metrics'</code> aggregate shape fail with replacements in 0.21. Pass <code>{ area: 'frames' }</code> for a bounded frame/jank-health payload or <code>{ area: 'memory', action: 'sample' }</code> for a compact memory-only sample. Use <code>{ area: 'memory', action: 'snapshot', kind: 'android-hprof', out: 'app.hprof' }</code> on Android or <code>{ area: 'memory', action: 'snapshot', kind: 'memgraph', out: 'app.memgraph' }</code> on supported Apple simulator/macOS app sessions to write large memory artifacts to disk. Android native artifacts use <code>{ area: 'cpu', subject: 'profile', action: 'start' | 'stop' | 'report', kind: 'simpleperf', out }</code> and <code>{ area: 'trace', action: 'start' | 'stop', kind: 'perfetto', out }</code>; CPU reports return at most ten top functions in data and print five, while trace/profile contents remain on disk. Physical iOS device memgraph capture reports unavailable with a reason/hint. On Android and supported Apple targets, <code>data.metrics.fps.droppedFramePercent</code> is the primary frame-smoothness value. Android derives it from the current <code>adb shell dumpsys gfxinfo <package> framestats</code> window; connected iOS devices derive it from <code>xcrun xctrace</code> Animation Hitches for the active app process. Frame samples include <code>windowStartedAt</code>, <code>windowEndedAt</code>, and <code>worstWindows</code> so agents can correlate dropped-frame clusters with logs, network entries, and their own session actions. A successful Android read resets Android frame stats; <code>open <app></code> resets the Android frame window too, so agents can call <code>perf({ area: 'frames' })</code>, perform a transition or gesture, then call it again to inspect that focused window. iOS simulator and macOS app sessions report frame health as unavailable rather than inventing FPS or dropped-frame values.</p>
|
|
<p>For Apple native profiling, call <code>perf({ area: 'cpu', subject: 'profile', action: 'start', kind: 'xctrace', template: 'Time Profiler', out: 'app.trace' })</code>, then stop with the same trace path and write a compact report with <code>action: 'report'</code>. The CPU report includes a bounded weighted top-function summary; the raw trace remains an artifact. <code>area: 'trace'</code> supports xctrace templates such as <code>Animation Hitches</code>.</p>
|
|
<p><code>client.recording.record({ action: 'start', path, quality: 'medium' })</code> starts a recording with medium output quality.</p>
|
|
<p><code>client.capture.screenshot({ path, scale: 0.3 })</code> captures a screenshot at 30% of its original width and height. <code>scale</code> accepts <code>0.01</code> through <code>1</code>.</p>
|
|
<p><code>client.batch.run({ steps })</code> accepts structured steps:
|
|
<code>{ command: 'open', input: { app: 'settings' } }</code>. Step <code>input</code> uses the same fields as the
|
|
matching client command; daemon-shaped <code>positionals</code>/<code>flags</code> steps are internal to the daemon batch
|
|
executor.</p>
|
|
<h2 class="rp-toc-include" id="batch-orchestration-for-custom-transports"><a href="#batch-orchestration-for-custom-transports" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Batch orchestration for custom transports</h2>
|
|
<p>Use <code>agent-device/batch</code> when a bridge or in-process runner receives daemon-shaped requests but owns command dispatch itself. The helper keeps validation, inherited flags, serial execution, partial results, and error envelopes aligned with the daemon batch command.</p>
|
|
<p>The standalone custom-transport example is embedded below from <a href="https://github.com/callstack/agent-device/blob/main/examples/sdk/batch-orchestration.ts" target="_blank" rel="noopener noreferrer" class="rp-link"><code>examples/sdk/batch-orchestration.ts</code></a>.</p>
|
|
<div class="rp-codeblock language-ts"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="ts"><code><span class="line"><span style="color:var(--shiki-token-comment)">/**</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-comment)"> * Batch orchestration for a custom transport: `runBatch` keeps step</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-comment)"> * validation, inherited flags, serial execution, partial results, and</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-comment)"> * daemon-shaped error envelopes aligned with the CLI's `batch` command, so a</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-comment)"> * bridge that owns command dispatch itself does not have to reimplement them.</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-comment)"> *</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-comment)"> * Demonstrates: `runBatch` from `agent-device/batch`, consumed against the</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-comment)"> * `DaemonResponse` result type from `agent-device/contracts`.</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-comment)"> *</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-comment)"> * Prerequisites: none — `dispatch` below is a stub; a real integration would</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-comment)"> * replace it with a call into the bridge's own command dispatcher.</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-comment)"> *</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-comment)"> * Run: node --experimental-strip-types examples/sdk/batch-orchestration.ts</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-comment)"> */</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">import</span><span style="color:var(--shiki-foreground)"> { runBatch } </span><span style="color:var(--shiki-token-keyword)">from</span><span style="color:var(--shiki-token-string-expression)"> 'agent-device/batch'</span><span style="color:var(--shiki-foreground)">;</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">import</span><span style="color:var(--shiki-token-keyword)"> type</span><span style="color:var(--shiki-foreground)"> { DaemonResponse } </span><span style="color:var(--shiki-token-keyword)">from</span><span style="color:var(--shiki-token-string-expression)"> 'agent-device/contracts'</span><span style="color:var(--shiki-foreground)">;</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">type</span><span style="color:var(--shiki-token-function)"> BatchRequest</span><span style="color:var(--shiki-token-keyword)"> =</span><span style="color:var(--shiki-token-function)"> Parameters</span><span style="color:var(--shiki-foreground)"><</span><span style="color:var(--shiki-token-keyword)">typeof</span><span style="color:var(--shiki-foreground)"> runBatch>[</span><span style="color:var(--shiki-token-constant)">0</span><span style="color:var(--shiki-foreground)">];</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">async</span><span style="color:var(--shiki-token-keyword)"> function</span><span style="color:var(--shiki-token-function)"> dispatch</span><span style="color:var(--shiki-foreground)">(stepReq</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-constant)"> unknown</span><span style="color:var(--shiki-foreground)">)</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-function)"> Promise</span><span style="color:var(--shiki-foreground)"><</span><span style="color:var(--shiki-token-function)">Record</span><span style="color:var(--shiki-foreground)"><</span><span style="color:var(--shiki-token-constant)">string</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-constant)"> unknown</span><span style="color:var(--shiki-foreground)">>> {</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-constant)"> console</span><span style="color:var(--shiki-token-function)">.log</span><span style="color:var(--shiki-foreground)">(</span><span style="color:var(--shiki-token-string-expression)">'dispatching step'</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-foreground)"> stepReq);</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)"> return</span><span style="color:var(--shiki-foreground)"> { handled</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-constant)"> true</span><span style="color:var(--shiki-foreground)"> };</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)">}</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">function</span><span style="color:var(--shiki-token-function)"> bridgeErrorToDaemonResponse</span><span style="color:var(--shiki-foreground)">(error</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-constant)"> unknown</span><span style="color:var(--shiki-foreground)">)</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-function)"> Extract</span><span style="color:var(--shiki-foreground)"><</span><span style="color:var(--shiki-token-function)">DaemonResponse</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-foreground)"> { ok</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-constant)"> false</span><span style="color:var(--shiki-foreground)"> }> {</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)"> return</span><span style="color:var(--shiki-foreground)"> {</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> ok</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-constant)"> false</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> error</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-foreground)"> {</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> code</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'COMMAND_FAILED'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> message</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-foreground)"> error </span><span style="color:var(--shiki-token-keyword)">instanceof</span><span style="color:var(--shiki-token-function)"> Error</span><span style="color:var(--shiki-token-keyword)"> ?</span><span style="color:var(--shiki-token-constant)"> error</span><span style="color:var(--shiki-foreground)">.message </span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'Unknown bridge error'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> }</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> };</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)">}</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">async</span><span style="color:var(--shiki-token-keyword)"> function</span><span style="color:var(--shiki-token-function)"> handleBatch</span><span style="color:var(--shiki-foreground)">(req</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-function)"> BatchRequest</span><span style="color:var(--shiki-foreground)">)</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-function)"> Promise</span><span style="color:var(--shiki-foreground)"><</span><span style="color:var(--shiki-token-function)">DaemonResponse</span><span style="color:var(--shiki-foreground)">> {</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)"> return</span><span style="color:var(--shiki-token-keyword)"> await</span><span style="color:var(--shiki-token-function)"> runBatch</span><span style="color:var(--shiki-foreground)">(req</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-constant)"> req</span><span style="color:var(--shiki-foreground)">.session </span><span style="color:var(--shiki-token-keyword)">??</span><span style="color:var(--shiki-token-string-expression)"> 'default'</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-keyword)"> async</span><span style="color:var(--shiki-foreground)"> (stepReq) </span><span style="color:var(--shiki-token-keyword)">=></span><span style="color:var(--shiki-foreground)"> {</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)"> try</span><span style="color:var(--shiki-foreground)"> {</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)"> return</span><span style="color:var(--shiki-foreground)"> { ok</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-constant)"> true</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-foreground)"> data</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-keyword)"> await</span><span style="color:var(--shiki-token-function)"> dispatch</span><span style="color:var(--shiki-foreground)">(stepReq) };</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> } </span><span style="color:var(--shiki-token-keyword)">catch</span><span style="color:var(--shiki-foreground)"> (error) {</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)"> return</span><span style="color:var(--shiki-token-function)"> bridgeErrorToDaemonResponse</span><span style="color:var(--shiki-foreground)">(error);</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> }</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> });</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)">}</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">const</span><span style="color:var(--shiki-token-constant)"> result</span><span style="color:var(--shiki-token-keyword)"> =</span><span style="color:var(--shiki-token-keyword)"> await</span><span style="color:var(--shiki-token-function)"> handleBatch</span><span style="color:var(--shiki-foreground)">({</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> command</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'batch'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> positionals</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-foreground)"> []</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> flags</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-foreground)"> {</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> batchSteps</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-foreground)"> [</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> { command</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'wait'</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-foreground)"> input</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-foreground)"> { text</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'Welcome'</span><span style="color:var(--shiki-foreground)"> } }</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> { command</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'back'</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-foreground)"> input</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-foreground)"> {} }</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> ]</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> }</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)">});</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">if</span><span style="color:var(--shiki-foreground)"> (</span><span style="color:var(--shiki-token-constant)">result</span><span style="color:var(--shiki-foreground)">.ok) {</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-constant)"> console</span><span style="color:var(--shiki-token-function)">.log</span><span style="color:var(--shiki-foreground)">(</span><span style="color:var(--shiki-token-string-expression)">`batch completed: </span><span style="color:var(--shiki-token-keyword)">${</span><span style="color:var(--shiki-token-constant)">JSON</span><span style="color:var(--shiki-token-function)">.stringify</span><span style="color:var(--shiki-foreground)">(</span><span style="color:var(--shiki-token-constant)">result</span><span style="color:var(--shiki-foreground)">.data)</span><span style="color:var(--shiki-token-keyword)">}</span><span style="color:var(--shiki-token-string-expression)">`</span><span style="color:var(--shiki-foreground)">);</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)">} </span><span style="color:var(--shiki-token-keyword)">else</span><span style="color:var(--shiki-foreground)"> {</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-constant)"> console</span><span style="color:var(--shiki-token-function)">.error</span><span style="color:var(--shiki-foreground)">(</span><span style="color:var(--shiki-token-string-expression)">`batch failed [</span><span style="color:var(--shiki-token-keyword)">${</span><span style="color:var(--shiki-token-constant)">result</span><span style="color:var(--shiki-foreground)">.</span><span style="color:var(--shiki-token-constant)">error</span><span style="color:var(--shiki-foreground)">.code</span><span style="color:var(--shiki-token-keyword)">}</span><span style="color:var(--shiki-token-string-expression)">]: </span><span style="color:var(--shiki-token-keyword)">${</span><span style="color:var(--shiki-token-constant)">result</span><span style="color:var(--shiki-foreground)">.</span><span style="color:var(--shiki-token-constant)">error</span><span style="color:var(--shiki-foreground)">.message</span><span style="color:var(--shiki-token-keyword)">}</span><span style="color:var(--shiki-token-string-expression)">`</span><span style="color:var(--shiki-foreground)">);</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-constant)"> process</span><span style="color:var(--shiki-foreground)">.exitCode </span><span style="color:var(--shiki-token-keyword)">=</span><span style="color:var(--shiki-token-constant)"> 1</span><span style="color:var(--shiki-foreground)">;</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)">}</span></span>
|
|
<span class="line"></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
|
<h2 class="rp-toc-include" id="android-installfromsource"><a href="#android-installfromsource" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Android <code>installFromSource()</code></h2>
|
|
<div class="rp-codeblock language-ts"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="ts"><code><span class="line"><span style="color:var(--shiki-token-keyword)">import</span><span style="color:var(--shiki-foreground)"> { createAgentDeviceClient } </span><span style="color:var(--shiki-token-keyword)">from</span><span style="color:var(--shiki-token-string-expression)"> 'agent-device'</span><span style="color:var(--shiki-foreground)">;</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">const</span><span style="color:var(--shiki-token-constant)"> androidClient</span><span style="color:var(--shiki-token-keyword)"> =</span><span style="color:var(--shiki-token-function)"> createAgentDeviceClient</span><span style="color:var(--shiki-foreground)">({ session</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'qa-android'</span><span style="color:var(--shiki-foreground)"> });</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">const</span><span style="color:var(--shiki-token-constant)"> installed</span><span style="color:var(--shiki-token-keyword)"> =</span><span style="color:var(--shiki-token-keyword)"> await</span><span style="color:var(--shiki-token-constant)"> androidClient</span><span style="color:var(--shiki-token-function)">.</span><span style="color:var(--shiki-token-constant)">apps</span><span style="color:var(--shiki-token-function)">.installFromSource</span><span style="color:var(--shiki-foreground)">({</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> platform</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'android'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> retainPaths</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-constant)"> true</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> retentionMs</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-constant)"> 60_000</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> source</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-foreground)"> { kind</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'url'</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-foreground)"> url</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'https://example.com/app.apk'</span><span style="color:var(--shiki-foreground)"> }</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)">});</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">await</span><span style="color:var(--shiki-token-constant)"> androidClient</span><span style="color:var(--shiki-token-function)">.</span><span style="color:var(--shiki-token-constant)">apps</span><span style="color:var(--shiki-token-function)">.open</span><span style="color:var(--shiki-foreground)">({</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> platform</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'android'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> app</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-constant)"> installed</span><span style="color:var(--shiki-foreground)">.launchTarget</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)">});</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-constant)">console</span><span style="color:var(--shiki-token-function)">.log</span><span style="color:var(--shiki-foreground)">(</span><span style="color:var(--shiki-token-constant)">installed</span><span style="color:var(--shiki-foreground)">.packageName</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-constant)"> installed</span><span style="color:var(--shiki-foreground)">.launchTarget);</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">if</span><span style="color:var(--shiki-foreground)"> (</span><span style="color:var(--shiki-token-constant)">installed</span><span style="color:var(--shiki-foreground)">.materializationId) {</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)"> await</span><span style="color:var(--shiki-token-constant)"> androidClient</span><span style="color:var(--shiki-token-function)">.</span><span style="color:var(--shiki-token-constant)">materializations</span><span style="color:var(--shiki-token-function)">.release</span><span style="color:var(--shiki-foreground)">({</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> materializationId</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-constant)"> installed</span><span style="color:var(--shiki-foreground)">.materializationId</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> });</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)">}</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">await</span><span style="color:var(--shiki-token-constant)"> androidClient</span><span style="color:var(--shiki-token-function)">.</span><span style="color:var(--shiki-token-constant)">sessions</span><span style="color:var(--shiki-token-function)">.close</span><span style="color:var(--shiki-foreground)">();</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
|
<p>On Android, a successful <code>installFromSource()</code> response returns enough app identity to relaunch the installed app:</p>
|
|
<ul>
|
|
<li><code>packageName</code></li>
|
|
<li><code>launchTarget</code></li>
|
|
</ul>
|
|
<p>If the daemon cannot determine installed app identity, the request fails instead of returning an empty success payload.</p>
|
|
<h2 class="rp-toc-include" id="url-source-rules"><a href="#url-source-rules" class="rp-header-anchor rp-link" aria-hidden="true">#</a>URL source rules</h2>
|
|
<p><code>installFromSource()</code> URL sources are intentionally limited:</p>
|
|
<ul>
|
|
<li>Private and loopback hosts are blocked by default.</li>
|
|
<li>Archive-backed URL installs are only supported for trusted artifact services, currently GitHub Actions and EAS.</li>
|
|
<li>For existing reachable artifact URLs, use <code>source: { kind: 'url', url: ... }</code>.</li>
|
|
<li>For local artifacts, use <code>source: { kind: 'path', path: ... }</code> or the CLI <code>install</code>/<code>reinstall</code> commands.</li>
|
|
<li>For compatible remote daemons that resolve CI artifacts server-side, pass a GitHub Actions artifact source:</li>
|
|
</ul>
|
|
<div class="rp-codeblock language-ts"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="ts"><code><span class="line"><span style="color:var(--shiki-token-keyword)">await</span><span style="color:var(--shiki-token-constant)"> client</span><span style="color:var(--shiki-token-function)">.</span><span style="color:var(--shiki-token-constant)">apps</span><span style="color:var(--shiki-token-function)">.installFromSource</span><span style="color:var(--shiki-foreground)">({</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> platform</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'android'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> source</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-foreground)"> {</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> kind</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'github-actions-artifact'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> owner</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'acme'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> repo</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'mobile'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> artifactId</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-constant)"> 1234567890</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> }</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)">});</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
|
<p>Remote daemons may also support <code>{ kind: 'github-actions-artifact', owner, repo, artifactName }</code> or <code>{ kind: 'github-actions-artifact', owner, repo, runId, artifactName }</code>. The local client preserves these payloads and does not perform GitHub authentication or artifact download.</p>
|
|
<p>Direct Android <code>.apk</code> and <code>.aab</code> URL sources can still resolve package identity from the downloaded install artifact. Trusted GitHub Actions and EAS archive URLs may contain one installable <code>.apk</code>, <code>.aab</code>, <code>.ipa</code>, or iOS <code>.app</code> tar archive.</p>
|
|
<h2 class="rp-toc-include" id="remote-metro-helpers"><a href="#remote-metro-helpers" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Remote Metro helpers</h2>
|
|
<div class="rp-codeblock language-ts"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="ts"><code><span class="line"><span style="color:var(--shiki-token-keyword)">import</span><span style="color:var(--shiki-foreground)"> { prepareMetroRuntime</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-foreground)"> reloadMetro</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-foreground)"> stopMetroTunnel } </span><span style="color:var(--shiki-token-keyword)">from</span><span style="color:var(--shiki-token-string-expression)"> 'agent-device/metro'</span><span style="color:var(--shiki-foreground)">;</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">import</span><span style="color:var(--shiki-foreground)"> { resolveRemoteConfigProfile } </span><span style="color:var(--shiki-token-keyword)">from</span><span style="color:var(--shiki-token-string-expression)"> 'agent-device/remote-config'</span><span style="color:var(--shiki-foreground)">;</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">const</span><span style="color:var(--shiki-token-constant)"> remoteConfig</span><span style="color:var(--shiki-token-keyword)"> =</span><span style="color:var(--shiki-token-function)"> resolveRemoteConfigProfile</span><span style="color:var(--shiki-foreground)">({</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> configPath</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> './agent-device.remote.json'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> cwd</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-constant)"> process</span><span style="color:var(--shiki-token-function)">.cwd</span><span style="color:var(--shiki-foreground)">()</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)">});</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">const</span><span style="color:var(--shiki-token-constant)"> prepared</span><span style="color:var(--shiki-token-keyword)"> =</span><span style="color:var(--shiki-token-keyword)"> await</span><span style="color:var(--shiki-token-function)"> prepareMetroRuntime</span><span style="color:var(--shiki-foreground)">({</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> projectRoot</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-constant)"> remoteConfig</span><span style="color:var(--shiki-foreground)">.</span><span style="color:var(--shiki-token-constant)">profile</span><span style="color:var(--shiki-foreground)">.metroProjectRoot</span><span style="color:var(--shiki-token-keyword)">!</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> kind</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-constant)"> remoteConfig</span><span style="color:var(--shiki-foreground)">.</span><span style="color:var(--shiki-token-constant)">profile</span><span style="color:var(--shiki-foreground)">.metroKind </span><span style="color:var(--shiki-token-keyword)">??</span><span style="color:var(--shiki-token-string-expression)"> 'auto'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> proxyBaseUrl</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-constant)"> remoteConfig</span><span style="color:var(--shiki-foreground)">.</span><span style="color:var(--shiki-token-constant)">profile</span><span style="color:var(--shiki-foreground)">.metroProxyBaseUrl</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> proxyBearerToken</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-constant)"> remoteConfig</span><span style="color:var(--shiki-foreground)">.</span><span style="color:var(--shiki-token-constant)">profile</span><span style="color:var(--shiki-foreground)">.metroBearerToken</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> bridgeScope</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-foreground)"> {</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> tenantId</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-constant)"> remoteConfig</span><span style="color:var(--shiki-foreground)">.</span><span style="color:var(--shiki-token-constant)">profile</span><span style="color:var(--shiki-foreground)">.tenant</span><span style="color:var(--shiki-token-keyword)">!</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> runId</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-constant)"> remoteConfig</span><span style="color:var(--shiki-foreground)">.</span><span style="color:var(--shiki-token-constant)">profile</span><span style="color:var(--shiki-foreground)">.runId</span><span style="color:var(--shiki-token-keyword)">!</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> leaseId</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-constant)"> remoteConfig</span><span style="color:var(--shiki-foreground)">.</span><span style="color:var(--shiki-token-constant)">profile</span><span style="color:var(--shiki-foreground)">.leaseId</span><span style="color:var(--shiki-token-keyword)">!</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> }</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> companionProfileKey</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-constant)"> remoteConfig</span><span style="color:var(--shiki-foreground)">.resolvedPath</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)">});</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-constant)">console</span><span style="color:var(--shiki-token-function)">.log</span><span style="color:var(--shiki-foreground)">(</span><span style="color:var(--shiki-token-constant)">prepared</span><span style="color:var(--shiki-foreground)">.iosRuntime</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-constant)"> prepared</span><span style="color:var(--shiki-foreground)">.androidRuntime);</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">await</span><span style="color:var(--shiki-token-function)"> reloadMetro</span><span style="color:var(--shiki-foreground)">({</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> runtime</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-constant)"> prepared</span><span style="color:var(--shiki-foreground)">.iosRuntime</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)">});</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">await</span><span style="color:var(--shiki-token-function)"> stopMetroTunnel</span><span style="color:var(--shiki-foreground)">({</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> projectRoot</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-constant)"> remoteConfig</span><span style="color:var(--shiki-foreground)">.</span><span style="color:var(--shiki-token-constant)">profile</span><span style="color:var(--shiki-foreground)">.metroProjectRoot</span><span style="color:var(--shiki-token-keyword)">!</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> profileKey</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-constant)"> remoteConfig</span><span style="color:var(--shiki-foreground)">.resolvedPath</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)">});</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
|
<p>Use <code>agent-device/remote-config</code> for profile loading and path resolution, <code>agent-device/metro</code> for Metro preparation, reload, and tunnel lifecycle, and <code>agent-device/contracts</code> when a server consumer needs daemon request or runtime contract types. For bridged remote Metro, <code>proxyBaseUrl</code> is the bridge origin and <code>publicBaseUrl</code> is optional; the bridge descriptor supplies cloud iOS wildcard HTTPS hints and Android runtime-route hints. <code>reloadMetro()</code> calls Metro's <code>/reload</code> endpoint, matching the terminal <code>r</code> reload path for connected React Native apps.</p>
|
|
<h2 class="rp-toc-include" id="selector-helpers"><a href="#selector-helpers" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Selector helpers</h2>
|
|
<p>Use <code>agent-device/selectors</code> when a remote daemon or bridge needs to parse and match selector expressions without deep-importing daemon internals. Matching is platform-aware because role normalization and editability checks differ by backend.</p>
|
|
<div class="rp-codeblock language-ts"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="ts"><code><span class="line"><span style="color:var(--shiki-token-keyword)">import</span><span style="color:var(--shiki-foreground)"> { findSelectorChainMatch</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-foreground)"> parseSelectorChain } </span><span style="color:var(--shiki-token-keyword)">from</span><span style="color:var(--shiki-token-string-expression)"> 'agent-device/selectors'</span><span style="color:var(--shiki-foreground)">;</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">const</span><span style="color:var(--shiki-token-constant)"> chain</span><span style="color:var(--shiki-token-keyword)"> =</span><span style="color:var(--shiki-token-function)"> parseSelectorChain</span><span style="color:var(--shiki-foreground)">(</span><span style="color:var(--shiki-token-string-expression)">'role=button label="Continue" visible=true'</span><span style="color:var(--shiki-foreground)">);</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">const</span><span style="color:var(--shiki-token-constant)"> match</span><span style="color:var(--shiki-token-keyword)"> =</span><span style="color:var(--shiki-token-function)"> findSelectorChainMatch</span><span style="color:var(--shiki-foreground)">(</span><span style="color:var(--shiki-token-constant)">snapshot</span><span style="color:var(--shiki-foreground)">.nodes</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-foreground)"> chain</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-foreground)"> {</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> platform</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-string-expression)"> 'android'</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)"> requireRect</span><span style="color:var(--shiki-token-keyword)">:</span><span style="color:var(--shiki-token-constant)"> true</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
|
<span class="line"><span style="color:var(--shiki-foreground)">});</span></span>
|
|
<span class="line"></span>
|
|
<span class="line"><span style="color:var(--shiki-token-keyword)">if</span><span style="color:var(--shiki-foreground)"> (</span><span style="color:var(--shiki-token-keyword)">!</span><span style="color:var(--shiki-foreground)">match) {</span></span>
|
|
<span class="line"><span style="color:var(--shiki-token-comment)"> // Build a daemon-shaped error with formatSelectorFailure(...) if needed.</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div><!--/$--></div><div class="container-uhcWmO"><img class="logo-IwzwG8" src="/agent-device/static/image/abstract-atom.4eca0300ff.avif" alt="Abstract Logo" aria-hidden="true"/><div class="content-uJxcIj"><div class="headlineContainer-NHNT4y"><h1 class="headline-iCUUUl">Need React or React Native
|
|
expertise you can count on?</h1></div><div class="buttonContainer-wOj8Y6"><div class="dark"><a href="https://www.callstack.com/contact?utm_campaign=open_source&utm_source=agent-device&utm_medium=referral&utm_content=FOOTER_CTA" class="button-DogSnd brand-rT2ahT ">Let's talk<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16" class="button-icon-Okk0hT" aria-hidden="true" focusable="false"><path fill="currentColor" d="M9.333 13.333h1.334V12H9.333zm-6.666-2.666h8V12H12v-1.333h1.333V9.333H12V8h-1.333v1.333H4V2.667H2.667zM9.333 8h1.334V6.667H9.333z"></path></svg></a></div></div></div></div><footer class="rp-doc-footer"><div class="rp-doc-footer__edit"><a href="https://github.com/callstack/agent-device/edit/main/website/docs/client-api.md" target="_blank" rel="noopener noreferrer" class="rp-edit-link rp-link">Edit this page on GitHub</a></div><div class="rp-doc-footer__divider"></div><div class="container-aZLxg0"><a href="/agent-device/docs/debugging-profiling" class="pagerLink-_WIlZJ rp-link"><span class="iconBox-AUO0Le"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 24 24" class="icon-WRLCnG"><path d="M4 20h2V4H4zm8-5v2h2v-2zm-2-4H8v2h2v2h2v-2h8v-2h-8V9h-2zm2-2h2V7h-2z"></path></svg></span><span class="textWrap-lmdyLc"><span class="desc-sp3vRh">Previous page</span><span class="title-hrit_i">Debugging & Profiling</span></span></a><a href="/agent-device/docs/ai-sdk" class="pagerLink-_WIlZJ next-axkYXz rp-link"><span class="textWrap-lmdyLc"><span class="desc-sp3vRh">Next page</span><span class="title-hrit_i">AI SDK</span></span><span class="iconBox-AUO0Le"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 24 24" class="icon-WRLCnG"><path d="M20 20h-2V4h2zm-8-5v2h-2v-2zm2-4h2v2h-2v2h-2v-2H4v-2h8V9h2zm-2-2h-2V7h2z"></path></svg></span></a></div></footer></main></div><aside class="rp-doc-layout__outline rp-scrollbar"><div class="rp-outline"><div class="rp-outline__title">Contents<svg width="14" height="14" class="rp-progress-circle"><circle cx="7" cy="7" r="6" stroke-linecap="round" fill="none" stroke="var(--rp-c-divider-light)" stroke-width="2"></circle><circle cx="7" cy="7" r="6" stroke-linecap="round" fill="none" stroke="var(--rp-c-brand)" stroke-width="2" stroke-dasharray="37.69911184307752" stroke-dashoffset="37.69911184307752" transform="rotate(-90 7 7)" style="transition:stroke-dashoffset 0.3s"></circle></svg></div><nav class="rp-outline__toc rp-scrollbar"><a href="#runnable-examples" class="rp-toc-item rp-link" title="Runnable examples" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">Runnable examples</span></a><a href="#api-reference" class="rp-toc-item rp-link" title="API reference" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">API reference</span></a><a href="#basic-usage" class="rp-toc-item rp-link" title="Basic usage" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">Basic usage</span></a><a href="#device-cloud-sessions" class="rp-toc-item rp-link" title="Device cloud sessions" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">Device cloud sessions</span></a><a href="#web-sessions" class="rp-toc-item rp-link" title="Web sessions" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">Web sessions</span></a><a href="#android-adb-providers" class="rp-toc-item rp-link" title="Android ADB providers" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">Android ADB providers</span></a><a href="#command-methods" class="rp-toc-item rp-link" title="Command methods" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">Command methods</span></a><a href="#batch-orchestration-for-custom-transports" class="rp-toc-item rp-link" title="Batch orchestration for custom transports" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">Batch orchestration for custom transports</span></a><a href="#android-installfromsource" class="rp-toc-item rp-link" title="Android installFromSource()" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">Android <code>installFromSource()</code></span></a><a href="#url-source-rules" class="rp-toc-item rp-link" title="URL source rules" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">URL source rules</span></a><a href="#remote-metro-helpers" class="rp-toc-item rp-link" title="Remote Metro helpers" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">Remote Metro helpers</span></a><a href="#selector-helpers" class="rp-toc-item rp-link" title="Selector helpers" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">Selector helpers</span></a></nav><div class="rp-outline__divider"></div><div class="rp-outline__bottom"><a href="https://github.com/callstack/agent-device/edit/main/website/docs/client-api.md" target="_blank" rel="noopener noreferrer" class="rp-outline__action-row rp-edit-link rp-link"><svg width="16" height="16" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24"><path d="M17 3a2.828 2.828 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5z"></path></svg><span>Edit this page on GitHub</span></a></div></div><div class="container-LzbylO"><div><div class="headline-y75_LS">Curious about developing mobile apps with AI agents?</div><div class="description-muYVs3">We can help you take your agentic workflows to the next level and ship faster.</div></div><a href="https://www.callstack.com/contact?utm_campaign=open_source&utm_source=agent-device&utm_medium=referral&utm_content=OUTLINE_CTA" class="button-DogSnd brand-rT2ahT ">Book a call<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16" class="button-icon-Okk0hT" aria-hidden="true" focusable="false"><path fill="currentColor" d="M9.333 13.333h1.334V12H9.333zm-6.666-2.666h8V12H12v-1.333h1.333V9.333H12V8h-1.333v1.333H4V2.667H2.667zM9.333 8h1.334V6.667H9.333z"></path></svg></a></div></aside></div></div>
|
|
<div id="__rspress_modal_container"></div>
|
|
</body>
|
|
</html>
|