@phone-use/sdk 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +73 -2
- package/dist/index.mjs +124 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/backends/cloud-sandbox.ts +202 -0
- package/src/index.ts +9 -1
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["#endpoint","#token","#timeoutMs","#rpc","_register","_createAd"],"sources":["../src/observe.ts","../src/secrets.ts","../src/actions.ts","../src/backends/agent-device.ts","../src/backends/device-runner.ts","../src/exec.ts","../src/lifecycle.ts","../src/backends/ios.ts","../src/index.ts"],"sourcesContent":["import type { DeviceBackend } from './backend.ts';\nimport type { Rect, SnapshotNode } from './device.ts';\nimport { SessionNotFoundError } from './errors.ts';\n\n// ---------------------------------------------------------------------------\n// DeviceCore: the one-brain observe/resolve/act core, moved\n// verbatim from the harness's DeviceContext. Everything here is portable —\n// no runtime-specific globals and no image libraries — so it runs under Node. The\n// module level holds only types, pure functions, and read-only lookup tables;\n// the harness's DeviceContext subclasses this and layers on cursor/live-view\n// rendering.\n// ---------------------------------------------------------------------------\n\n/** One compressed observation: the frontmost app plus the rendered element list. */\nexport type Observation = {\n /** Frontmost app name, when known. */\n app?: string | undefined;\n /** Frontmost app bundle id, when known. */\n bundleId?: string | undefined;\n /** Whether the element list was truncated. */\n truncated: boolean;\n /** The compressed, human/LLM-readable element listing. */\n elements: string;\n};\n\n/**\n * Post-action evidence from the driver's verify pass: whether the\n * accessibility tree changed, without paying for a full follow-up snapshot.\n */\nexport type ActionEvidence = {\n /** Did the tree fingerprint change across the action. */\n changed?: boolean | undefined;\n /** Human-readable verdict detail. */\n detail?: string | undefined;\n};\n\n// Raw iOS accessibility trees are unusable for agents on content-heavy screens\n// (a full HN page is 485 nodes / ~15k tokens, most of it \"|\" separators and\n// off-screen rows). observe() reduces to what a human sees: on-screen,\n// non-noise elements with compact geometry, plus counts for what's off-screen.\nconst NOISE_LABELS: ReadonlySet<string> = new Set(['|', '(', ')', ',', '·', '•']);\n\nfunction isNoise(n: SnapshotNode): boolean {\n const kind = n.type ?? n.role ?? '';\n if (!n.label) return false;\n return (kind === 'StaticText' || kind === 'Other') && NOISE_LABELS.has(n.label.trim());\n}\n\nfunction intersectsViewport(rect: Rect | undefined, vw: number, vh: number): boolean {\n if (!rect) return true;\n return rect.x < vw && rect.y < vh && rect.x + rect.width > 0 && rect.y + rect.height > 0;\n}\n\n// Longest label/value the renderer emits verbatim. Longer text is cut WITH an\n// explicit \"[truncated]\" marker — a silently shortened value reads as the\n// field's full content and sends the model verifying against a phantom.\nconst RENDER_TEXT_MAX = 160;\n\nfunction renderText(s: string): string {\n return s.length <= RENDER_TEXT_MAX\n ? JSON.stringify(s)\n : `${JSON.stringify(s.slice(0, RENDER_TEXT_MAX))} [truncated]`;\n}\n\nfunction formatNode(n: SnapshotNode, opts: { suppressFocused: boolean; vw?: number | undefined }): string {\n const role = n.role ?? n.type ?? 'element';\n const ref = n.ref && !n.ref.startsWith('@') ? `@${n.ref}` : (n.ref ?? '');\n const parts = [`${ref} [${role}]`];\n const label = n.label ?? n.identifier;\n if (label) parts.push(renderText(label));\n if (n.value && n.value !== n.label) parts.push(`value=${renderText(n.value)}`);\n if (n.rect)\n parts.push(\n `(${Math.round(n.rect.x)},${Math.round(n.rect.y)} ${Math.round(n.rect.width)}x${Math.round(n.rect.height)})`,\n );\n // Rendered nodes always intersect the viewport, but a carousel/pager item can\n // straddle the edge with its CENTER off-screen horizontally — where a\n // center-targeted tap misses. Say so instead of letting the line imply a\n // normally tappable element.\n if (n.rect && opts.vw !== undefined) {\n const cx = n.rect.x + n.rect.width / 2;\n if (cx < 0 || cx > opts.vw) parts.push('(center off-screen)');\n }\n if (n.enabled === false) parts.push('(disabled)');\n if (n.selected) parts.push('(selected)');\n if (n.focused && !opts.suppressFocused) parts.push('(focused)');\n if (n.interactionBlocked) parts.push(`(blocked: ${n.interactionBlocked})`);\n return parts.join(' ');\n}\n\n// The on-screen, non-noise elements plus off-viewport counts — the shared core\n// of both the full render (compressNodes) and the delta render.\nfunction keptViewportNodes(nodes: SnapshotNode[]): {\n kept: SnapshotNode[];\n above: number;\n below: number;\n suppressFocused: boolean;\n vw: number;\n} {\n const root = nodes.find((n) => (n.type === 'Application' || n.type === 'Window') && n.rect);\n const vw = root?.rect?.width ?? 500;\n const vh = root?.rect?.height ?? 1000;\n\n // The XCTest tree sometimes marks every node focused — meaningless; only\n // show (focused) when it identifies a minority of elements.\n const focusedCount = nodes.filter((n) => n.focused).length;\n const suppressFocused = focusedCount > nodes.length / 3;\n\n const kept: SnapshotNode[] = [];\n let above = 0;\n let below = 0;\n for (const n of nodes) {\n if (isNoise(n)) continue;\n if (!intersectsViewport(n.rect, vw, vh)) {\n if (n.rect && n.rect.y >= vh) below += 1;\n else above += 1;\n continue;\n }\n kept.push(n);\n }\n return { kept, above, below, suppressFocused, vw };\n}\n\nfunction compressNodes(nodes: SnapshotNode[]): string {\n const { kept, above, below, suppressFocused, vw } = keptViewportNodes(nodes);\n const lines = kept.map((n) => formatNode(n, { suppressFocused, vw }));\n if (above > 0) lines.unshift(`[${above} elements above the viewport — scroll up to reach them]`);\n if (below > 0) lines.push(`[${below} elements below the viewport — scroll down to reach them]`);\n return lines.join('\\n');\n}\n\n// --- Observation delta rendering (LLM-loop token saver) --------------------\n// Re-serializing the whole compressed tree on every observe is the dominant\n// token cost of a long agent loop (research brief 3: LLM round-trips are\n// 75-94% of task latency). When the screen is structurally identical to the\n// last render — same elements, same order, so @refs are unchanged — we emit\n// only the value/state changes plus an \"unchanged\" note instead of the full\n// tree. This is SAFE BY CONSTRUCTION: iOS @refs are assigned by traversal\n// order, so ANY add/remove/reorder rotates them; we detect that via ordered-\n// key equality and fall back to the full tree, which re-establishes valid\n// refs. The delta path therefore only fires when refs are provably stable\n// (the toggle / settings re-observe case); scrolls and screen changes render\n// full. This is a rendering optimization only — the driver's structured\n// element accessors (interactiveElements/findElement) are unaffected.\n\n/** The delta renderer's baseline: last rendered app, element keys, and lines. */\nexport type RenderState = { app?: string | undefined; keys: string[]; lineByKey: Map<string, string> };\n\n// Identity of an element that is stable across a value/state change (so a\n// flipped toggle keeps its key) but distinguishes different elements. Value is\n// deliberately excluded; the formatted line carries value/state for diffing.\nfunction elementKey(n: SnapshotNode): string {\n const role = n.role ?? n.type ?? 'element';\n const label = (n.label ?? n.identifier ?? '').trim();\n const pos = n.rect ? `${Math.round(n.rect.x)},${Math.round(n.rect.y)}` : '';\n return `${role}|${label}|${pos}`;\n}\n\nfunction arraysEqual(a: string[], b: string[]): boolean {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;\n return true;\n}\n\n/** A structured interactive element extracted from the snapshot cache. */\nexport type UiElement = {\n /** Snapshot-scoped element ref (normalized to the `@N` form). */\n ref: string;\n /** Visible label (or accessibility identifier when the label is empty). */\n label: string;\n /** Semantic role, e.g. \"Button\", \"Cell\", \"Switch\". */\n role: string;\n /** Current value (\"1\"/\"0\" for switches, field contents, ...). */\n value?: string | undefined;\n /** On-screen geometry when known. */\n rect?: Rect | undefined;\n /** Accessibility identifier when the app exposes one. */\n id?: string | undefined;\n /** false when the element is disabled. */\n enabled?: boolean | undefined;\n /** Reason interaction is blocked, when the tree reports one. */\n blocked?: string | undefined;\n};\n\nexport const TAPPABLE: ReadonlySet<string> = new Set([\n 'Button',\n 'Cell',\n 'Link',\n 'MenuItem',\n 'Tab',\n 'StaticText',\n 'Switch',\n]);\n\nconst EDITABLE: ReadonlySet<string> = new Set(['SearchField', 'TextField', 'SecureTextField']);\n// Multiline bodies (Notes/Messages compose areas) are TextViews — reachable by\n// setField but NOT by search (a search bar is never a TextView), so they're\n// opt-in to avoid a compose body shadowing a real search field.\nconst EDITABLE_MULTILINE: ReadonlySet<string> = new Set([...EDITABLE, 'TextView', 'TextEditor']);\n\nfunction labelTokens(s: string): string[] {\n return s\n .toLowerCase()\n .split(/[^a-z0-9]+/i)\n .filter((t) => t.length > 2);\n}\n\n// How well a query matches a label, tolerant of punctuation / spacing / word\n// order: the fraction of the label's tokens the query covers. 1.0 means the query\n// contains every significant word of the label (a pure punctuation/spacing\n// variant); a partial overlap (e.g. \"Screen Capture\" vs \"Full Screen Previews\",\n// sharing only \"screen\") scores low and is rejected.\nfunction fuzzyScore(label: string, query: string): number {\n const qt = new Set(labelTokens(query));\n const lt = labelTokens(label);\n if (!qt.size || !lt.length) return 0;\n return lt.filter((t) => qt.has(t)).length / lt.length;\n}\n\n/**\n * Does a label match a query — by substring, or a strict punctuation/spacing-\n * tolerant fuzzy match? Shared by the task layer's cached-map lookups so\n * ask/toggle tolerate rewording the same way findElement does.\n */\nexport function labelMatches(label: string, query: string): boolean {\n return label.toLowerCase().includes(query.toLowerCase()) || fuzzyScore(label, query) >= 0.75;\n}\n\n// --- Element resolution ladder (harness v2, decision doc research/10 §4) ----\n// Progressive relaxation, apply_patch-style: each rung only fires if the rung\n// above found nothing. `via` reports the match provenance so drift is visible\n// in traces. Ambiguity is a CONTRACT, not a guess: multiple distinct matches on\n// the winning rung (different role or id) return `candidates` instead of\n// silently picking one — the caller disambiguates with role/near or fails\n// loudly with the list (the Claude Code Edit-tool uniqueness pattern).\n\n/**\n * Outcome of the resolution ladder. Exactly one of: a match (`el` set, `via`\n * reporting the winning rung), an ambiguity (`el` null + `candidates` listing\n * the distinct matches — the caller disambiguates with role/near), or a miss\n * (`el` null, no candidates).\n */\nexport type Resolution = {\n /** The winning element, or null on ambiguity/miss. */\n el: UiElement | null;\n /** Match provenance — which rung won (id, exact label, substring, fuzzy). */\n via?: string | undefined;\n /** On ambiguity: the distinct elements that tied. */\n candidates?: UiElement[] | undefined;\n};\n\n/** Disambiguators accepted by the resolution ladder. */\nexport type ResolveOpts = {\n /** Restrict matches to this role (case-insensitive). */\n role?: string | undefined;\n /** Label of another element; pick the candidate geometrically closest to it. */\n near?: string | undefined;\n};\n\nfunction center(e: UiElement): { x: number; y: number } | null {\n return e.rect ? { x: e.rect.x + e.rect.width / 2, y: e.rect.y + e.rect.height / 2 } : null;\n}\n\nfunction disambiguate(matches: UiElement[], via: string, opts: ResolveOpts, els: UiElement[]): Resolution {\n let pool = matches;\n if (opts.role) {\n const byRole = pool.filter((e) => e.role.toLowerCase() === opts.role!.toLowerCase());\n if (byRole.length) pool = byRole;\n }\n if (pool.length > 1 && opts.near) {\n const anchor = els.find((e) => labelMatches(e.label, opts.near!));\n const ac = anchor ? center(anchor) : null;\n if (ac) {\n pool = [...pool].sort((a, b) => {\n const ca = center(a);\n const cb = center(b);\n const da = ca ? (ca.x - ac.x) ** 2 + (ca.y - ac.y) ** 2 : Infinity;\n const db = cb ? (cb.x - ac.x) ** 2 + (cb.y - ac.y) ** 2 : Infinity;\n return da - db;\n });\n return { el: pool[0]!, via: `${via}, nearest \"${opts.near}\"` }; // non-empty: sorted copy of pool\n }\n }\n if (pool.length === 1) return { el: pool[0]!, via };\n // Same role AND same label are pre-deduped upstream; what's left here are\n // genuinely different controls matching the same query — refuse to guess.\n return { el: null, candidates: pool, via };\n}\n\n/**\n * One screen's worth of the resolution ladder: id exact → exact label →\n * substring → fuzzy above a strict bar. This is the per-iteration body of\n * resolveElement's scroll loop, extracted so callers holding a fresh cache\n * (item-4 auto-wait) can match without scrolling. Returns `{ el: null }` with\n * no candidates when no rung matched at all.\n */\nexport function matchInElements(els: UiElement[], query: string, opts: ResolveOpts): Resolution {\n const q = query.toLowerCase();\n\n // Rung 0: exact accessibility-identifier match — the stablest anchor an\n // app exposes (survives label rewording and localization).\n const byId = els.filter((e) => e.id && e.id.toLowerCase() === q);\n if (byId.length) return disambiguate(byId, 'id', opts, els);\n\n // Rung 1: exact label (case-insensitive).\n const exact = els.filter((e) => e.label.toLowerCase() === q);\n if (exact.length) return disambiguate(exact, 'exact label', opts, els);\n\n // Rung 2: label substring.\n const sub = els.filter((e) => e.label.toLowerCase().includes(q));\n if (sub.length) return disambiguate(sub, 'label substring', opts, els);\n\n // Rung 3: best punctuation/spacing-tolerant fuzzy match above a strict bar.\n let best: UiElement | null = null;\n let bestScore = 0;\n for (const e of els) {\n const s = fuzzyScore(e.label, query);\n if (s > bestScore) {\n bestScore = s;\n best = e;\n }\n }\n if (best && bestScore >= 0.75) return { el: best, via: `fuzzy ${bestScore.toFixed(2)}` };\n\n return { el: null };\n}\n\n/** Outcome of a system-alert interaction (see `DeviceCore.handleAlert`). */\nexport type AlertOutcome = {\n /** Was an alert showing at all. */\n present: boolean;\n /** Was it cleared (accept/dismiss actions only). */\n handled?: boolean | undefined;\n /** The button that was tapped, when handled. */\n button?: string | undefined;\n /** Title/message/buttons summary of the alert. */\n description?: string | undefined;\n};\n\n// Permission / system dialogs surface in the snapshot as a type:\"Alert\" node\n// whose sibling Buttons are the choices (the alert is modal, so no other\n// buttons coexist). The daemon's system-alert command only sees an app's *own*\n// UIAlertControllers — SpringBoard-presented permission prompts (location,\n// notifications, contacts…) are invisible to it, which is why real apps stalled\n// the crawler behind a dialog it couldn't clear. Detecting the node directly\n// catches both. Button labels use a curly apostrophe (\"Don't Allow\"), so match\n// on an apostrophe-normalized form.\nconst na = (s: string): string => s.toLowerCase().replace(/[’']/g, \"'\").trim();\n// Preference order matters: for a location prompt, \"Allow While Using App\" is\n// the standard grant and must win over \"Allow Once\".\nconst ALERT_ACCEPT: readonly string[] = [\n 'allow while using app',\n 'always allow',\n 'allow',\n 'ok',\n 'yes',\n 'continue',\n 'allow once',\n 'turn on',\n 'enable',\n 'agree',\n 'accept',\n 'got it',\n 'join',\n];\nconst ALERT_DISMISS: readonly string[] = [\n \"don't allow\",\n 'not now',\n 'cancel',\n 'no thanks',\n 'no',\n 'deny',\n 'dismiss',\n 'later',\n 'skip',\n \"don't\",\n];\n\ntype AlertInfo = { title: string; message?: string | undefined; buttons: UiElement[] };\n\nfunction pickAlertButton(buttons: UiElement[], action: 'accept' | 'dismiss'): UiElement | undefined {\n const prefs = action === 'accept' ? ALERT_ACCEPT : ALERT_DISMISS;\n for (const p of prefs) {\n const hit = buttons.find((b) => na(b.label) === p);\n if (hit) return hit;\n }\n for (const p of prefs) {\n const hit = buttons.find((b) => na(b.label).includes(p));\n if (hit) return hit;\n }\n // Last resort: accepting picks any non-negative button; dismissing, any button.\n if (action === 'accept') return buttons.find((b) => !ALERT_DISMISS.some((d) => na(b.label).includes(d)));\n return buttons[0];\n}\n\nfunction describeAlert(info: AlertInfo): string {\n const head = `${info.title}${info.message ? ` ${info.message}` : ''}`.trim();\n return head + (info.buttons.length ? ` [buttons: ${info.buttons.map((b) => b.label).join(', ')}]` : '');\n}\n\nfunction normRef(ref: string): string {\n return ref.startsWith('@') ? ref : `@${ref}`;\n}\n\n/** Render any thrown value as a one-line message (appends `details.hint` when present). */\nexport function describeError(error: unknown): string {\n if (error instanceof Error && error.message) {\n const hint = (error as { details?: { hint?: string } }).details?.hint;\n return hint ? `${error.message} (${hint})` : error.message;\n }\n return String(error);\n}\n\n/**\n * The device core: one instance = one device's observe/resolve/act state,\n * driving one {@link DeviceBackend}. Everything here is portable — no\n * runtime-specific globals and no image libraries — so it runs under Node.\n * The harness's DeviceContext subclasses this and adds the cursor +\n * live-viewer layer via the onCacheUpdated hook.\n */\nexport class DeviceCore {\n /** The backend this core drives. */\n readonly backend: DeviceBackend;\n\n // Shared snapshot cache so a cursor move (highlight an element) doesn't need\n // a fresh accessibility snapshot — observe() populates it; the cursor tools\n // reuse it for element geometry and box overlays.\n protected cachedNodes: SnapshotNode[] = [];\n protected cachedViewport = { width: 390, height: 844 };\n protected lastApp: { app?: string | undefined; bundleId?: string | undefined } = {};\n private lastRender: RenderState | null = null;\n // Freshness stamp of the snapshot cache (item-4 auto-wait reads this).\n protected cacheAt = 0;\n\n constructor(backend: DeviceBackend) {\n this.backend = backend;\n }\n\n // Hook for harness-side live-viewer publication: called after every snapshot\n // cache update. The base core has no viewer, so this is a no-op.\n protected onCacheUpdated(): void {}\n\n /**\n * Canonical post-action report for LLM tool results, shared by every tool\n * surface (agent tools + MCP): verdict from the action's own evidence, then a\n * delta-rendered view of the screen it left behind.\n */\n async renderActionResult(prefix: string, evidence?: ActionEvidence, refresh = false): Promise<string> {\n if (refresh) await this.observe(); // refresh the cache; renderObservation reads it\n const verdict = evidence?.detail ? ` (${evidence.detail})` : '';\n return `${prefix}${verdict}\\n\\nCurrent screen (app: ${this.currentApp() ?? 'unknown'}):\\n${this.renderObservation()}`;\n }\n\n /**\n * Render the current cached screen for the LLM. full=true (or a structural\n * change since last render) yields the complete compressed tree; otherwise a\n * compact delta. Always updates the baseline.\n */\n renderObservation(full = false): string {\n const app = this.lastApp.app;\n const { kept, above, below, suppressFocused, vw } = keptViewportNodes(this.cachedNodes);\n const keys = kept.map(elementKey);\n const lineByKey = new Map<string, string>();\n for (const n of kept) lineByKey.set(elementKey(n), formatNode(n, { suppressFocused, vw }));\n\n const sameStructure =\n !full &&\n this.lastRender != null &&\n this.lastRender.app === app &&\n arraysEqual(this.lastRender.keys, keys) &&\n // Guard against duplicate-key collisions collapsing the maps differently.\n lineByKey.size === keys.length &&\n this.lastRender.lineByKey.size === this.lastRender.keys.length;\n\n if (sameStructure && this.lastRender) {\n const changed: string[] = [];\n for (const key of keys) {\n const now = lineByKey.get(key)!;\n const before = this.lastRender.lineByKey.get(key);\n if (before !== now) changed.push(`~ ${now}`);\n }\n this.lastRender = { app, keys, lineByKey };\n if (changed.length === 0) {\n return `Screen unchanged since last observation (${keys.length} elements).`;\n }\n return `Same screen; ${changed.length} of ${keys.length} element(s) changed:\\n${changed.join('\\n')}\\n(other elements and their @refs unchanged)`;\n }\n\n // Full render + refresh the baseline.\n this.lastRender = { app, keys, lineByKey };\n const lines = kept.map((n) => formatNode(n, { suppressFocused, vw }));\n if (above > 0) lines.unshift(`[${above} elements above the viewport — scroll up to reach them]`);\n if (below > 0) lines.push(`[${below} elements below the viewport — scroll down to reach them]`);\n return lines.join('\\n');\n }\n\n private cacheSnapshot(nodes: SnapshotNode[]): void {\n this.cachedNodes = nodes;\n const root = nodes.find((n) => (n.type === 'Application' || n.type === 'Window') && n.rect);\n if (root?.rect) this.cachedViewport = { width: root.rect.width, height: root.rect.height };\n this.cacheAt = Date.now();\n this.onCacheUpdated();\n }\n\n // One snapshot → cache. observe() and every action share this so we snapshot\n // once per state change instead of separately for verify + observe.\n private async refreshCache(): Promise<void> {\n const snap = await this.backend.snapshot({ interactiveOnly: true });\n this.cacheSnapshot(snap.nodes);\n this.lastApp = { app: snap.appName, bundleId: snap.appBundleId };\n }\n\n // A cheap fingerprint of the current screen to detect whether an action\n // changed anything, replacing the driver's expensive verify pass.\n private cacheSignature(): string {\n const head = this.cachedNodes\n .slice(0, 16)\n .map((n) => `${n.ref ?? ''}:${n.label ?? n.type ?? ''}`)\n .join('|');\n return `${this.cachedNodes.length}#${head}`;\n }\n\n /** Milliseconds since the cache was last refreshed (Infinity before first). */\n cacheAgeMs(): number {\n return this.cacheAt === 0 ? Number.POSITIVE_INFINITY : Date.now() - this.cacheAt;\n }\n\n /** Public fingerprint of the cached tree — the settle/verify signal. */\n stateSignature(): string {\n return this.cacheSignature();\n }\n\n /** The cached screen as a compressed {@link Observation} (no new snapshot). */\n currentElements(): Observation {\n return {\n app: this.lastApp.app,\n bundleId: this.lastApp.bundleId,\n truncated: false,\n elements: compressNodes(this.cachedNodes),\n };\n }\n\n /**\n * The frontmost app name from the last snapshot — cheap label without paying\n * the full tree compression (used by the delta renderer's callers).\n */\n currentApp(): string | undefined {\n return this.lastApp.app;\n }\n\n /**\n * Structured interactive elements from the current cache — the crawler taps\n * these by label (refs are only valid within one snapshot).\n */\n interactiveElements(): UiElement[] {\n const out: UiElement[] = [];\n const seen = new Set<string>();\n for (const n of this.cachedNodes) {\n if (!n.ref || !n.rect) continue;\n // role-first, matching the human-readable element list (a Settings row is\n // type=Button role=Cell; we treat it as its semantic role, \"Cell\").\n const role = n.role ?? n.type ?? '';\n if (!TAPPABLE.has(role)) continue;\n const label = (n.label ?? n.identifier ?? '').trim();\n if (!label) continue;\n if (n.rect.width >= this.cachedViewport.width && n.rect.height >= this.cachedViewport.height) continue;\n const key = `${role}:${label}`;\n if (seen.has(key)) continue;\n seen.add(key);\n out.push({\n ref: normRef(n.ref),\n label,\n role,\n value: n.value,\n rect: n.rect,\n id: n.identifier?.trim() || undefined,\n enabled: n.enabled,\n blocked: n.interactionBlocked,\n });\n }\n return out;\n }\n\n /**\n * Editable text inputs from the current cache. These roles are deliberately\n * excluded from interactiveElements() (they aren't \"tap\" targets), so the\n * input primitive needs its own accessor to find a search bar / text field to\n * focus. includeMultiline adds TextView bodies for form/compose filling.\n */\n inputFields(includeMultiline = false): UiElement[] {\n const editable = includeMultiline ? EDITABLE_MULTILINE : EDITABLE;\n const out: UiElement[] = [];\n for (const n of this.cachedNodes) {\n if (!n.ref || !n.rect) continue;\n const role = n.role ?? n.type ?? '';\n if (!editable.has(role)) continue;\n out.push({\n ref: normRef(n.ref),\n label: (n.label ?? n.identifier ?? '').trim(),\n role,\n value: n.value,\n rect: n.rect,\n enabled: n.enabled,\n blocked: n.interactionBlocked,\n });\n }\n return out;\n }\n\n /**\n * Run the resolution ladder against the current cache only — no scrolling,\n * no fresh snapshot. resolveElement drives this per scroll step.\n */\n resolveInCache(query: string, opts: ResolveOpts = {}): Resolution {\n return matchInElements(this.interactiveElements(), query, opts);\n }\n\n /** The full ladder: scroll to top, then match + scroll down until found or stable. */\n async resolveElement(query: string, opts: ResolveOpts = {}): Promise<Resolution> {\n await this.scrollToTop();\n for (let i = 0; i < 10; i++) {\n const r = this.resolveInCache(query, opts);\n if (r.el || r.candidates) return r;\n\n const before = this.screenSignature();\n await this.scroll('down');\n await this.observe();\n if (this.screenSignature() === before) break;\n }\n return { el: null };\n }\n\n /**\n * Compatibility wrapper: single best element or null (read paths — ask/read a\n * value — where picking the first match is low-risk). Tap paths use\n * resolveElement directly and honor the ambiguity contract.\n */\n async findElement(labelSubstring: string): Promise<UiElement | null> {\n const r = await this.resolveElement(labelSubstring);\n return r.el ?? r.candidates?.[0] ?? null;\n }\n\n /**\n * Read a labeled value. iOS list rows fold the value into the label\n * (\"iOS Version, 26.1\") or expose it as a Switch value (\"1\"/\"0\"); handle both.\n */\n async readField(labelSubstring: string): Promise<string | null> {\n const el = await this.findElement(labelSubstring);\n if (!el) return null;\n if (el.value != null && el.value !== '') return el.value;\n // \"Label, value\" pattern → take the part after the label text. If the query\n // wasn't a substring (a fuzzy match), we can't split cleanly — return the\n // whole row, which still carries the value.\n const idx = el.label.toLowerCase().indexOf(labelSubstring.toLowerCase());\n if (idx < 0) return el.label;\n const after = el.label\n .slice(idx + labelSubstring.length)\n .replace(/^[\\s,:]+/, '')\n .trim();\n return after || el.label;\n }\n\n /**\n * A structural fingerprint of the current screen that is stable across\n * dynamic content (times, battery, values) — it keys the crawler's graph\n * nodes so the same screen is recognized regardless of transient text.\n */\n screenSignature(): string {\n const title =\n this.cachedNodes.find((n) => (n.type === 'NavigationBar' || n.role === 'NavigationBar') && n.label)\n ?.label ?? '';\n const labels = this.cachedNodes\n .filter((n) => TAPPABLE.has(n.role ?? n.type ?? '') && (n.label ?? '').trim())\n .map((n) => `${n.role ?? n.type}:${(n.label ?? '').trim()}`)\n .sort();\n const uniq = [...new Set(labels)];\n return `${this.lastApp.bundleId ?? ''}|${title}|${uniq.join('~')}`;\n }\n\n /** Navigation-bar title of the cached screen ('' when absent). */\n screenTitle(): string {\n return (\n this.cachedNodes.find((n) => (n.type === 'NavigationBar' || n.role === 'NavigationBar') && n.label)\n ?.label ?? ''\n );\n }\n\n /** Take one fresh snapshot into the cache and return the compressed observation. */\n async observe(): Promise<Observation> {\n try {\n await this.refreshCache();\n return this.currentElements();\n } catch (error) {\n if (\n error instanceof SessionNotFoundError ||\n (error as { code?: string })?.code === 'SESSION_NOT_FOUND'\n ) {\n return {\n truncated: false,\n elements: 'No app session is active yet. Use open_app to launch an app first.',\n };\n }\n throw error;\n }\n }\n\n /**\n * Open an app by name/bundle id. relaunch forces a fresh launch (clean\n * initial screen) instead of just foregrounding — iOS keeps an app's\n * navigation state across foregrounding, so primitives that need a known\n * starting screen pass relaunch=true.\n */\n async openApp(app: string, relaunch = false): Promise<string> {\n const result = await this.backend.openApp({ app, relaunch });\n return `Opened ${result.appName ?? app} (${result.appBundleId ?? 'unknown bundle'})`;\n }\n\n /**\n * Level-2 of the action ladder: deep links beat tap sequences when a URL route\n * exists (maps://, app schemes, https:// universal links). XCTest sessions are\n * app-scoped, so a link that opens a different app must re-scope the session\n * to that app or observations keep tracking the old one.\n */\n async openUrl(url: string, app?: string): Promise<string> {\n const target = app ?? (await this.currentBundleId());\n await this.backend.openApp(target ? { app: target, url } : { url });\n return app ? `Opened ${url} in ${app}` : `Opened ${url}`;\n }\n\n private async currentBundleId(): Promise<string | undefined> {\n try {\n const snap = await this.backend.snapshot({ interactiveOnly: true, depth: 1 });\n return snap.appBundleId;\n } catch {\n return undefined;\n }\n }\n\n /** List installed app bundle ids. */\n async listApps(): Promise<string[]> {\n return this.backend.listApps();\n }\n\n // A tap self-diffs against our own snapshot cache: fingerprint before, tap\n // with no driver-side verify (which would cost a second snapshot pair),\n // re-snapshot once, fingerprint after. One snapshot instead of the verify\n // pass's three, and the cache is left fresh so callers don't observe again.\n private async tapAndDiff(tap: () => Promise<unknown>): Promise<ActionEvidence> {\n const before = this.cacheSignature();\n await tap();\n await this.refreshCache();\n const after = this.cacheSignature();\n const changed = before !== after;\n return {\n changed,\n detail: changed ? 'screen changed' : 'screen did NOT change — the action may have had no effect',\n };\n }\n\n /** Tap an element ref, self-diffing the cache to report whether the screen changed. */\n async press(ref: string): Promise<ActionEvidence> {\n try {\n return await this.tapAndDiff(() => this.backend.press({ ref }));\n } catch (error) {\n // The runner refuses center-targeted taps whose center is off-screen\n // (\"off-screen and not safe to press\") — but a carousel/pager item can\n // straddle the viewport edge with most of it visible and perfectly\n // tappable. Fall back to the midpoint of the VISIBLE region. Fully\n // off-screen elements still refuse (rethrow), preserving the scroll-into-\n // view recovery in tapLabel/tapControl.\n if (!/off-?screen/i.test(describeError(error))) throw error;\n const mid = this.visibleMidpoint(this.findNode(ref)?.rect);\n if (!mid) throw error;\n return this.tapAndDiff(() => this.backend.press({ x: mid.x, y: mid.y }));\n }\n }\n\n // Midpoint of the part of `rect` inside the viewport, or null when nothing\n // of it is visible.\n private visibleMidpoint(rect?: Rect): { x: number; y: number } | null {\n if (!rect) return null;\n const x1 = Math.max(rect.x, 0);\n const y1 = Math.max(rect.y, 0);\n const x2 = Math.min(rect.x + rect.width, this.cachedViewport.width);\n const y2 = Math.min(rect.y + rect.height, this.cachedViewport.height);\n if (x2 <= x1 || y2 <= y1) return null;\n return { x: Math.round((x1 + x2) / 2), y: Math.round((y1 + y2) / 2) };\n }\n\n // Fully within a safe band clear of the top nav bar and bottom tab/home area.\n protected onScreen(rect?: Rect): boolean {\n if (!rect) return false;\n const cy = rect.y + rect.height / 2;\n return cy > 56 && cy < this.cachedViewport.height - 44 && rect.x < this.cachedViewport.width;\n }\n\n /**\n * Open an app and walk its nav stack back to the root (dismissing modals), so\n * map-based navigation always starts from a known origin.\n */\n async goToRoot(app: string): Promise<void> {\n const DISMISS = ['Close', 'Cancel', 'Done', 'Not Now', 'Dismiss'];\n await this.observe().catch(() => undefined);\n if (this.lastApp.bundleId !== app) {\n await this.openApp(app);\n await this.observe();\n }\n // Real apps launch behind stacked permission prompts (see clearBlockingAlerts);\n // clear them first so the nav-stack walk below sees the actual app.\n await this.clearBlockingAlerts('accept');\n for (let i = 0; i < 12; i++) {\n const els = this.interactiveElements();\n const back = els.find((e) => e.role === 'Button' && !!e.rect && e.rect.x < 70 && e.rect.y < 110);\n const dismiss = els.find((e) => e.role === 'Button' && DISMISS.includes(e.label));\n const target = back ?? dismiss;\n if (!target) break;\n await this.press(target.ref);\n await this.observe();\n }\n // The root may be left scrolled from prior navigation; reset it to the top\n // so crawls/navigation start from a known position.\n await this.scrollToTop();\n }\n\n /** Height of the cached viewport in points. */\n viewportHeight(): number {\n return this.cachedViewport.height;\n }\n\n /**\n * Vertical span of interactive content in the current cache. Used to decide\n * whether scrolling is even necessary — scroll gestures cost ~2s each, so\n * skipping them on screens that already fit is the single biggest crawl\n * speedup.\n */\n contentBounds(): { minY: number; maxY: number } {\n let minY = Infinity;\n let maxY = -Infinity;\n for (const n of this.cachedNodes) {\n if (!n.rect) continue;\n if (!TAPPABLE.has(n.role ?? n.type ?? '')) continue;\n minY = Math.min(minY, n.rect.y);\n maxY = Math.max(maxY, n.rect.y + n.rect.height);\n }\n return { minY: minY === Infinity ? 0 : minY, maxY: maxY === -Infinity ? 0 : maxY };\n }\n\n /**\n * Tapping the status bar scrolls the active scroll view to the top — native\n * iOS behavior, one fast tap instead of multiple ~2s scroll gestures. Falls\n * back to gesture scrolling if the tap doesn't take.\n */\n async scrollToTop(): Promise<void> {\n try {\n await this.backend.press({ x: Math.round(this.cachedViewport.width / 2), y: 6 });\n await this.observe();\n return;\n } catch {\n /* fall back to gesture scroll below */\n }\n for (let i = 0; i < 6; i++) {\n const before = this.screenSignature();\n await this.scroll('up');\n await this.observe();\n if (this.screenSignature() === before) return;\n }\n }\n\n /**\n * Tap an element by its label, scrolling it into view first if it's\n * off-screen. The crawler and the map navigator use this so a target below\n * the fold (a long Settings list) is still reachable. Re-resolves the ref\n * after each scroll.\n */\n async tapLabel(label: string): Promise<boolean> {\n for (let i = 0; i < 12; i++) {\n const el = this.interactiveElements().find((e) => e.label === label);\n if (el && this.onScreen(el.rect)) {\n try {\n await this.press(el.ref);\n return true;\n } catch (error) {\n if (!/off-?screen/i.test(describeError(error))) throw error;\n // straddled the edge — fall through to a nudge scroll and retry\n }\n }\n // Known position → scroll toward it. Not in the realized tree at all →\n // sweep to the top first (rows may be scrolled past above), then scan down.\n const dir: 'up' | 'down' = el?.rect ? (el.rect.y < 0 ? 'up' : 'down') : i < 5 ? 'up' : 'down';\n await this.scroll(dir);\n await this.observe();\n }\n return false;\n }\n\n /**\n * Vision-path fallback: tap raw coordinates when the accessibility tree is\n * missing or wrong (canvas, games, custom controls). Coordinates are in the\n * same space as observe()'s rects and the screenshot pixels (@1x points).\n */\n async pressAt(x: number, y: number): Promise<ActionEvidence> {\n return this.tapAndDiff(() => this.backend.press({ x, y }));\n }\n\n /**\n * Coordinate drag: touch down at (x,y), move by (dx,dy). The primitive for\n * controls a tap can't operate — picker wheels (drag vertically on the wheel\n * column), sliders, and custom carousels. Same coordinate space as rects.\n */\n async pan(x: number, y: number, dx: number, dy: number, durationMs?: number): Promise<void> {\n await this.backend.pan(x, y, dx, dy, durationMs);\n }\n\n /**\n * Set-of-Marks visual observation: screenshot with `@ref` labels drawn on the\n * elements, so a vision model can ground itself in pixels and still act by ref.\n */\n async screenshotWithRefs(path: string): Promise<string> {\n const result = await this.backend.screenshot({ path, overlayRefs: true });\n return result.path;\n }\n\n protected async currentViewport(): Promise<{ width: number; height: number }> {\n try {\n const snap = await this.backend.snapshot({ interactiveOnly: true, depth: 1 });\n const root = snap.nodes.find((n) => (n.type === 'Application' || n.type === 'Window') && n.rect);\n return { width: root?.rect?.width ?? 390, height: root?.rect?.height ?? 844 };\n } catch {\n return { width: 390, height: 844 };\n }\n }\n\n /** Long-press an element ref. */\n async longPress(ref: string, durationMs = 800): Promise<void> {\n await this.backend.longPress(ref, durationMs);\n }\n\n /** Focus a field and replace its text, self-diffing the cache for evidence. */\n async fill(ref: string, text: string): Promise<ActionEvidence> {\n return this.tapAndDiff(() => this.backend.fill(ref, text));\n }\n\n /** Type into whatever currently has keyboard focus. */\n async typeText(text: string): Promise<void> {\n await this.backend.typeText(text);\n }\n\n /**\n * Press the keyboard's return/go key. Submits a search bar that acts on\n * Return (Safari's address bar, web forms) rather than filtering results as\n * you type.\n */\n async pressReturn(): Promise<void> {\n await this.backend.pressKey('return');\n }\n\n /** Scroll the active scroll view one step. */\n async scroll(direction: 'up' | 'down' | 'left' | 'right'): Promise<void> {\n await this.backend.scroll(direction);\n }\n\n /** Block until `text` appears on screen; returns a confirmation note. */\n async waitForText(text: string, timeoutMs = 5000): Promise<string> {\n await this.backend.waitForText(text, timeoutMs);\n return `\"${text}\" appeared on screen`;\n }\n\n // Read a modal alert (if any) from the current snapshot cache — cheap, no\n // extra snapshot, since observe() already caches the Alert node\n // (interactiveOnly keeps it).\n private alertFromCache(): AlertInfo | null {\n const alert = this.cachedNodes.find((n) => (n.type ?? n.role) === 'Alert');\n if (!alert) return null;\n const texts = this.cachedNodes\n .filter((n) => (n.type ?? n.role) === 'StaticText' && n.label)\n .map((n) => (n.label ?? '').trim());\n const buttons: UiElement[] = [];\n for (const n of this.cachedNodes) {\n if (!n.ref || !n.rect || (n.role ?? n.type) !== 'Button') continue;\n const label = (n.label ?? n.identifier ?? '').trim();\n if (label)\n buttons.push({\n ref: normRef(n.ref),\n label,\n role: 'Button',\n value: n.value,\n rect: n.rect,\n enabled: n.enabled,\n blocked: n.interactionBlocked,\n });\n }\n const title = (alert.label ?? texts[0] ?? 'Alert').trim();\n return { title, message: texts.find((t) => t !== title), buttons };\n }\n\n /**\n * System dialogs (permissions, sign-in prompts) block everything else; the\n * driver exposes them as a first-class action instead of hoping a tap lands.\n */\n async handleAlert(action: 'get' | 'accept' | 'dismiss'): Promise<AlertOutcome> {\n await this.observe().catch(() => undefined);\n const info = this.alertFromCache();\n if (info) {\n const description = describeAlert(info);\n if (action === 'get') return { present: true, description };\n const btn = pickAlertButton(info.buttons, action);\n if (!btn?.rect) return { present: true, handled: false, description };\n await this.pressAt(btn.rect.x + btn.rect.width / 2, btn.rect.y + btn.rect.height / 2);\n await this.observe().catch(() => undefined);\n const still = this.alertFromCache();\n // Handled if this alert is gone; a *different* alert surfacing (stacked\n // prompts) still counts — this one was cleared.\n return {\n present: true,\n handled: still == null || still.title !== info.title,\n button: btn.label,\n description,\n };\n }\n // Fallback: the backend's command for an app's own alert not surfaced as a node.\n try {\n const result = await this.backend.systemAlert(action);\n const alert = result.alert;\n return {\n present: alert != null,\n handled: result.handled,\n button: result.button,\n description: alert\n ? `${alert.title ?? ''} ${alert.message ?? ''}`.trim() +\n (alert.buttons?.length ? ` [buttons: ${alert.buttons.join(', ')}]` : '')\n : undefined,\n };\n } catch (error) {\n if (/alert not found/i.test(describeError(error))) return { present: false };\n throw error;\n }\n }\n\n /**\n * Clear the launch permission gauntlet — real apps stack location /\n * notification / tracking prompts on first open, each blocking the app.\n * Grants by default so the crawl sees the most surface. Returns the buttons\n * tapped. Bounded so a non-clearing dialog can't loop forever.\n */\n async clearBlockingAlerts(action: 'accept' | 'dismiss' = 'accept', max = 6): Promise<string[]> {\n const tapped: string[] = [];\n let lastTitle = '';\n for (let i = 0; i < max; i++) {\n const info = this.alertFromCache();\n if (!info) {\n await this.observe().catch(() => undefined);\n if (!this.alertFromCache()) break;\n }\n const r = await this.handleAlert(action);\n if (!r.present || !r.button || !r.handled) break;\n if (r.description === lastTitle) break; // no progress — same dialog persists\n lastTitle = r.description ?? '';\n tapped.push(r.button);\n }\n return tapped;\n }\n\n /** Go to the home screen. */\n async goHome(): Promise<void> {\n await this.backend.home();\n }\n\n /** Navigate back (nav-bar back / hardware back). */\n async goBack(): Promise<void> {\n await this.backend.back();\n }\n\n /** Save a screenshot to `path`; returns the written path. */\n async screenshot(path: string): Promise<string> {\n const result = await this.backend.screenshot({ path });\n return result.path;\n }\n\n /** Close the backend's transport session. */\n async closeSession(): Promise<void> {\n await this.backend.closeSession();\n }\n\n protected findNode(ref: string): SnapshotNode | undefined {\n const want = normRef(ref);\n return this.cachedNodes.find((n) => n.ref && normRef(n.ref) === want);\n }\n\n // Ensure the cache is fresh enough to resolve refs / draw boxes.\n protected async ensureCache(): Promise<void> {\n if (this.cachedNodes.length === 0) await this.observe();\n }\n}\n","// ---------------------------------------------------------------------------\n// %variable% secret substitution (Stagehand's pattern):\n// the model/caller plans against NAMES; values are injected at the last moment\n// before backend.fill/typeText and never rendered into Actions, results,\n// observations, or traces. Redaction is best-effort belt-and-braces — after\n// typing into a non-secure field the next snapshot's value contains the\n// secret, and redact() at observe/result assembly keeps it out of outbound\n// text. The hard guarantee is at the substitution point: values never enter\n// stored Actions by construction.\n// ---------------------------------------------------------------------------\n\nconst MIN_SECRET_LENGTH = 4;\n\n/**\n * `%variable%` secret substitution (Stagehand's pattern):\n * the model/caller plans against NAMES; values are injected at the last moment\n * before backend.fill/typeText and never rendered into Actions, results,\n * observations, or traces. Redaction is best-effort belt-and-braces; the hard\n * guarantee is at the substitution point — values never enter stored Actions\n * by construction.\n */\nexport class SecretStore {\n private readonly values = new Map<string, string>();\n\n constructor(values?: Record<string, string>) {\n if (values) for (const [k, v] of Object.entries(values)) this.set(k, v);\n }\n\n /**\n * Store a secret under `name`. Rejects values shorter than 4 chars — a\n * 2-char secret would redact innocent UI text everywhere.\n */\n set(name: string, value: string): void {\n if (value.length < MIN_SECRET_LENGTH) {\n throw new Error(`secret \"${name}\" is too short (<${MIN_SECRET_LENGTH} chars) to redact safely`);\n }\n this.values.set(name, value);\n }\n\n /** The stored secret NAMES (never the values). */\n names(): string[] {\n return [...this.values.keys()];\n }\n\n /** %name% → value. Unknown %x% stays literal. */\n substitute(text: string): string {\n return text.replace(/%([A-Za-z0-9_-]+)%/g, (whole, name: string) => this.values.get(name) ?? whole);\n }\n\n /** value → %name% across outbound text (messages, rendered observations). */\n redact(text: string): string {\n let out = text;\n for (const [name, value] of this.values) {\n out = out.split(value).join(`%${name}%`);\n }\n return out;\n }\n\n /** Per-call vars layered over the store (call-scoped, never persisted). */\n withOverrides(vars?: Record<string, string>): SecretStore {\n if (!vars || Object.keys(vars).length === 0) return this;\n const merged = new SecretStore();\n for (const [k, v] of this.values) merged.values.set(k, v);\n for (const [k, v] of Object.entries(vars)) merged.set(k, v);\n return merged;\n }\n}\n","import type { Rect, ScrollDirection } from './device.ts';\nimport {\n AbortedError,\n ActionFailedError,\n PhoneUseError,\n type PhoneUseErrorCode,\n TimeoutError,\n} from './errors.ts';\nimport {\n type DeviceCore,\n matchInElements,\n type Resolution,\n type ResolveOpts,\n TAPPABLE,\n type UiElement,\n} from './observe.ts';\nimport { SecretStore } from './secrets.ts';\n\n// ---------------------------------------------------------------------------\n// The observe→act seam: observe() returns\n// portable Action descriptors carrying RE-RESOLVABLE element queries; act()\n// re-resolves against the live tree and executes with no re-inference. A\n// compiled skill is a stored Action[]. The resolution ladder (DeviceCore) is\n// the one query engine — this module contains dispatch, auto-wait, abort, and\n// secrets wiring, never matching logic.\n//\n// Never-throw contract: executeAction returns {success:false,...} for every\n// device-legible outcome (not found, ambiguous, wait deadline, gesture\n// failure). It throws PhoneUseError subclasses only for infrastructure:\n// aborts, closed sessions on non-observe verbs, unsupported capabilities,\n// unknown errors.\n// ---------------------------------------------------------------------------\n\n/**\n * A RE-RESOLVABLE element query — how a portable {@link Action} names its\n * target. Resolved against the live tree by the resolution ladder at act()\n * time; no stale handles.\n */\nexport type ElementQuery = {\n /** Label to match (exact → substring → fuzzy, the ladder's rungs). */\n label?: string | undefined;\n /** Accessibility identifier — rung 0 of the ladder, wins when present. */\n id?: string | undefined;\n /** Disambiguator: restrict matches to this role (e.g. \"Button\"). */\n role?: string | undefined;\n /** Disambiguator: label of another element; pick the geometrically closest match. */\n near?: string | undefined;\n};\n\n/** Verbs a portable {@link Action} can carry. */\nexport type ActionVerb =\n | 'tap'\n | 'longPress'\n | 'fill'\n | 'type'\n | 'pressKey'\n | 'scroll'\n | 'openApp'\n | 'openUrl'\n | 'back'\n | 'home'\n | 'alert'\n | 'waitForText';\n\n/**\n * The observe→act seam: a portable action\n * descriptor carrying a re-resolvable {@link ElementQuery}. `observe()` returns\n * these; `act()` re-resolves against the live tree and executes with no\n * re-inference. A compiled skill is a stored `Action[]`.\n */\nexport type Action = {\n /** Versioned, documented UNSTABLE pre-1.0. */\n formatVersion: 0;\n /** What to do. */\n verb: ActionVerb;\n /** Target query for element-directed verbs (tap/longPress/fill). */\n target?: ElementQuery | undefined;\n /** Verb parameters (text, direction, app, url, ...). */\n params?:\n | {\n /** fill/type text — may contain %name% secret references. */\n text?: string | undefined;\n direction?: ScrollDirection | undefined;\n app?: string | undefined;\n url?: string | undefined;\n durationMs?: number | undefined;\n key?: 'return' | undefined;\n alertAction?: 'accept' | 'dismiss' | undefined;\n submit?: boolean | undefined;\n relaunch?: boolean | undefined;\n }\n | undefined;\n /**\n * Provenance from observe/record time. ADVISORY ONLY — act() always\n * re-resolves; this exists for traces, drift diagnosis, and human review.\n */\n observed?:\n | {\n via?: string | undefined;\n label?: string | undefined;\n role?: string | undefined;\n rect?: Rect | undefined;\n app?: string | undefined;\n screenTitle?: string | undefined;\n }\n | undefined;\n};\n\n/** The stored-Action[] artifact (public TYPE, unstable FORMAT pre-1.0). */\nexport type CompiledSkill = {\n formatVersion: 0;\n name: string;\n description?: string | undefined;\n params?: string[] | undefined;\n precondition?: string | undefined;\n actions: Action[];\n};\n\n/** An interactive element as surfaced by `observe()` (alias of {@link UiElement}). */\nexport type ObservedElement = UiElement;\n\n/** What `observe()` returns: elements, rendered text, and portable actions. */\nexport type ObserveResult = {\n /** Always true for a completed observation. */\n success: boolean;\n /** Human-readable summary of the observation. */\n message: string;\n /** Frontmost app name, when known. */\n app?: string | undefined;\n /** Frontmost app bundle id, when known. */\n bundleId?: string | undefined;\n /** Navigation-bar title of the current screen, when present. */\n screenTitle?: string | undefined;\n /** Structured channel (secret-redacted values). */\n elements: ObservedElement[];\n /** Compressed text channel (secret-redacted). */\n rendered: string;\n /** Portable descriptors: a tap per tappable, a fill per input field. */\n actions: Action[];\n};\n\n/**\n * Structured outcome of every action verb. Never-throw contract: device-legible\n * failures (not found, ambiguous, wait deadline, gesture failure) come back as\n * `{success: false, ...}`; only infrastructure errors (abort, closed session,\n * unsupported capability) throw PhoneUseError subclasses.\n */\nexport type ActionResult = {\n /** Did the action execute as intended. */\n success: boolean;\n /** Human-readable outcome (secret-redacted). */\n message: string;\n /** tapAndDiff verdict where applicable: did the screen actually change. */\n changed?: boolean | undefined;\n /** How the target resolved (match provenance, ref, label, role, rect). */\n resolved?: { via: string; ref: string; label: string; role: string; rect?: Rect | undefined } | undefined;\n /** The ambiguity contract, surfaced structurally. */\n candidates?: ObservedElement[] | undefined;\n /** Auto-wait cost when the slow path ran (elapsed ms, poll count). */\n waited?: { ms: number; polls: number } | undefined;\n /** Set on structured failures with an error flavor (e.g. TIMEOUT). */\n code?: PhoneUseErrorCode | undefined;\n};\n\n/** Per-call options accepted by every action verb. */\nexport type ActOptions = {\n /** Abort the call; the in-flight gesture may still land (state indeterminate). */\n signal?: AbortSignal | undefined;\n /** Auto-wait deadline (default 5000 ms). */\n timeoutMs?: number | undefined;\n /** Per-call secret overrides, layered on the device store. */\n vars?: Record<string, string> | undefined;\n};\n\n// --- abort plumbing ---------------------------------------------------------\n\nfunction throwIfAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted) throw new AbortedError();\n}\n\n/** Race a backend promise against the caller's abort. The abandoned in-flight\n * call may still land on the device — documented abort semantics (state\n * indeterminate); no retry follows an abort. */\nasync function raceWithAbort<T>(promise: Promise<T>, signal: AbortSignal | undefined): Promise<T> {\n if (!signal) return promise;\n throwIfAborted(signal);\n let onAbort: (() => void) | undefined;\n const aborted = new Promise<never>((_, reject) => {\n onAbort = () => reject(new AbortedError());\n signal.addEventListener('abort', onAbort, { once: true });\n });\n try {\n return await Promise.race([promise, aborted]);\n } finally {\n if (onAbort) signal.removeEventListener('abort', onAbort);\n }\n}\n\nfunction sleep(ms: number, signal: AbortSignal | undefined): Promise<void> {\n return raceWithAbort(new Promise<void>((r) => setTimeout(r, ms)), signal);\n}\n\n// --- observe-side synthesis ---------------------------------------------------\n\nfunction queryFor(el: UiElement): ElementQuery {\n return el.id ? { id: el.id } : { label: el.label };\n}\n\nfunction provenance(core: DeviceCore, el: UiElement, via?: string) {\n return {\n ...(via === undefined ? {} : { via }),\n label: el.label,\n role: el.role,\n ...(el.rect === undefined ? {} : { rect: el.rect }),\n ...(core.currentApp() === undefined ? {} : { app: core.currentApp() }),\n ...(core.screenTitle() ? { screenTitle: core.screenTitle() } : {}),\n };\n}\n\n/** Synthesize portable actions from the CURRENT cache (observe-time). */\nexport function toActions(core: DeviceCore): Action[] {\n const actions: Action[] = [];\n for (const el of core.interactiveElements()) {\n const kind = el.role;\n if (TAPPABLE.has(kind)) {\n actions.push({\n formatVersion: 0,\n verb: 'tap',\n target: queryFor(el),\n observed: provenance(core, el, el.id ? 'id' : 'exact label'),\n });\n }\n }\n for (const el of core.inputFields(true)) {\n actions.push({\n formatVersion: 0,\n verb: 'fill',\n target: queryFor(el),\n params: { text: '' },\n observed: provenance(core, el, el.id ? 'id' : 'exact label'),\n });\n }\n return actions;\n}\n\nconst NO_SECRETS = new SecretStore();\n\n/**\n * Take one fresh snapshot and assemble the full {@link ObserveResult}:\n * deduped element channel, secret-redacted rendered text, and a portable\n * Action per tappable / input field.\n */\nexport async function buildObserveResult(\n core: DeviceCore,\n secrets: SecretStore = NO_SECRETS,\n): Promise<ObserveResult> {\n const obs = await core.observe();\n const redact = (s: string) => secrets.redact(s);\n // Tappables + input fields: one structured element channel (deduped by ref).\n const seen = new Set<string>();\n const elements: ObservedElement[] = [];\n for (const el of [...core.interactiveElements(), ...core.inputFields(true)]) {\n if (seen.has(el.ref)) continue;\n seen.add(el.ref);\n elements.push({\n ...el,\n label: redact(el.label),\n ...(el.value === undefined || el.value === null ? {} : { value: redact(el.value) }),\n });\n }\n return {\n success: true,\n message: elements.length\n ? `observed ${elements.length} interactive elements`\n : obs.elements.slice(0, 120),\n ...(obs.app === undefined ? {} : { app: obs.app }),\n ...(obs.bundleId === undefined ? {} : { bundleId: obs.bundleId }),\n ...(core.screenTitle() ? { screenTitle: core.screenTitle() } : {}),\n elements,\n rendered: redact(core.renderObservation(true)),\n actions: toActions(core),\n };\n}\n\n// --- act-side dispatch ---------------------------------------------------------\n\nfunction toResolveOpts(q: ElementQuery): ResolveOpts {\n return {\n ...(q.role === undefined ? {} : { role: q.role }),\n ...(q.near === undefined ? {} : { near: q.near }),\n };\n}\n\nfunction queryText(q: ElementQuery): string {\n const t = q.id ?? q.label;\n if (t === undefined || t === '') {\n throw new ActionFailedError('action target needs an id or label');\n }\n return t;\n}\n\nfunction isActionable(el: UiElement): boolean {\n return el.enabled !== false && !el.blocked;\n}\n\nconst CACHE_FRESH_MS = 2000;\nconst POLL_STEPS_MS = [150, 300, 600, 800];\n\ntype WaitOutcome =\n | { ok: true; el: UiElement; via: string; waited: { ms: number; polls: number } | undefined }\n | { ok: false; result: ActionResult };\n\n/**\n * Resolve + auto-wait (visible+hittable+enabled+settled on every\n * action, no caller sleep — and it must not double latency).\n * Fast path: a fresh cache resolving to an actionable target executes with\n * ZERO extra snapshots. Slow path: poll in place (never scroll — scrolling is\n * the ladder's job, and polling must not dismiss transient menus) until the\n * target is actionable AND the tree signature is stable between polls.\n */\nasync function resolveWithWait(\n core: DeviceCore,\n q: ElementQuery,\n opts: ActOptions,\n pool: 'tappable' | 'fields',\n): Promise<WaitOutcome> {\n const signal = opts.signal;\n const deadline = Date.now() + (opts.timeoutMs ?? 5000);\n const text = queryText(q);\n const rOpts = toResolveOpts(q);\n // Tap targets resolve against interactive (tappable) elements; fill targets\n // against input fields — two pools, one matcher (the ladder's rungs).\n const inCache = (): Resolution =>\n pool === 'fields'\n ? matchInElements(core.inputFields(true), text, rOpts)\n : core.resolveInCache(text, rOpts);\n\n // Fast path: fresh cache + actionable target → go now, zero snapshots.\n if (core.cacheAgeMs() < CACHE_FRESH_MS) {\n const r = inCache();\n if (r.el && isActionable(r.el)) return { ok: true, el: r.el, via: r.via ?? 'cache', waited: undefined };\n if (r.candidates?.length) return { ok: false, result: ambiguityResult(text, r) };\n }\n\n // Not in the (possibly stale) cache at all. For tappables, run one full\n // ladder pass (scroll search) — not-on-screen is a search problem;\n // not-yet-enabled is a wait problem. Fields skip the scroll ladder (fields\n // live on the current form) and go straight to the poll.\n throwIfAborted(signal);\n let r: Resolution;\n if (pool === 'tappable') {\n r = await raceWithAbort(core.resolveElement(text, rOpts), signal);\n } else {\n await raceWithAbort(core.observe(), signal);\n r = inCache();\n }\n if (!r.el && r.candidates?.length) return { ok: false, result: ambiguityResult(text, r) };\n if (r.el && isActionable(r.el)) return { ok: true, el: r.el, via: r.via ?? 'ladder', waited: undefined };\n\n // Wait loop: poll in place until actionable + settled, or deadline.\n const started = Date.now();\n let polls = 0;\n let lastSig = core.stateSignature();\n let step = 0;\n while (Date.now() < deadline) {\n await sleep(POLL_STEPS_MS[Math.min(step, POLL_STEPS_MS.length - 1)]!, signal);\n step++;\n polls++;\n throwIfAborted(signal);\n await raceWithAbort(core.observe(), signal);\n const sig = core.stateSignature();\n const settled = sig === lastSig;\n lastSig = sig;\n const rr = inCache();\n if (rr.el && isActionable(rr.el) && settled) {\n return { ok: true, el: rr.el, via: rr.via ?? 'wait', waited: { ms: Date.now() - started, polls } };\n }\n if (!rr.el && rr.candidates?.length) return { ok: false, result: ambiguityResult(text, rr) };\n r = rr;\n }\n return {\n ok: false,\n result: {\n success: false,\n code: 'TIMEOUT',\n message: r.el\n ? `timed out after ${opts.timeoutMs ?? 5000}ms waiting for \"${text}\" to become enabled/settled`\n : `timed out after ${opts.timeoutMs ?? 5000}ms — no element matching \"${text}\" on this screen`,\n waited: { ms: Date.now() - started, polls },\n },\n };\n}\n\nfunction ambiguityResult(text: string, r: Resolution): ActionResult {\n const list = (r.candidates ?? [])\n .map(\n (c) => `${c.role} \"${c.label}\"${c.rect ? ` at (${Math.round(c.rect.x)},${Math.round(c.rect.y)})` : ''}`,\n )\n .join('; ');\n return {\n success: false,\n message: `\"${text}\" is ambiguous — ${r.candidates?.length ?? 0} matches: ${list}. Disambiguate with role or near.`,\n candidates: r.candidates ?? [],\n };\n}\n\nfunction resolvedOf(el: UiElement, via: string) {\n return {\n via,\n ref: el.ref,\n label: el.label,\n role: el.role,\n ...(el.rect === undefined ? {} : { rect: el.rect }),\n };\n}\n\n/**\n * THE dispatcher: resolve → auto-wait → execute → diff. One brain — used by\n * device.tap/type/act, and (items 5-6) by the harness and the skill runner.\n */\nexport async function executeAction(\n core: DeviceCore,\n action: Action,\n opts: ActOptions = {},\n secrets: SecretStore = NO_SECRETS,\n): Promise<ActionResult> {\n const signal = opts.signal;\n throwIfAborted(signal);\n const store = secrets.withOverrides(opts.vars);\n const redact = (s: string) => store.redact(s);\n\n try {\n switch (action.verb) {\n case 'tap':\n case 'longPress':\n case 'fill': {\n if (!action.target) return { success: false, message: `${action.verb} needs a target query` };\n const wait = await resolveWithWait(\n core,\n action.target,\n opts,\n action.verb === 'fill' ? 'fields' : 'tappable',\n );\n if (!wait.ok) return wait.result;\n const { el, via, waited } = wait;\n if (action.verb === 'longPress') {\n await raceWithAbort(core.longPress(el.ref, action.params?.durationMs), signal);\n return {\n success: true,\n message: redact(`long-pressed \"${el.label}\"`),\n resolved: resolvedOf(el, via),\n waited,\n };\n }\n if (action.verb === 'fill') {\n const text = store.substitute(action.params?.text ?? '');\n const ev = await raceWithAbort(core.fill(el.ref, text), signal);\n if (action.params?.submit) await raceWithAbort(core.pressReturn(), signal);\n return {\n success: true,\n message: redact(`filled \"${el.label}\"${action.params?.submit ? ', pressed Return' : ''}`),\n ...(ev.changed === undefined ? {} : { changed: ev.changed }),\n resolved: resolvedOf(el, via),\n waited,\n };\n }\n const ev = await raceWithAbort(core.press(el.ref), signal);\n return {\n success: true,\n message: redact(`tapped \"${el.label}\"${ev.changed === false ? ' (no change)' : ''}`),\n ...(ev.changed === undefined ? {} : { changed: ev.changed }),\n resolved: resolvedOf(el, via),\n waited,\n };\n }\n case 'type': {\n const text = store.substitute(action.params?.text ?? '');\n await raceWithAbort(core.typeText(text), signal);\n if (action.params?.submit) await raceWithAbort(core.pressReturn(), signal);\n return { success: true, message: redact(`typed ${JSON.stringify(action.params?.text ?? '')}`) };\n }\n case 'pressKey': {\n await raceWithAbort(core.pressReturn(), signal);\n return { success: true, message: 'pressed Return' };\n }\n case 'scroll': {\n const direction = action.params?.direction ?? 'down';\n await raceWithAbort(core.scroll(direction), signal);\n await raceWithAbort(core.observe(), signal);\n return { success: true, message: `scrolled ${direction}` };\n }\n case 'openApp': {\n if (!action.params?.app) return { success: false, message: 'openApp needs params.app' };\n const note = await raceWithAbort(\n core.openApp(action.params.app, action.params.relaunch ?? false),\n signal,\n );\n return { success: true, message: note };\n }\n case 'openUrl': {\n if (!action.params?.url) return { success: false, message: 'openUrl needs params.url' };\n const note = await raceWithAbort(core.openUrl(action.params.url, action.params.app), signal);\n return { success: true, message: note };\n }\n case 'back': {\n await raceWithAbort(core.goBack(), signal);\n return { success: true, message: 'went back' };\n }\n case 'home': {\n await raceWithAbort(core.goHome(), signal);\n return { success: true, message: 'went home' };\n }\n case 'alert': {\n const outcome = await raceWithAbort(core.handleAlert(action.params?.alertAction ?? 'accept'), signal);\n if (!outcome.present) return { success: false, message: 'no system alert is showing' };\n return {\n success: outcome.handled !== false,\n message: `alert ${outcome.handled ? `handled via \"${outcome.button}\"` : 'NOT handled'}: ${outcome.description ?? ''}`,\n };\n }\n case 'waitForText': {\n if (!action.params?.text) return { success: false, message: 'waitForText needs params.text' };\n const note = await raceWithAbort(\n core.waitForText(action.params.text, opts.timeoutMs ?? 5000),\n signal,\n );\n const ok = !/did not appear|not found|timed out/i.test(note);\n return { success: ok, message: redact(note), ...(ok ? {} : { code: 'TIMEOUT' as const }) };\n }\n default:\n return { success: false, message: `unknown verb ${String((action as { verb?: unknown }).verb)}` };\n }\n } catch (error) {\n // Infrastructure failures propagate; device-legible gesture failures are\n // structured results.\n if (error instanceof AbortedError) throw error;\n if (error instanceof PhoneUseError) {\n if (error instanceof ActionFailedError || error instanceof TimeoutError) {\n return { success: false, message: redact(error.message), code: error.code };\n }\n throw error;\n }\n throw error;\n }\n}\n","import { createAgentDeviceClient } from 'agent-device';\nimport type { DeviceBackend } from '../backend.ts';\nimport { BaseDeviceBackend } from '../backend.ts';\nimport type { DeviceConfig } from '../config.ts';\nimport type {\n AlertAction,\n BackendAlertResult,\n Capability,\n OpenAppResult,\n PressTarget,\n ScrollDirection,\n Snapshot,\n} from '../device.ts';\nimport { ALL_CAPABILITIES } from '../device.ts';\nimport { toPhoneUseError } from '../errors.ts';\n\n// ---------------------------------------------------------------------------\n// The agent-device backend: the ONE place agent-device is called. Device\n// pinning is per-request in agent-device (AgentDeviceSelectionOptions), so a\n// backend holds a selection object and spreads it into every call. With no\n// config, selection is {} and the client is default-constructed — requests are\n// byte-identical to the pre-seam process-global path (booted-sim auto-detect)\n// — the backward-compat guarantee against default-selection drift.\n//\n// Every method normalizes errors via toPhoneUseError — no agent-device type\n// or error ever escapes this file.\n// ---------------------------------------------------------------------------\n\ntype AdClient = ReturnType<typeof createAgentDeviceClient>;\n\nclass AgentDeviceBackend extends BaseDeviceBackend {\n private readonly client: AdClient;\n private readonly selection: Record<string, unknown>;\n // Sessions are lazy daemon-side: nothing exists to close until a first real\n // call is made, and asking the daemon anyway would SPAWN one on hosts where\n // it isn't running (observed in the Mac verification sweep).\n private used = false;\n\n constructor(config?: DeviceConfig) {\n super('agent-device', ALL_CAPABILITIES);\n this.client = createAgentDeviceClient(\n config &&\n (config.session !== undefined ||\n config.daemonBaseUrl !== undefined ||\n config.daemonAuthToken !== undefined)\n ? {\n ...(config.session === undefined ? {} : { session: config.session }),\n ...(config.daemonBaseUrl === undefined ? {} : { daemonBaseUrl: config.daemonBaseUrl }),\n ...(config.daemonAuthToken === undefined ? {} : { daemonAuthToken: config.daemonAuthToken }),\n }\n : undefined,\n );\n this.selection = !config\n ? {}\n : {\n platform: config.platform,\n ...(config.device === undefined ? {} : { device: config.device }),\n ...(config.platform === 'ios' && config.udid !== undefined ? { udid: config.udid } : {}),\n ...(config.platform === 'ios' && config.simulatorDeviceSet !== undefined\n ? { iosSimulatorDeviceSet: config.simulatorDeviceSet }\n : {}),\n ...(config.platform === 'android' && config.serial !== undefined ? { serial: config.serial } : {}),\n };\n }\n\n private async guard<T>(capability: Capability, fn: () => Promise<T>): Promise<T> {\n if (capability !== 'closeSession') this.used = true;\n try {\n return await fn();\n } catch (error) {\n throw toPhoneUseError(error, { backend: this.backendName, capability });\n }\n }\n\n override snapshot(opts?: {\n interactiveOnly?: boolean | undefined;\n depth?: number | undefined;\n }): Promise<Snapshot> {\n return this.guard('snapshot', async () => {\n const snap = await this.client.capture.snapshot({\n ...this.selection,\n ...(opts?.interactiveOnly === undefined ? {} : { interactiveOnly: opts.interactiveOnly }),\n ...(opts?.depth === undefined ? {} : { depth: opts.depth }),\n });\n return { nodes: snap.nodes, appName: snap.appName, appBundleId: snap.appBundleId };\n });\n }\n\n override screenshot(opts: { path: string; overlayRefs?: boolean | undefined }): Promise<{ path: string }> {\n return this.guard('screenshot', async () => {\n const result = await this.client.capture.screenshot({\n ...this.selection,\n path: opts.path,\n ...(opts.overlayRefs === undefined ? {} : { overlayRefs: opts.overlayRefs }),\n });\n return { path: result.path };\n });\n }\n\n override press(target: PressTarget): Promise<void> {\n return this.guard('press', async () => {\n await this.client.interactions.press({ ...this.selection, ...target });\n });\n }\n\n override longPress(ref: string, durationMs?: number): Promise<void> {\n return this.guard('longPress', async () => {\n // settle: true preserved exactly from the pre-seam driver.\n await this.client.interactions.longPress({\n ...this.selection,\n ref,\n ...(durationMs === undefined ? {} : { durationMs }),\n settle: true,\n });\n });\n }\n\n override fill(ref: string, text: string): Promise<void> {\n return this.guard('fill', async () => {\n await this.client.interactions.fill({ ...this.selection, ref, text });\n });\n }\n\n override typeText(text: string): Promise<void> {\n return this.guard('type', async () => {\n await this.client.interactions.type({ ...this.selection, text });\n });\n }\n\n override pressKey(_key: 'return'): Promise<void> {\n return this.guard('key', async () => {\n await this.client.command.keyboard({ ...this.selection, action: 'return' });\n });\n }\n\n override scroll(direction: ScrollDirection): Promise<void> {\n return this.guard('scroll', async () => {\n const args = { ...this.selection, direction } as Parameters<AdClient['interactions']['scroll']>[0];\n await this.client.interactions.scroll(args);\n });\n }\n\n override pan(x: number, y: number, dx: number, dy: number, durationMs?: number): Promise<void> {\n return this.guard('pan', async () => {\n await this.client.interactions.pan({\n ...this.selection,\n x,\n y,\n dx,\n dy,\n ...(durationMs === undefined ? {} : { durationMs }),\n });\n });\n }\n\n override waitForText(text: string, timeoutMs?: number): Promise<void> {\n return this.guard('waitForText', async () => {\n await this.client.command.wait({\n ...this.selection,\n text,\n ...(timeoutMs === undefined ? {} : { timeoutMs }),\n });\n });\n }\n\n override systemAlert(action: AlertAction): Promise<BackendAlertResult> {\n return this.guard('alert', async () => {\n const result = (await this.client.command.alert({ ...this.selection, action })) as {\n alert?: { title?: string; message?: string; buttons?: string[] } | null;\n handled?: boolean;\n button?: string;\n };\n return { alert: result.alert, handled: result.handled, button: result.button };\n });\n }\n\n override home(): Promise<void> {\n return this.guard('home', async () => {\n await this.client.command.home({ ...this.selection });\n });\n }\n\n override back(): Promise<void> {\n return this.guard('back', async () => {\n await this.client.command.back({ ...this.selection });\n });\n }\n\n override openApp(opts: {\n app?: string | undefined;\n url?: string | undefined;\n relaunch?: boolean | undefined;\n }): Promise<OpenAppResult> {\n return this.guard('openApp', async () => {\n // Preserve the pre-seam arg branching exactly:\n // {app, relaunch} for app launches; {app, url} | {url} for deep links.\n const args =\n opts.url === undefined\n ? { app: opts.app, ...(opts.relaunch === undefined ? {} : { relaunch: opts.relaunch }) }\n : opts.app !== undefined\n ? { app: opts.app, url: opts.url }\n : { url: opts.url };\n const result = (await this.client.apps.open({ ...this.selection, ...args } as Parameters<\n AdClient['apps']['open']\n >[0])) as { appName?: string; appBundleId?: string };\n return { appName: result.appName, appBundleId: result.appBundleId };\n });\n }\n\n override listApps(): Promise<string[]> {\n return this.guard('listApps', async () => {\n const result = (await this.client.apps.list(\n Object.keys(this.selection).length\n ? (this.selection as Parameters<AdClient['apps']['list']>[0])\n : undefined,\n )) as unknown as string[];\n return result;\n });\n }\n\n override closeSession(): Promise<void> {\n if (!this.used) return Promise.resolve();\n return this.guard('closeSession', async () => {\n // Pre-seam behavior: close({}) — session override only when pinned.\n await this.client.sessions.close({ ...this.selection });\n });\n }\n}\n\n/**\n * Build the agent-device backend: the ONE place agent-device is called. Device\n * pinning is per-request in agent-device, so the backend holds a selection\n * object and spreads it into every call. With no config, selection is `{}` and\n * the client is default-constructed — requests are byte-identical to the\n * pre-seam process-global path (booted-sim auto-detect). Every method\n * normalizes errors via `toPhoneUseError`; no agent-device type or error ever\n * escapes this module.\n */\nexport function createAgentDeviceBackend(config?: DeviceConfig): DeviceBackend {\n return new AgentDeviceBackend(config);\n}\n","import { BaseDeviceBackend } from '../backend.ts';\nimport type {\n AlertAction,\n BackendAlertResult,\n Capability,\n OpenAppResult,\n PressTarget,\n ScrollDirection,\n Snapshot,\n} from '../device.ts';\nimport { ActionFailedError, DeviceNotFoundError, TimeoutError } from '../errors.ts';\n\n/**\n * A device-runner is addressed purely by URL, so it takes no DeviceConfig\n * platform/udid selection — only where to reach the runner and how to auth.\n */\nexport type DeviceRunnerConfig = {\n endpoint?: string | undefined;\n token?: string | undefined;\n timeoutMs?: number | undefined;\n};\n\nconst RUNNER_CAPABILITIES: readonly Capability[] = [\n 'snapshot',\n 'screenshot',\n 'press',\n 'fill',\n 'type',\n 'scroll',\n 'pan',\n 'openApp',\n 'home',\n];\n\n/**\n * Backend that speaks to an on-device runner: an XCTest-hosted JSON-RPC server\n * running ON the iPhone itself, which holds the automation privileges iOS\n * denies to ordinary apps.\n *\n * The endpoint is just a URL, so the same backend serves every topology:\n * - `http://127.0.0.1:45678` — port-forwarded from a paired host\n * - `http://<phone-ip>:45678` — straight over the LAN / tailnet\n * - `https://relay.example/d/<id>` — the runner dials out to a cloud relay,\n * which is what lets an agent anywhere drive the phone with no inbound\n * ports and no Mac in the loop.\n *\n * The wire format matches the shape proven by rounak/PhoneAgent: newline-free\n * JSON request/response over HTTP POST, one method per call.\n */\nexport class DeviceRunnerBackend extends BaseDeviceBackend {\n readonly #endpoint: string;\n readonly #token: string | undefined;\n readonly #timeoutMs: number;\n\n constructor(config?: DeviceRunnerConfig) {\n // BaseDeviceBackend owns backendName/capabilities — set them via super()\n // rather than redeclaring the fields.\n super('device-runner', RUNNER_CAPABILITIES);\n const endpoint = config?.endpoint ?? process.env.PHONE_USE_RUNNER_URL ?? 'http://127.0.0.1:45678';\n this.#endpoint = endpoint.replace(/\\/+$/, '');\n this.#token = config?.token ?? process.env.PHONE_USE_RUNNER_TOKEN;\n this.#timeoutMs = config?.timeoutMs ?? 30_000;\n }\n\n async #rpc<T>(method: string, params: Record<string, unknown> = {}): Promise<T> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.#timeoutMs);\n let res: Response;\n try {\n res = await fetch(this.#endpoint, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n ...(this.#token ? { authorization: `Bearer ${this.#token}` } : {}),\n },\n body: JSON.stringify({ jsonrpc: '2.0', id: Date.now(), method, params }),\n signal: controller.signal,\n });\n } catch (cause) {\n if (controller.signal.aborted) {\n throw new TimeoutError(`runner did not answer ${method} within ${this.#timeoutMs}ms`);\n }\n throw new DeviceNotFoundError(\n `cannot reach the on-device runner at ${this.#endpoint} — is it activated on the phone?`,\n { cause },\n );\n } finally {\n clearTimeout(timer);\n }\n\n if (!res.ok) {\n throw new ActionFailedError(`runner returned HTTP ${res.status} for ${method}`);\n }\n const body = (await res.json()) as { result?: T; error?: { message?: string } };\n if (body.error) {\n throw new ActionFailedError(body.error.message ?? `runner rejected ${method}`);\n }\n return body.result as T;\n }\n\n override async snapshot(opts?: {\n interactiveOnly?: boolean | undefined;\n depth?: number | undefined;\n }): Promise<Snapshot> {\n // The runner speaks its own compact wire shape; map it onto the SDK's\n // Snapshot contract so every consumer (CLI, MCP, agent, bench) is unaware\n // it is talking to a phone rather than a simulator.\n const wire = await this.#rpc<{\n app?: string;\n elements: Array<{\n ref: string;\n role?: string;\n label?: string;\n value?: string;\n enabled?: boolean;\n rect?: { x: number; y: number; w: number; h: number };\n }>;\n }>('get_tree', {\n interactiveOnly: opts?.interactiveOnly ?? false,\n depth: opts?.depth,\n });\n return {\n appBundleId: wire.app,\n appName: wire.app,\n nodes: (wire.elements ?? []).map((e) => ({\n ref: e.ref,\n role: e.role,\n type: e.role,\n label: e.label,\n value: e.value,\n enabled: e.enabled,\n rect: e.rect ? { x: e.rect.x, y: e.rect.y, width: e.rect.w, height: e.rect.h } : undefined,\n })),\n };\n }\n\n override async screenshot(opts: {\n path: string;\n overlayRefs?: boolean | undefined;\n }): Promise<{ path: string }> {\n const { base64 } = await this.#rpc<{ base64: string }>('get_screen_image', {\n overlayRefs: opts.overlayRefs ?? false,\n });\n const { writeFile } = await import('node:fs/promises');\n await writeFile(opts.path, Buffer.from(base64, 'base64'));\n return { path: opts.path };\n }\n\n override async press(target: PressTarget): Promise<void> {\n // PressTarget is {ref} | {x,y} — never a bare string, so narrow on the key.\n if ('ref' in target) {\n await this.#rpc('tap_element', { ref: target.ref });\n return;\n }\n await this.#rpc('tap', { x: target.x, y: target.y });\n }\n\n override async fill(ref: string, text: string): Promise<void> {\n await this.#rpc('enter_text', { ref, text, replace: true });\n }\n\n override async typeText(text: string): Promise<void> {\n await this.#rpc('enter_text', { text, replace: false });\n }\n\n override async scroll(direction: ScrollDirection): Promise<void> {\n await this.#rpc('scroll', { direction });\n }\n\n override async pan(x: number, y: number, dx: number, dy: number, durationMs = 300): Promise<void> {\n await this.#rpc('swipe', { x, y, dx, dy, durationMs });\n }\n\n override async home(): Promise<void> {\n await this.#rpc('home');\n }\n\n override async openApp(opts: {\n app?: string | undefined;\n url?: string | undefined;\n relaunch?: boolean | undefined;\n }): Promise<OpenAppResult> {\n return this.#rpc<OpenAppResult>('open_app', {\n app: opts.app,\n url: opts.url,\n relaunch: opts.relaunch ?? false,\n });\n }\n\n override async systemAlert(action: AlertAction): Promise<BackendAlertResult> {\n return this.#rpc<BackendAlertResult>('alert', { action });\n }\n\n override async closeSession(): Promise<void> {\n // The runner outlives any single client; nothing to tear down.\n }\n\n /** Liveness probe used by `phone-use doctor` and the relay health check. */\n async ping(): Promise<{ ok: boolean; ios?: string; device?: string }> {\n return this.#rpc('get_context');\n }\n}\n\nexport const createDeviceRunnerBackend = (config?: DeviceRunnerConfig): DeviceRunnerBackend =>\n new DeviceRunnerBackend(config);\n","import { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\n\n/** Per-call options an {@link ExecRunner} accepts. */\nexport type ExecOptions = {\n /** Kill the process after this many ms (rejects in the killed shape). */\n timeoutMs?: number | undefined;\n /** Replacement environment for the child process. */\n env?: Record<string, string> | undefined;\n};\n\n/** What an {@link ExecRunner} resolves with on exit 0. */\nexport type ExecResult = { stdout: string; stderr: string };\n\n/**\n * The process-execution seam (dependency-inject the spawn/exec runner\n * so unit tests run without the real binaries). Runners are dumb: resolve on\n * exit 0, reject with the execFile error shape otherwise — error normalization\n * to PhoneUseError happens at the call site, once.\n */\nexport type ExecRunner = (file: string, args: string[], opts?: ExecOptions) => Promise<ExecResult>;\n\nconst pExecFile = promisify(execFile);\n\nexport const defaultExecRunner: ExecRunner = async (file, args, opts) => {\n const { stdout, stderr } = await pExecFile(file, args, {\n encoding: 'utf8',\n // simctl `list devices -j` on a runtime-rich Mac can exceed the 1 MiB\n // default and fail spuriously — a failure the VPS test tier can never see.\n maxBuffer: 16 * 1024 * 1024,\n ...(opts?.timeoutMs === undefined ? {} : { timeout: opts.timeoutMs }),\n ...(opts?.env === undefined ? {} : { env: opts.env }),\n });\n return { stdout, stderr };\n};\n\n/** The execFile rejection shape runners produce (structural, for call sites). */\nexport type ExecError = Error & {\n code?: number | string | undefined;\n stdout?: string | undefined;\n stderr?: string | undefined;\n killed?: boolean | undefined;\n signal?: string | undefined;\n};\n\nexport function isExecError(err: unknown): err is ExecError {\n return err instanceof Error && ('code' in err || 'killed' in err || 'stderr' in err);\n}\n","import {\n type Action,\n type ActionResult,\n type ActOptions,\n buildObserveResult,\n type ElementQuery,\n executeAction,\n type ObserveResult,\n} from './actions.ts';\nimport type { DeviceBackend } from './backend.ts';\nimport type { Capability, ScrollDirection } from './device.ts';\nimport { SessionNotFoundError } from './errors.ts';\nimport { DeviceCore } from './observe.ts';\nimport { SecretStore } from './secrets.ts';\n\n/** The platform a {@link Device} runs on. */\nexport type DevicePlatform = 'ios' | 'android';\n/** Lifecycle state of a {@link Device} handle. */\nexport type DeviceStatus = 'running' | 'closed';\n\n/**\n * The Device lifecycle handle: id, pinned backend, close/dispose, idle lease +\n * reaper — plus the action verb surface layered onto the same type.\n * `ios.launch()` and `ios.connect()` return it; the future android engine will\n * share `createDeviceHandle`.\n */\nexport interface Device {\n /** udid (iOS) / serial (Android). */\n readonly id: string;\n /** Which platform this device runs. */\n readonly platform: DevicePlatform;\n /** Simulator/device name when known. */\n readonly name?: string | undefined;\n /** Name of the backend driving this device. */\n readonly backendName: string;\n /** The backend's declared capability set. */\n readonly capabilities: ReadonlySet<Capability>;\n /**\n * The pinned backend — `new DeviceContext(device.backend)` works today.\n * Backend calls through this handle count as activity for the idle lease.\n */\n readonly backend: DeviceBackend;\n /** true when launch() created the device — close() then also deletes it. */\n readonly createdByUs: boolean;\n /** Current lifecycle state. */\n readonly status: DeviceStatus;\n /** Sugar for `status === 'closed'`. */\n readonly isClosed: boolean;\n /** Re-arm the idle lease (ms overrides the configured window for this arm only). */\n extendLease(ms?: number): void;\n /** Canonical, idempotent shutdown. `await using` is sugar over this. */\n close(): Promise<void>;\n /** `await using` support — delegates to {@link Device.close}. */\n [Symbol.asyncDispose](): Promise<void>;\n\n // --- the action surface: flat hot path ------------------------------------\n /** Look at the screen: elements + rendered text + portable Action[]. */\n observe(opts?: { signal?: AbortSignal | undefined }): Promise<ObserveResult>;\n /** Tap by label/id query. Auto-waits; never throws for normal outcomes. */\n tap(target: string | ElementQuery, opts?: ActOptions): Promise<ActionResult>;\n /** Type text (optionally into a field resolved by query); %name% secrets substituted. */\n type(\n text: string,\n opts?: ActOptions & { field?: string | ElementQuery | undefined; submit?: boolean | undefined },\n ): Promise<ActionResult>;\n /** Execute a portable Action deterministically — no re-inference. */\n act(action: Action, opts?: ActOptions): Promise<ActionResult>;\n\n // --- grouped breadth -------------------------------------------------------\n /** App management: open by name/deep link, list installed, current app. */\n readonly apps: {\n /** Open an app by name/bundle id, or a deep link when `url` is set. */\n open(\n app: string,\n opts?: { relaunch?: boolean | undefined; url?: string | undefined; signal?: AbortSignal | undefined },\n ): Promise<ActionResult>;\n /** List installed app bundle ids. */\n list(opts?: { signal?: AbortSignal | undefined }): Promise<string[]>;\n /** The frontmost app name from the last observation (no new snapshot). */\n current(): string | undefined;\n };\n /** Screen-level verbs: scroll, screenshot, waitForText, alert, back, home. */\n readonly screen: {\n /** Scroll the active scroll view one step. */\n scroll(direction: ScrollDirection, opts?: { signal?: AbortSignal | undefined }): Promise<ActionResult>;\n /** Save a screenshot to `path`. */\n screenshot(opts: {\n path: string;\n signal?: AbortSignal | undefined;\n }): Promise<{ success: boolean; message: string; path?: string | undefined }>;\n /** Block until `text` appears on screen or the timeout elapses. */\n waitForText(\n text: string,\n opts?: { timeoutMs?: number | undefined; signal?: AbortSignal | undefined },\n ): Promise<ActionResult>;\n /** Read ('get'), accept, or dismiss a blocking system alert. */\n alert(\n action: 'get' | 'accept' | 'dismiss',\n opts?: { signal?: AbortSignal | undefined },\n ): Promise<ActionResult>;\n /** Navigate back. */\n back(opts?: { signal?: AbortSignal | undefined }): Promise<ActionResult>;\n /** Go to the home screen. */\n home(opts?: { signal?: AbortSignal | undefined }): Promise<ActionResult>;\n };\n /** %name% secret store — values substituted at execution, redacted everywhere else. */\n readonly secrets: SecretStore;\n}\n\n// The idle lease: an unref'd timer, so a LEAKED handle can never hold the\n// process open — and on expiry the reaper closes the device, so a leaked\n// handle can't poison the host with an orphaned booted sim either (the\n// bench-hang failure mode). Limits, honestly: this protects in-process leaks\n// only; a kill -9'd process orphans the sim until external cleanup — created\n// sims carry the `phone-use-` name prefix precisely so\n// `xcrun simctl list devices -j` can find and delete them.\nexport class IdleLease {\n private timer: ReturnType<typeof setTimeout> | null = null;\n private readonly windowMs: number | false;\n private readonly onExpire: () => void;\n\n constructor(windowMs: number | false, onExpire: () => void) {\n this.windowMs = windowMs;\n this.onExpire = onExpire;\n this.touch();\n }\n\n /** Re-arm with the configured window (no-op when disabled). */\n touch(): void {\n this.arm(this.windowMs);\n }\n\n /** Re-arm with a one-shot override window. */\n extend(ms?: number): void {\n this.arm(ms ?? this.windowMs);\n }\n\n private arm(ms: number | false): void {\n if (this.timer) clearTimeout(this.timer);\n this.timer = null;\n if (ms === false) return;\n const t = setTimeout(this.onExpire, ms);\n // Fake-timer objects may lack unref — guard, don't crash.\n t.unref?.();\n this.timer = t;\n }\n\n dispose(): void {\n if (this.timer) clearTimeout(this.timer);\n this.timer = null;\n }\n}\n\n/** Inputs to {@link createDeviceHandle} — what an engine supplies per device. */\nexport type CreateDeviceHandleOptions = {\n /** udid (iOS) / serial (Android). */\n id: string;\n /** Which platform the device runs. */\n platform: DevicePlatform;\n /** Simulator/device name when known. */\n name?: string | undefined;\n /** The backend pinned to this device. */\n backend: DeviceBackend;\n /** true when the engine created the device (close() then also deletes it). */\n createdByUs: boolean;\n /** Idle window in ms; false disables the lease. Default 180_000 (3m). */\n idleTimeoutMs?: number | false | undefined;\n /** Observer for reaper-initiated closes (the SDK never logs). */\n onIdleClose?: ((device: Device) => void) | undefined;\n /** Initial %name% secret values. */\n secrets?: Record<string, string> | undefined;\n /** @internal harness seam — supplies the verb core (DeviceContext extends DeviceCore). */\n coreFactory?: ((backend: DeviceBackend) => DeviceCore) | undefined;\n /** Platform teardown: shutdown (+ delete when createdByUs). */\n doClose: () => Promise<void>;\n};\n\n/**\n * Assemble a Device handle over a backend: lease/reaper, verb surface,\n * close/dispose semantics. Engine authors (ios here, android in item 7b,\n * phone-backend-* third parties) build on this; tests fabricate devices with\n * it over a FakeBackend.\n */\nexport function createDeviceHandle(opts: CreateDeviceHandleOptions): Device {\n let status: DeviceStatus = 'running';\n let closePromise: Promise<void> | null = null;\n\n const close = (): Promise<void> => {\n closePromise ??= (async () => {\n status = 'closed';\n lease.dispose();\n // Best-effort session close; a session may never have opened (agent-device\n // sessions are lazy), so swallow the not-found case.\n await opts.backend.closeSession().catch(() => undefined);\n await opts.doClose();\n })();\n return closePromise;\n };\n\n const lease = new IdleLease(opts.idleTimeoutMs ?? 180_000, () => {\n void close()\n .catch(() => undefined)\n .then(() => opts.onIdleClose?.(device));\n });\n\n // Backend calls through the handle count as lease activity — without this,\n // a long bench run driving DeviceContext(device.backend) would be reaped\n // mid-run, recreating the exact hazard the lease exists to prevent.\n const touchingBackend = new Proxy(opts.backend, {\n get(target, prop, receiver) {\n const value = Reflect.get(target, prop, receiver);\n if (typeof value !== 'function') return value;\n return (...args: unknown[]) => {\n if (status === 'running') lease.touch();\n return (value as (...a: unknown[]) => unknown).apply(target, args);\n };\n },\n });\n\n // The verb surface drives its own DeviceCore over the lease-touching proxy,\n // so every verb call counts as activity. One brain: all logic lives in\n // DeviceCore + executeAction; the Device only wires them together.\n const core = opts.coreFactory?.(touchingBackend) ?? new DeviceCore(touchingBackend);\n const secrets = new SecretStore(opts.secrets);\n\n const assertOpen = (): void => {\n if (status === 'closed') throw new SessionNotFoundError(`device ${opts.id} is closed`);\n };\n\n const toQuery = (target: string | ElementQuery): ElementQuery =>\n typeof target === 'string' ? { label: target } : target;\n\n const device: Device = {\n id: opts.id,\n platform: opts.platform,\n name: opts.name,\n backendName: opts.backend.backendName,\n capabilities: opts.backend.capabilities,\n backend: touchingBackend,\n createdByUs: opts.createdByUs,\n get status() {\n return status;\n },\n get isClosed() {\n return status === 'closed';\n },\n extendLease(ms?: number) {\n if (status === 'running') lease.extend(ms);\n },\n close,\n [Symbol.asyncDispose]: close,\n\n observe() {\n assertOpen();\n return buildObserveResult(core, secrets);\n },\n tap(target, actOpts = {}) {\n assertOpen();\n return executeAction(\n core,\n { formatVersion: 0, verb: 'tap', target: toQuery(target) },\n actOpts,\n secrets,\n );\n },\n type(text, actOpts = {}) {\n assertOpen();\n const { field, submit, ...rest } = actOpts;\n const action: Action =\n field === undefined\n ? { formatVersion: 0, verb: 'type', params: { text, submit } }\n : { formatVersion: 0, verb: 'fill', target: toQuery(field), params: { text, submit } };\n return executeAction(core, action, rest, secrets);\n },\n act(action, actOpts = {}) {\n assertOpen();\n return executeAction(core, action, actOpts, secrets);\n },\n\n apps: {\n open(app, o = {}) {\n assertOpen();\n const action: Action =\n o.url === undefined\n ? { formatVersion: 0, verb: 'openApp', params: { app, relaunch: o.relaunch } }\n : { formatVersion: 0, verb: 'openUrl', params: { app, url: o.url } };\n return executeAction(core, action, { signal: o.signal }, secrets);\n },\n list(o = {}) {\n assertOpen();\n void o;\n return core.listApps();\n },\n current() {\n return core.currentApp();\n },\n },\n screen: {\n scroll(direction, o = {}) {\n assertOpen();\n return executeAction(\n core,\n { formatVersion: 0, verb: 'scroll', params: { direction } },\n { signal: o.signal },\n secrets,\n );\n },\n async screenshot(o) {\n assertOpen();\n const path = await core.screenshot(o.path);\n return { success: true, message: `screenshot saved`, path };\n },\n waitForText(text, o = {}) {\n assertOpen();\n return executeAction(\n core,\n { formatVersion: 0, verb: 'waitForText', params: { text } },\n { signal: o.signal, timeoutMs: o.timeoutMs },\n secrets,\n );\n },\n alert(action, o = {}) {\n assertOpen();\n if (action === 'get') {\n return core.handleAlert('get').then((r) => ({\n success: r.present,\n message: r.present ? `alert: ${r.description ?? ''}` : 'no system alert is showing',\n }));\n }\n return executeAction(\n core,\n { formatVersion: 0, verb: 'alert', params: { alertAction: action } },\n { signal: o.signal },\n secrets,\n );\n },\n back(o = {}) {\n assertOpen();\n return executeAction(core, { formatVersion: 0, verb: 'back' }, { signal: o.signal }, secrets);\n },\n home(o = {}) {\n assertOpen();\n return executeAction(core, { formatVersion: 0, verb: 'home' }, { signal: o.signal }, secrets);\n },\n },\n secrets,\n };\n return device;\n}\n","import type { IosDeviceConfig } from '../config.ts';\nimport { ActionFailedError, DeviceNotFoundError, TimeoutError, toPhoneUseError } from '../errors.ts';\nimport { defaultExecRunner, type ExecRunner, isExecError } from '../exec.ts';\nimport { createDeviceHandle, type Device } from '../lifecycle.ts';\nimport { createAgentDeviceBackend } from './agent-device.ts';\n\n// ---------------------------------------------------------------------------\n// The iOS engine (engine-as-object): ios.launch() creates\n// and boots a DEDICATED simulator via simctl — no more \"whatever is booted\" —\n// and returns a Device whose backend is pinned to that udid. ios.connect()\n// reattaches; its no-arg form is the sole survivor of the old booted-sim\n// auto-detect. Scripts never branch on locality: connect(endpoint) for cloud\n// devices is reserved API — local-only for now.\n//\n// Created sims are named `phone-use-<hex>` deliberately: if a process is\n// kill -9'd, the in-process reaper can't run, and the name prefix is how\n// orphans are found (`xcrun simctl list devices -j` | filter the prefix).\n// ---------------------------------------------------------------------------\n\ntype CommonIosOptions = {\n /** Custom simulator device set directory (maps to `simctl --set`). */\n simulatorDeviceSet?: string | undefined;\n /** agent-device session/daemon pinning, passed through to the backend. */\n session?: string | undefined;\n daemonBaseUrl?: string | undefined;\n daemonAuthToken?: string | undefined;\n /** Idle lease window in ms (false disables). Default 180_000 (3 min). */\n idleTimeoutMs?: number | false | undefined;\n /** Observer for reaper-initiated closes. */\n onIdleClose?: ((device: Device) => void) | undefined;\n /** Initial %name% secret values (see Device.secrets). */\n secrets?: Record<string, string> | undefined;\n /** @internal harness seam — supplies the verb core (see createDeviceHandle). */\n coreFactory?:\n | ((backend: import('../backend.ts').DeviceBackend) => import('../observe.ts').DeviceCore)\n | undefined;\n /**\n * Probe the agent-device daemon right away (one listApps) so a missing\n * daemon fails at launch instead of on first use. Default false: sessions\n * open lazily and a probe requires the daemon to exist.\n */\n failFast?: boolean | undefined;\n /** @internal test seam — DI'd process runner. */\n exec?: ExecRunner | undefined;\n};\n\n/** Options for `ios.launch()` — device type, runtime, name, boot ceiling. */\nexport type IosLaunchOptions = CommonIosOptions & {\n /** simctl device type, e.g. \"iPhone 16\" (the default). */\n deviceType?: string | undefined;\n /** simctl runtime id; omitted → newest compatible. */\n runtime?: string | undefined;\n /** Simulator name; default `phone-use-<hex>` (the orphan-discovery prefix). */\n name?: string | undefined;\n /** Boot wait ceiling for `simctl bootstatus` (default 120_000 ms). */\n bootTimeoutMs?: number | undefined;\n};\n\n/** Options for `ios.connect()`. */\nexport type IosConnectOptions = CommonIosOptions & {\n /** Boot wait ceiling when connect has to boot a shut-down sim (default 120_000 ms). */\n bootTimeoutMs?: number | undefined;\n};\n\nconst UDID_RE = /^[0-9A-F]{8}(-[0-9A-F]{4}){3}-[0-9A-F]{12}$/i;\n\ntype SimctlDeviceRow = { udid: string; state: string; name?: string; isAvailable?: boolean };\ntype SimctlList = { devices: Record<string, SimctlDeviceRow[]> };\n\nfunction simctlArgs(setPath: string | undefined, args: string[]): string[] {\n return setPath === undefined ? ['simctl', ...args] : ['simctl', '--set', setPath, ...args];\n}\n\n// Exit 149 = \"operation not allowed in current state\" (already booted /\n// already shut down). Code first, stderr regex as fallback — Apple rewords\n// messages; the numeric code is the stable signal.\nfunction isAlreadyInState(err: unknown): boolean {\n if (!isExecError(err)) return false;\n if (err.code === 149) return true;\n return /current state.*(Booted|Shutdown)/i.test(err.stderr ?? '');\n}\n\nasync function runSimctl(\n exec: ExecRunner,\n setPath: string | undefined,\n args: string[],\n opts: { timeoutMs?: number | undefined; tolerateState?: boolean | undefined } = {},\n): Promise<string> {\n try {\n const r = await exec(\n 'xcrun',\n simctlArgs(setPath, args),\n opts.timeoutMs === undefined ? undefined : { timeoutMs: opts.timeoutMs },\n );\n return r.stdout;\n } catch (err) {\n if (opts.tolerateState && isAlreadyInState(err)) return '';\n if (isExecError(err)) {\n if (err.killed || err.signal) {\n throw new TimeoutError(\n `simctl ${args[0]} timed out${opts.timeoutMs ? ` after ${opts.timeoutMs}ms` : ''}`,\n {\n cause: err,\n },\n );\n }\n throw new ActionFailedError(\n `simctl ${args[0]} failed (exit ${String(err.code ?? '?')}): ${(err.stderr ?? err.message).trim()}`,\n { details: { backendCode: String(err.code ?? 'EXEC') }, cause: err },\n );\n }\n throw toPhoneUseError(err);\n }\n}\n\nfunction parseCreatedUdid(stdout: string): string {\n const lines = stdout\n .split('\\n')\n .map((l) => l.trim())\n .filter(Boolean);\n const last = lines[lines.length - 1] ?? '';\n if (!UDID_RE.test(last)) {\n throw new ActionFailedError(\n `could not parse udid from simctl create output: ${JSON.stringify(stdout.slice(0, 200))}`,\n );\n }\n return last;\n}\n\nfunction parseList(stdout: string): SimctlDeviceRow[] {\n let parsed: SimctlList;\n try {\n parsed = JSON.parse(stdout) as SimctlList;\n } catch (err) {\n throw new ActionFailedError('could not parse simctl list output as JSON', { cause: err });\n }\n return Object.values(parsed.devices ?? {}).flat();\n}\n\nfunction makeBackendConfig(udid: string, opts: CommonIosOptions): IosDeviceConfig {\n return {\n platform: 'ios',\n udid,\n ...(opts.simulatorDeviceSet === undefined ? {} : { simulatorDeviceSet: opts.simulatorDeviceSet }),\n // The daemon binds one session to one device: a udid-pinned Device on the\n // shared \"default\" session collides with whatever bound it first (live\n // Mac finding). A udid-derived session name is what makes two Devices\n // independent; deterministic so reconnects reuse the same session.\n session: opts.session ?? `phone-use-${udid}`,\n ...(opts.daemonBaseUrl === undefined ? {} : { daemonBaseUrl: opts.daemonBaseUrl }),\n ...(opts.daemonAuthToken === undefined ? {} : { daemonAuthToken: opts.daemonAuthToken }),\n };\n}\n\nasync function bootAndWait(\n exec: ExecRunner,\n setPath: string | undefined,\n udid: string,\n bootTimeoutMs: number,\n): Promise<void> {\n await runSimctl(exec, setPath, ['boot', udid], { tolerateState: true });\n // -b boots if needed, closing the boot/bootstatus race; blocks until booted.\n await runSimctl(exec, setPath, ['bootstatus', udid, '-b'], { timeoutMs: bootTimeoutMs });\n}\n\nasync function finishHandle(\n udid: string,\n name: string | undefined,\n createdByUs: boolean,\n opts: CommonIosOptions,\n exec: ExecRunner,\n): Promise<Device> {\n const backend = createAgentDeviceBackend(makeBackendConfig(udid, opts));\n if (opts.failFast) await backend.listApps();\n return createDeviceHandle({\n id: udid,\n platform: 'ios',\n name,\n backend,\n createdByUs,\n idleTimeoutMs: opts.idleTimeoutMs,\n onIdleClose: opts.onIdleClose,\n secrets: opts.secrets,\n coreFactory: opts.coreFactory,\n doClose: async () => {\n await runSimctl(exec, opts.simulatorDeviceSet, ['shutdown', udid], { tolerateState: true });\n if (createdByUs) await runSimctl(exec, opts.simulatorDeviceSet, ['delete', udid]);\n },\n });\n}\n\n/**\n * Create and boot a DEDICATED simulator via simctl — no more \"whatever is\n * booted\" — and return a {@link Device} pinned to its udid. Created sims are\n * named `phone-use-<hex>` deliberately: if the process is kill -9'd the\n * in-process reaper can't run, and the name prefix is how orphans are found.\n * `close()` shuts the sim down AND deletes it (we created it); a failed boot\n * best-effort-deletes before rethrowing.\n */\nasync function launch(options: IosLaunchOptions = {}): Promise<Device> {\n const exec = options.exec ?? defaultExecRunner;\n const deviceType = options.deviceType ?? 'iPhone 16';\n const name = options.name ?? `phone-use-${Math.random().toString(16).slice(2, 10)}`;\n const bootTimeoutMs = options.bootTimeoutMs ?? 120_000;\n\n const createArgs = [\n 'create',\n name,\n deviceType,\n ...(options.runtime === undefined ? [] : [options.runtime]),\n ];\n const udid = parseCreatedUdid(await runSimctl(exec, options.simulatorDeviceSet, createArgs));\n\n try {\n await bootAndWait(exec, options.simulatorDeviceSet, udid, bootTimeoutMs);\n } catch (err) {\n // We created it and it never booted — best-effort delete so the failure\n // doesn't leak a sim, then rethrow the original error.\n await runSimctl(exec, options.simulatorDeviceSet, ['delete', udid]).catch(() => undefined);\n throw err;\n }\n\n return finishHandle(udid, name, true, options, exec);\n}\n\n/**\n * Reattach to an existing simulator by udid (booting it if shut down). The\n * no-arg form is the sole survivor of the old booted-sim auto-detect: it\n * attaches to the first booted, available sim. `close()` on a connected\n * device shuts it down but never deletes it.\n */\nasync function connect(udid?: string, options: IosConnectOptions = {}): Promise<Device> {\n const exec = options.exec ?? defaultExecRunner;\n const bootTimeoutMs = options.bootTimeoutMs ?? 120_000;\n\n if (udid === undefined) {\n // The surviving auto-detect: attach to the first booted, available sim.\n const rows = parseList(\n await runSimctl(exec, options.simulatorDeviceSet, ['list', 'devices', 'booted', '-j']),\n );\n const booted = rows.find((d) => d.state === 'Booted' && d.isAvailable !== false);\n if (!booted) throw new DeviceNotFoundError('no booted simulator — use ios.launch() or boot one');\n return finishHandle(booted.udid, booted.name, false, options, exec);\n }\n\n const rows = parseList(await runSimctl(exec, options.simulatorDeviceSet, ['list', 'devices', '-j']));\n const row = rows.find((d) => d.udid.toLowerCase() === udid.toLowerCase());\n if (!row) throw new DeviceNotFoundError(`no simulator with udid ${udid}`);\n if (row.state !== 'Booted') await bootAndWait(exec, options.simulatorDeviceSet, row.udid, bootTimeoutMs);\n return finishHandle(row.udid, row.name, false, options, exec);\n}\n\n/**\n * The iOS engine object (Playwright-style): `ios.launch()` for a dedicated\n * simulator, `ios.connect()` to reattach. Both return the same Device type.\n */\nexport const ios = {\n /** Create + boot a dedicated simulator and return a Device pinned to it. */\n launch,\n /** Reattach to an existing simulator (no-arg: first booted sim). */\n connect,\n} as const;\n","/**\n * @phone-use/sdk — the device runtime SDK: engine-as-object lifecycle\n * (ios.launch/connect → Device), Device backends, config, errors, capabilities,\n * and the action verb surface.\n *\n * The test double (FakeBackend) lives on the \"@phone-use/sdk/testing\" subpath,\n * deliberately not re-exported here.\n */\n/** The published package version (kept in sync with package.json by the release flow). */\nexport const VERSION = '0.2.0';\n\nexport {\n type Action,\n type ActionResult,\n type ActionVerb,\n type ActOptions,\n buildObserveResult,\n type CompiledSkill,\n type ElementQuery,\n executeAction,\n type ObservedElement,\n type ObserveResult,\n toActions,\n} from './actions.ts';\nexport {\n type BackendFactory,\n BaseDeviceBackend,\n type DeviceBackend,\n getBackendFactory,\n listBackends,\n registerBackend,\n} from './backend.ts';\nexport { createAgentDeviceBackend } from './backends/agent-device.ts';\nexport { createDeviceRunnerBackend, DeviceRunnerBackend } from './backends/device-runner.ts';\nexport { type IosConnectOptions, type IosLaunchOptions, ios } from './backends/ios.ts';\nexport type { AndroidDeviceConfig, CommonDeviceConfig, DeviceConfig, IosDeviceConfig } from './config.ts';\nexport type {\n AlertAction,\n BackendAlertResult,\n Capability,\n OpenAppResult,\n PressTarget,\n Rect,\n ScrollDirection,\n Snapshot,\n SnapshotNode,\n} from './device.ts';\nexport { ALL_CAPABILITIES } from './device.ts';\nexport {\n AbortedError,\n ActionFailedError,\n DeviceInUseError,\n DeviceNotFoundError,\n PhoneUseError,\n type PhoneUseErrorCode,\n type PhoneUseErrorDetails,\n SessionNotFoundError,\n TimeoutError,\n toPhoneUseError,\n UnsupportedCapabilityError,\n} from './errors.ts';\nexport {\n type CreateDeviceHandleOptions,\n createDeviceHandle,\n type Device,\n type DevicePlatform,\n type DeviceStatus,\n} from './lifecycle.ts';\nexport type {\n ActionEvidence,\n AlertOutcome,\n Observation,\n RenderState,\n Resolution,\n ResolveOpts,\n UiElement,\n} from './observe.ts';\nexport { DeviceCore, describeError, labelMatches, matchInElements } from './observe.ts';\nexport { SecretStore } from './secrets.ts';\n\n// Built-in backend registration — explicit, here, so importing the barrel\n// registers it (documented; sideEffects:false refers to bundler tree-shaking\n// of the *published* dist, where the barrel is the entry).\nimport { registerBackend as _register } from './backend.ts';\nimport { createAgentDeviceBackend as _createAd } from './backends/agent-device.ts';\n\n_register('agent-device', _createAd);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["#endpoint","#token","#timeoutMs","#rpc","_register","_createAd"],"sources":["../src/observe.ts","../src/secrets.ts","../src/actions.ts","../src/backends/agent-device.ts","../src/backends/cloud-sandbox.ts","../src/backends/device-runner.ts","../src/exec.ts","../src/lifecycle.ts","../src/backends/ios.ts","../src/index.ts"],"sourcesContent":["import type { DeviceBackend } from './backend.ts';\nimport type { Rect, SnapshotNode } from './device.ts';\nimport { SessionNotFoundError } from './errors.ts';\n\n// ---------------------------------------------------------------------------\n// DeviceCore: the one-brain observe/resolve/act core, moved\n// verbatim from the harness's DeviceContext. Everything here is portable —\n// no runtime-specific globals and no image libraries — so it runs under Node. The\n// module level holds only types, pure functions, and read-only lookup tables;\n// the harness's DeviceContext subclasses this and layers on cursor/live-view\n// rendering.\n// ---------------------------------------------------------------------------\n\n/** One compressed observation: the frontmost app plus the rendered element list. */\nexport type Observation = {\n /** Frontmost app name, when known. */\n app?: string | undefined;\n /** Frontmost app bundle id, when known. */\n bundleId?: string | undefined;\n /** Whether the element list was truncated. */\n truncated: boolean;\n /** The compressed, human/LLM-readable element listing. */\n elements: string;\n};\n\n/**\n * Post-action evidence from the driver's verify pass: whether the\n * accessibility tree changed, without paying for a full follow-up snapshot.\n */\nexport type ActionEvidence = {\n /** Did the tree fingerprint change across the action. */\n changed?: boolean | undefined;\n /** Human-readable verdict detail. */\n detail?: string | undefined;\n};\n\n// Raw iOS accessibility trees are unusable for agents on content-heavy screens\n// (a full HN page is 485 nodes / ~15k tokens, most of it \"|\" separators and\n// off-screen rows). observe() reduces to what a human sees: on-screen,\n// non-noise elements with compact geometry, plus counts for what's off-screen.\nconst NOISE_LABELS: ReadonlySet<string> = new Set(['|', '(', ')', ',', '·', '•']);\n\nfunction isNoise(n: SnapshotNode): boolean {\n const kind = n.type ?? n.role ?? '';\n if (!n.label) return false;\n return (kind === 'StaticText' || kind === 'Other') && NOISE_LABELS.has(n.label.trim());\n}\n\nfunction intersectsViewport(rect: Rect | undefined, vw: number, vh: number): boolean {\n if (!rect) return true;\n return rect.x < vw && rect.y < vh && rect.x + rect.width > 0 && rect.y + rect.height > 0;\n}\n\n// Longest label/value the renderer emits verbatim. Longer text is cut WITH an\n// explicit \"[truncated]\" marker — a silently shortened value reads as the\n// field's full content and sends the model verifying against a phantom.\nconst RENDER_TEXT_MAX = 160;\n\nfunction renderText(s: string): string {\n return s.length <= RENDER_TEXT_MAX\n ? JSON.stringify(s)\n : `${JSON.stringify(s.slice(0, RENDER_TEXT_MAX))} [truncated]`;\n}\n\nfunction formatNode(n: SnapshotNode, opts: { suppressFocused: boolean; vw?: number | undefined }): string {\n const role = n.role ?? n.type ?? 'element';\n const ref = n.ref && !n.ref.startsWith('@') ? `@${n.ref}` : (n.ref ?? '');\n const parts = [`${ref} [${role}]`];\n const label = n.label ?? n.identifier;\n if (label) parts.push(renderText(label));\n if (n.value && n.value !== n.label) parts.push(`value=${renderText(n.value)}`);\n if (n.rect)\n parts.push(\n `(${Math.round(n.rect.x)},${Math.round(n.rect.y)} ${Math.round(n.rect.width)}x${Math.round(n.rect.height)})`,\n );\n // Rendered nodes always intersect the viewport, but a carousel/pager item can\n // straddle the edge with its CENTER off-screen horizontally — where a\n // center-targeted tap misses. Say so instead of letting the line imply a\n // normally tappable element.\n if (n.rect && opts.vw !== undefined) {\n const cx = n.rect.x + n.rect.width / 2;\n if (cx < 0 || cx > opts.vw) parts.push('(center off-screen)');\n }\n if (n.enabled === false) parts.push('(disabled)');\n if (n.selected) parts.push('(selected)');\n if (n.focused && !opts.suppressFocused) parts.push('(focused)');\n if (n.interactionBlocked) parts.push(`(blocked: ${n.interactionBlocked})`);\n return parts.join(' ');\n}\n\n// The on-screen, non-noise elements plus off-viewport counts — the shared core\n// of both the full render (compressNodes) and the delta render.\nfunction keptViewportNodes(nodes: SnapshotNode[]): {\n kept: SnapshotNode[];\n above: number;\n below: number;\n suppressFocused: boolean;\n vw: number;\n} {\n const root = nodes.find((n) => (n.type === 'Application' || n.type === 'Window') && n.rect);\n const vw = root?.rect?.width ?? 500;\n const vh = root?.rect?.height ?? 1000;\n\n // The XCTest tree sometimes marks every node focused — meaningless; only\n // show (focused) when it identifies a minority of elements.\n const focusedCount = nodes.filter((n) => n.focused).length;\n const suppressFocused = focusedCount > nodes.length / 3;\n\n const kept: SnapshotNode[] = [];\n let above = 0;\n let below = 0;\n for (const n of nodes) {\n if (isNoise(n)) continue;\n if (!intersectsViewport(n.rect, vw, vh)) {\n if (n.rect && n.rect.y >= vh) below += 1;\n else above += 1;\n continue;\n }\n kept.push(n);\n }\n return { kept, above, below, suppressFocused, vw };\n}\n\nfunction compressNodes(nodes: SnapshotNode[]): string {\n const { kept, above, below, suppressFocused, vw } = keptViewportNodes(nodes);\n const lines = kept.map((n) => formatNode(n, { suppressFocused, vw }));\n if (above > 0) lines.unshift(`[${above} elements above the viewport — scroll up to reach them]`);\n if (below > 0) lines.push(`[${below} elements below the viewport — scroll down to reach them]`);\n return lines.join('\\n');\n}\n\n// --- Observation delta rendering (LLM-loop token saver) --------------------\n// Re-serializing the whole compressed tree on every observe is the dominant\n// token cost of a long agent loop (research brief 3: LLM round-trips are\n// 75-94% of task latency). When the screen is structurally identical to the\n// last render — same elements, same order, so @refs are unchanged — we emit\n// only the value/state changes plus an \"unchanged\" note instead of the full\n// tree. This is SAFE BY CONSTRUCTION: iOS @refs are assigned by traversal\n// order, so ANY add/remove/reorder rotates them; we detect that via ordered-\n// key equality and fall back to the full tree, which re-establishes valid\n// refs. The delta path therefore only fires when refs are provably stable\n// (the toggle / settings re-observe case); scrolls and screen changes render\n// full. This is a rendering optimization only — the driver's structured\n// element accessors (interactiveElements/findElement) are unaffected.\n\n/** The delta renderer's baseline: last rendered app, element keys, and lines. */\nexport type RenderState = { app?: string | undefined; keys: string[]; lineByKey: Map<string, string> };\n\n// Identity of an element that is stable across a value/state change (so a\n// flipped toggle keeps its key) but distinguishes different elements. Value is\n// deliberately excluded; the formatted line carries value/state for diffing.\nfunction elementKey(n: SnapshotNode): string {\n const role = n.role ?? n.type ?? 'element';\n const label = (n.label ?? n.identifier ?? '').trim();\n const pos = n.rect ? `${Math.round(n.rect.x)},${Math.round(n.rect.y)}` : '';\n return `${role}|${label}|${pos}`;\n}\n\nfunction arraysEqual(a: string[], b: string[]): boolean {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;\n return true;\n}\n\n/** A structured interactive element extracted from the snapshot cache. */\nexport type UiElement = {\n /** Snapshot-scoped element ref (normalized to the `@N` form). */\n ref: string;\n /** Visible label (or accessibility identifier when the label is empty). */\n label: string;\n /** Semantic role, e.g. \"Button\", \"Cell\", \"Switch\". */\n role: string;\n /** Current value (\"1\"/\"0\" for switches, field contents, ...). */\n value?: string | undefined;\n /** On-screen geometry when known. */\n rect?: Rect | undefined;\n /** Accessibility identifier when the app exposes one. */\n id?: string | undefined;\n /** false when the element is disabled. */\n enabled?: boolean | undefined;\n /** Reason interaction is blocked, when the tree reports one. */\n blocked?: string | undefined;\n};\n\nexport const TAPPABLE: ReadonlySet<string> = new Set([\n 'Button',\n 'Cell',\n 'Link',\n 'MenuItem',\n 'Tab',\n 'StaticText',\n 'Switch',\n]);\n\nconst EDITABLE: ReadonlySet<string> = new Set(['SearchField', 'TextField', 'SecureTextField']);\n// Multiline bodies (Notes/Messages compose areas) are TextViews — reachable by\n// setField but NOT by search (a search bar is never a TextView), so they're\n// opt-in to avoid a compose body shadowing a real search field.\nconst EDITABLE_MULTILINE: ReadonlySet<string> = new Set([...EDITABLE, 'TextView', 'TextEditor']);\n\nfunction labelTokens(s: string): string[] {\n return s\n .toLowerCase()\n .split(/[^a-z0-9]+/i)\n .filter((t) => t.length > 2);\n}\n\n// How well a query matches a label, tolerant of punctuation / spacing / word\n// order: the fraction of the label's tokens the query covers. 1.0 means the query\n// contains every significant word of the label (a pure punctuation/spacing\n// variant); a partial overlap (e.g. \"Screen Capture\" vs \"Full Screen Previews\",\n// sharing only \"screen\") scores low and is rejected.\nfunction fuzzyScore(label: string, query: string): number {\n const qt = new Set(labelTokens(query));\n const lt = labelTokens(label);\n if (!qt.size || !lt.length) return 0;\n return lt.filter((t) => qt.has(t)).length / lt.length;\n}\n\n/**\n * Does a label match a query — by substring, or a strict punctuation/spacing-\n * tolerant fuzzy match? Shared by the task layer's cached-map lookups so\n * ask/toggle tolerate rewording the same way findElement does.\n */\nexport function labelMatches(label: string, query: string): boolean {\n return label.toLowerCase().includes(query.toLowerCase()) || fuzzyScore(label, query) >= 0.75;\n}\n\n// --- Element resolution ladder (harness v2, decision doc research/10 §4) ----\n// Progressive relaxation, apply_patch-style: each rung only fires if the rung\n// above found nothing. `via` reports the match provenance so drift is visible\n// in traces. Ambiguity is a CONTRACT, not a guess: multiple distinct matches on\n// the winning rung (different role or id) return `candidates` instead of\n// silently picking one — the caller disambiguates with role/near or fails\n// loudly with the list (the Claude Code Edit-tool uniqueness pattern).\n\n/**\n * Outcome of the resolution ladder. Exactly one of: a match (`el` set, `via`\n * reporting the winning rung), an ambiguity (`el` null + `candidates` listing\n * the distinct matches — the caller disambiguates with role/near), or a miss\n * (`el` null, no candidates).\n */\nexport type Resolution = {\n /** The winning element, or null on ambiguity/miss. */\n el: UiElement | null;\n /** Match provenance — which rung won (id, exact label, substring, fuzzy). */\n via?: string | undefined;\n /** On ambiguity: the distinct elements that tied. */\n candidates?: UiElement[] | undefined;\n};\n\n/** Disambiguators accepted by the resolution ladder. */\nexport type ResolveOpts = {\n /** Restrict matches to this role (case-insensitive). */\n role?: string | undefined;\n /** Label of another element; pick the candidate geometrically closest to it. */\n near?: string | undefined;\n};\n\nfunction center(e: UiElement): { x: number; y: number } | null {\n return e.rect ? { x: e.rect.x + e.rect.width / 2, y: e.rect.y + e.rect.height / 2 } : null;\n}\n\nfunction disambiguate(matches: UiElement[], via: string, opts: ResolveOpts, els: UiElement[]): Resolution {\n let pool = matches;\n if (opts.role) {\n const byRole = pool.filter((e) => e.role.toLowerCase() === opts.role!.toLowerCase());\n if (byRole.length) pool = byRole;\n }\n if (pool.length > 1 && opts.near) {\n const anchor = els.find((e) => labelMatches(e.label, opts.near!));\n const ac = anchor ? center(anchor) : null;\n if (ac) {\n pool = [...pool].sort((a, b) => {\n const ca = center(a);\n const cb = center(b);\n const da = ca ? (ca.x - ac.x) ** 2 + (ca.y - ac.y) ** 2 : Infinity;\n const db = cb ? (cb.x - ac.x) ** 2 + (cb.y - ac.y) ** 2 : Infinity;\n return da - db;\n });\n return { el: pool[0]!, via: `${via}, nearest \"${opts.near}\"` }; // non-empty: sorted copy of pool\n }\n }\n if (pool.length === 1) return { el: pool[0]!, via };\n // Same role AND same label are pre-deduped upstream; what's left here are\n // genuinely different controls matching the same query — refuse to guess.\n return { el: null, candidates: pool, via };\n}\n\n/**\n * One screen's worth of the resolution ladder: id exact → exact label →\n * substring → fuzzy above a strict bar. This is the per-iteration body of\n * resolveElement's scroll loop, extracted so callers holding a fresh cache\n * (item-4 auto-wait) can match without scrolling. Returns `{ el: null }` with\n * no candidates when no rung matched at all.\n */\nexport function matchInElements(els: UiElement[], query: string, opts: ResolveOpts): Resolution {\n const q = query.toLowerCase();\n\n // Rung 0: exact accessibility-identifier match — the stablest anchor an\n // app exposes (survives label rewording and localization).\n const byId = els.filter((e) => e.id && e.id.toLowerCase() === q);\n if (byId.length) return disambiguate(byId, 'id', opts, els);\n\n // Rung 1: exact label (case-insensitive).\n const exact = els.filter((e) => e.label.toLowerCase() === q);\n if (exact.length) return disambiguate(exact, 'exact label', opts, els);\n\n // Rung 2: label substring.\n const sub = els.filter((e) => e.label.toLowerCase().includes(q));\n if (sub.length) return disambiguate(sub, 'label substring', opts, els);\n\n // Rung 3: best punctuation/spacing-tolerant fuzzy match above a strict bar.\n let best: UiElement | null = null;\n let bestScore = 0;\n for (const e of els) {\n const s = fuzzyScore(e.label, query);\n if (s > bestScore) {\n bestScore = s;\n best = e;\n }\n }\n if (best && bestScore >= 0.75) return { el: best, via: `fuzzy ${bestScore.toFixed(2)}` };\n\n return { el: null };\n}\n\n/** Outcome of a system-alert interaction (see `DeviceCore.handleAlert`). */\nexport type AlertOutcome = {\n /** Was an alert showing at all. */\n present: boolean;\n /** Was it cleared (accept/dismiss actions only). */\n handled?: boolean | undefined;\n /** The button that was tapped, when handled. */\n button?: string | undefined;\n /** Title/message/buttons summary of the alert. */\n description?: string | undefined;\n};\n\n// Permission / system dialogs surface in the snapshot as a type:\"Alert\" node\n// whose sibling Buttons are the choices (the alert is modal, so no other\n// buttons coexist). The daemon's system-alert command only sees an app's *own*\n// UIAlertControllers — SpringBoard-presented permission prompts (location,\n// notifications, contacts…) are invisible to it, which is why real apps stalled\n// the crawler behind a dialog it couldn't clear. Detecting the node directly\n// catches both. Button labels use a curly apostrophe (\"Don't Allow\"), so match\n// on an apostrophe-normalized form.\nconst na = (s: string): string => s.toLowerCase().replace(/[’']/g, \"'\").trim();\n// Preference order matters: for a location prompt, \"Allow While Using App\" is\n// the standard grant and must win over \"Allow Once\".\nconst ALERT_ACCEPT: readonly string[] = [\n 'allow while using app',\n 'always allow',\n 'allow',\n 'ok',\n 'yes',\n 'continue',\n 'allow once',\n 'turn on',\n 'enable',\n 'agree',\n 'accept',\n 'got it',\n 'join',\n];\nconst ALERT_DISMISS: readonly string[] = [\n \"don't allow\",\n 'not now',\n 'cancel',\n 'no thanks',\n 'no',\n 'deny',\n 'dismiss',\n 'later',\n 'skip',\n \"don't\",\n];\n\ntype AlertInfo = { title: string; message?: string | undefined; buttons: UiElement[] };\n\nfunction pickAlertButton(buttons: UiElement[], action: 'accept' | 'dismiss'): UiElement | undefined {\n const prefs = action === 'accept' ? ALERT_ACCEPT : ALERT_DISMISS;\n for (const p of prefs) {\n const hit = buttons.find((b) => na(b.label) === p);\n if (hit) return hit;\n }\n for (const p of prefs) {\n const hit = buttons.find((b) => na(b.label).includes(p));\n if (hit) return hit;\n }\n // Last resort: accepting picks any non-negative button; dismissing, any button.\n if (action === 'accept') return buttons.find((b) => !ALERT_DISMISS.some((d) => na(b.label).includes(d)));\n return buttons[0];\n}\n\nfunction describeAlert(info: AlertInfo): string {\n const head = `${info.title}${info.message ? ` ${info.message}` : ''}`.trim();\n return head + (info.buttons.length ? ` [buttons: ${info.buttons.map((b) => b.label).join(', ')}]` : '');\n}\n\nfunction normRef(ref: string): string {\n return ref.startsWith('@') ? ref : `@${ref}`;\n}\n\n/** Render any thrown value as a one-line message (appends `details.hint` when present). */\nexport function describeError(error: unknown): string {\n if (error instanceof Error && error.message) {\n const hint = (error as { details?: { hint?: string } }).details?.hint;\n return hint ? `${error.message} (${hint})` : error.message;\n }\n return String(error);\n}\n\n/**\n * The device core: one instance = one device's observe/resolve/act state,\n * driving one {@link DeviceBackend}. Everything here is portable — no\n * runtime-specific globals and no image libraries — so it runs under Node.\n * The harness's DeviceContext subclasses this and adds the cursor +\n * live-viewer layer via the onCacheUpdated hook.\n */\nexport class DeviceCore {\n /** The backend this core drives. */\n readonly backend: DeviceBackend;\n\n // Shared snapshot cache so a cursor move (highlight an element) doesn't need\n // a fresh accessibility snapshot — observe() populates it; the cursor tools\n // reuse it for element geometry and box overlays.\n protected cachedNodes: SnapshotNode[] = [];\n protected cachedViewport = { width: 390, height: 844 };\n protected lastApp: { app?: string | undefined; bundleId?: string | undefined } = {};\n private lastRender: RenderState | null = null;\n // Freshness stamp of the snapshot cache (item-4 auto-wait reads this).\n protected cacheAt = 0;\n\n constructor(backend: DeviceBackend) {\n this.backend = backend;\n }\n\n // Hook for harness-side live-viewer publication: called after every snapshot\n // cache update. The base core has no viewer, so this is a no-op.\n protected onCacheUpdated(): void {}\n\n /**\n * Canonical post-action report for LLM tool results, shared by every tool\n * surface (agent tools + MCP): verdict from the action's own evidence, then a\n * delta-rendered view of the screen it left behind.\n */\n async renderActionResult(prefix: string, evidence?: ActionEvidence, refresh = false): Promise<string> {\n if (refresh) await this.observe(); // refresh the cache; renderObservation reads it\n const verdict = evidence?.detail ? ` (${evidence.detail})` : '';\n return `${prefix}${verdict}\\n\\nCurrent screen (app: ${this.currentApp() ?? 'unknown'}):\\n${this.renderObservation()}`;\n }\n\n /**\n * Render the current cached screen for the LLM. full=true (or a structural\n * change since last render) yields the complete compressed tree; otherwise a\n * compact delta. Always updates the baseline.\n */\n renderObservation(full = false): string {\n const app = this.lastApp.app;\n const { kept, above, below, suppressFocused, vw } = keptViewportNodes(this.cachedNodes);\n const keys = kept.map(elementKey);\n const lineByKey = new Map<string, string>();\n for (const n of kept) lineByKey.set(elementKey(n), formatNode(n, { suppressFocused, vw }));\n\n const sameStructure =\n !full &&\n this.lastRender != null &&\n this.lastRender.app === app &&\n arraysEqual(this.lastRender.keys, keys) &&\n // Guard against duplicate-key collisions collapsing the maps differently.\n lineByKey.size === keys.length &&\n this.lastRender.lineByKey.size === this.lastRender.keys.length;\n\n if (sameStructure && this.lastRender) {\n const changed: string[] = [];\n for (const key of keys) {\n const now = lineByKey.get(key)!;\n const before = this.lastRender.lineByKey.get(key);\n if (before !== now) changed.push(`~ ${now}`);\n }\n this.lastRender = { app, keys, lineByKey };\n if (changed.length === 0) {\n return `Screen unchanged since last observation (${keys.length} elements).`;\n }\n return `Same screen; ${changed.length} of ${keys.length} element(s) changed:\\n${changed.join('\\n')}\\n(other elements and their @refs unchanged)`;\n }\n\n // Full render + refresh the baseline.\n this.lastRender = { app, keys, lineByKey };\n const lines = kept.map((n) => formatNode(n, { suppressFocused, vw }));\n if (above > 0) lines.unshift(`[${above} elements above the viewport — scroll up to reach them]`);\n if (below > 0) lines.push(`[${below} elements below the viewport — scroll down to reach them]`);\n return lines.join('\\n');\n }\n\n private cacheSnapshot(nodes: SnapshotNode[]): void {\n this.cachedNodes = nodes;\n const root = nodes.find((n) => (n.type === 'Application' || n.type === 'Window') && n.rect);\n if (root?.rect) this.cachedViewport = { width: root.rect.width, height: root.rect.height };\n this.cacheAt = Date.now();\n this.onCacheUpdated();\n }\n\n // One snapshot → cache. observe() and every action share this so we snapshot\n // once per state change instead of separately for verify + observe.\n private async refreshCache(): Promise<void> {\n const snap = await this.backend.snapshot({ interactiveOnly: true });\n this.cacheSnapshot(snap.nodes);\n this.lastApp = { app: snap.appName, bundleId: snap.appBundleId };\n }\n\n // A cheap fingerprint of the current screen to detect whether an action\n // changed anything, replacing the driver's expensive verify pass.\n private cacheSignature(): string {\n const head = this.cachedNodes\n .slice(0, 16)\n .map((n) => `${n.ref ?? ''}:${n.label ?? n.type ?? ''}`)\n .join('|');\n return `${this.cachedNodes.length}#${head}`;\n }\n\n /** Milliseconds since the cache was last refreshed (Infinity before first). */\n cacheAgeMs(): number {\n return this.cacheAt === 0 ? Number.POSITIVE_INFINITY : Date.now() - this.cacheAt;\n }\n\n /** Public fingerprint of the cached tree — the settle/verify signal. */\n stateSignature(): string {\n return this.cacheSignature();\n }\n\n /** The cached screen as a compressed {@link Observation} (no new snapshot). */\n currentElements(): Observation {\n return {\n app: this.lastApp.app,\n bundleId: this.lastApp.bundleId,\n truncated: false,\n elements: compressNodes(this.cachedNodes),\n };\n }\n\n /**\n * The frontmost app name from the last snapshot — cheap label without paying\n * the full tree compression (used by the delta renderer's callers).\n */\n currentApp(): string | undefined {\n return this.lastApp.app;\n }\n\n /**\n * Structured interactive elements from the current cache — the crawler taps\n * these by label (refs are only valid within one snapshot).\n */\n interactiveElements(): UiElement[] {\n const out: UiElement[] = [];\n const seen = new Set<string>();\n for (const n of this.cachedNodes) {\n if (!n.ref || !n.rect) continue;\n // role-first, matching the human-readable element list (a Settings row is\n // type=Button role=Cell; we treat it as its semantic role, \"Cell\").\n const role = n.role ?? n.type ?? '';\n if (!TAPPABLE.has(role)) continue;\n const label = (n.label ?? n.identifier ?? '').trim();\n if (!label) continue;\n if (n.rect.width >= this.cachedViewport.width && n.rect.height >= this.cachedViewport.height) continue;\n const key = `${role}:${label}`;\n if (seen.has(key)) continue;\n seen.add(key);\n out.push({\n ref: normRef(n.ref),\n label,\n role,\n value: n.value,\n rect: n.rect,\n id: n.identifier?.trim() || undefined,\n enabled: n.enabled,\n blocked: n.interactionBlocked,\n });\n }\n return out;\n }\n\n /**\n * Editable text inputs from the current cache. These roles are deliberately\n * excluded from interactiveElements() (they aren't \"tap\" targets), so the\n * input primitive needs its own accessor to find a search bar / text field to\n * focus. includeMultiline adds TextView bodies for form/compose filling.\n */\n inputFields(includeMultiline = false): UiElement[] {\n const editable = includeMultiline ? EDITABLE_MULTILINE : EDITABLE;\n const out: UiElement[] = [];\n for (const n of this.cachedNodes) {\n if (!n.ref || !n.rect) continue;\n const role = n.role ?? n.type ?? '';\n if (!editable.has(role)) continue;\n out.push({\n ref: normRef(n.ref),\n label: (n.label ?? n.identifier ?? '').trim(),\n role,\n value: n.value,\n rect: n.rect,\n enabled: n.enabled,\n blocked: n.interactionBlocked,\n });\n }\n return out;\n }\n\n /**\n * Run the resolution ladder against the current cache only — no scrolling,\n * no fresh snapshot. resolveElement drives this per scroll step.\n */\n resolveInCache(query: string, opts: ResolveOpts = {}): Resolution {\n return matchInElements(this.interactiveElements(), query, opts);\n }\n\n /** The full ladder: scroll to top, then match + scroll down until found or stable. */\n async resolveElement(query: string, opts: ResolveOpts = {}): Promise<Resolution> {\n await this.scrollToTop();\n for (let i = 0; i < 10; i++) {\n const r = this.resolveInCache(query, opts);\n if (r.el || r.candidates) return r;\n\n const before = this.screenSignature();\n await this.scroll('down');\n await this.observe();\n if (this.screenSignature() === before) break;\n }\n return { el: null };\n }\n\n /**\n * Compatibility wrapper: single best element or null (read paths — ask/read a\n * value — where picking the first match is low-risk). Tap paths use\n * resolveElement directly and honor the ambiguity contract.\n */\n async findElement(labelSubstring: string): Promise<UiElement | null> {\n const r = await this.resolveElement(labelSubstring);\n return r.el ?? r.candidates?.[0] ?? null;\n }\n\n /**\n * Read a labeled value. iOS list rows fold the value into the label\n * (\"iOS Version, 26.1\") or expose it as a Switch value (\"1\"/\"0\"); handle both.\n */\n async readField(labelSubstring: string): Promise<string | null> {\n const el = await this.findElement(labelSubstring);\n if (!el) return null;\n if (el.value != null && el.value !== '') return el.value;\n // \"Label, value\" pattern → take the part after the label text. If the query\n // wasn't a substring (a fuzzy match), we can't split cleanly — return the\n // whole row, which still carries the value.\n const idx = el.label.toLowerCase().indexOf(labelSubstring.toLowerCase());\n if (idx < 0) return el.label;\n const after = el.label\n .slice(idx + labelSubstring.length)\n .replace(/^[\\s,:]+/, '')\n .trim();\n return after || el.label;\n }\n\n /**\n * A structural fingerprint of the current screen that is stable across\n * dynamic content (times, battery, values) — it keys the crawler's graph\n * nodes so the same screen is recognized regardless of transient text.\n */\n screenSignature(): string {\n const title =\n this.cachedNodes.find((n) => (n.type === 'NavigationBar' || n.role === 'NavigationBar') && n.label)\n ?.label ?? '';\n const labels = this.cachedNodes\n .filter((n) => TAPPABLE.has(n.role ?? n.type ?? '') && (n.label ?? '').trim())\n .map((n) => `${n.role ?? n.type}:${(n.label ?? '').trim()}`)\n .sort();\n const uniq = [...new Set(labels)];\n return `${this.lastApp.bundleId ?? ''}|${title}|${uniq.join('~')}`;\n }\n\n /** Navigation-bar title of the cached screen ('' when absent). */\n screenTitle(): string {\n return (\n this.cachedNodes.find((n) => (n.type === 'NavigationBar' || n.role === 'NavigationBar') && n.label)\n ?.label ?? ''\n );\n }\n\n /** Take one fresh snapshot into the cache and return the compressed observation. */\n async observe(): Promise<Observation> {\n try {\n await this.refreshCache();\n return this.currentElements();\n } catch (error) {\n if (\n error instanceof SessionNotFoundError ||\n (error as { code?: string })?.code === 'SESSION_NOT_FOUND'\n ) {\n return {\n truncated: false,\n elements: 'No app session is active yet. Use open_app to launch an app first.',\n };\n }\n throw error;\n }\n }\n\n /**\n * Open an app by name/bundle id. relaunch forces a fresh launch (clean\n * initial screen) instead of just foregrounding — iOS keeps an app's\n * navigation state across foregrounding, so primitives that need a known\n * starting screen pass relaunch=true.\n */\n async openApp(app: string, relaunch = false): Promise<string> {\n const result = await this.backend.openApp({ app, relaunch });\n return `Opened ${result.appName ?? app} (${result.appBundleId ?? 'unknown bundle'})`;\n }\n\n /**\n * Level-2 of the action ladder: deep links beat tap sequences when a URL route\n * exists (maps://, app schemes, https:// universal links). XCTest sessions are\n * app-scoped, so a link that opens a different app must re-scope the session\n * to that app or observations keep tracking the old one.\n */\n async openUrl(url: string, app?: string): Promise<string> {\n const target = app ?? (await this.currentBundleId());\n await this.backend.openApp(target ? { app: target, url } : { url });\n return app ? `Opened ${url} in ${app}` : `Opened ${url}`;\n }\n\n private async currentBundleId(): Promise<string | undefined> {\n try {\n const snap = await this.backend.snapshot({ interactiveOnly: true, depth: 1 });\n return snap.appBundleId;\n } catch {\n return undefined;\n }\n }\n\n /** List installed app bundle ids. */\n async listApps(): Promise<string[]> {\n return this.backend.listApps();\n }\n\n // A tap self-diffs against our own snapshot cache: fingerprint before, tap\n // with no driver-side verify (which would cost a second snapshot pair),\n // re-snapshot once, fingerprint after. One snapshot instead of the verify\n // pass's three, and the cache is left fresh so callers don't observe again.\n private async tapAndDiff(tap: () => Promise<unknown>): Promise<ActionEvidence> {\n const before = this.cacheSignature();\n await tap();\n await this.refreshCache();\n const after = this.cacheSignature();\n const changed = before !== after;\n return {\n changed,\n detail: changed ? 'screen changed' : 'screen did NOT change — the action may have had no effect',\n };\n }\n\n /** Tap an element ref, self-diffing the cache to report whether the screen changed. */\n async press(ref: string): Promise<ActionEvidence> {\n try {\n return await this.tapAndDiff(() => this.backend.press({ ref }));\n } catch (error) {\n // The runner refuses center-targeted taps whose center is off-screen\n // (\"off-screen and not safe to press\") — but a carousel/pager item can\n // straddle the viewport edge with most of it visible and perfectly\n // tappable. Fall back to the midpoint of the VISIBLE region. Fully\n // off-screen elements still refuse (rethrow), preserving the scroll-into-\n // view recovery in tapLabel/tapControl.\n if (!/off-?screen/i.test(describeError(error))) throw error;\n const mid = this.visibleMidpoint(this.findNode(ref)?.rect);\n if (!mid) throw error;\n return this.tapAndDiff(() => this.backend.press({ x: mid.x, y: mid.y }));\n }\n }\n\n // Midpoint of the part of `rect` inside the viewport, or null when nothing\n // of it is visible.\n private visibleMidpoint(rect?: Rect): { x: number; y: number } | null {\n if (!rect) return null;\n const x1 = Math.max(rect.x, 0);\n const y1 = Math.max(rect.y, 0);\n const x2 = Math.min(rect.x + rect.width, this.cachedViewport.width);\n const y2 = Math.min(rect.y + rect.height, this.cachedViewport.height);\n if (x2 <= x1 || y2 <= y1) return null;\n return { x: Math.round((x1 + x2) / 2), y: Math.round((y1 + y2) / 2) };\n }\n\n // Fully within a safe band clear of the top nav bar and bottom tab/home area.\n protected onScreen(rect?: Rect): boolean {\n if (!rect) return false;\n const cy = rect.y + rect.height / 2;\n return cy > 56 && cy < this.cachedViewport.height - 44 && rect.x < this.cachedViewport.width;\n }\n\n /**\n * Open an app and walk its nav stack back to the root (dismissing modals), so\n * map-based navigation always starts from a known origin.\n */\n async goToRoot(app: string): Promise<void> {\n const DISMISS = ['Close', 'Cancel', 'Done', 'Not Now', 'Dismiss'];\n await this.observe().catch(() => undefined);\n if (this.lastApp.bundleId !== app) {\n await this.openApp(app);\n await this.observe();\n }\n // Real apps launch behind stacked permission prompts (see clearBlockingAlerts);\n // clear them first so the nav-stack walk below sees the actual app.\n await this.clearBlockingAlerts('accept');\n for (let i = 0; i < 12; i++) {\n const els = this.interactiveElements();\n const back = els.find((e) => e.role === 'Button' && !!e.rect && e.rect.x < 70 && e.rect.y < 110);\n const dismiss = els.find((e) => e.role === 'Button' && DISMISS.includes(e.label));\n const target = back ?? dismiss;\n if (!target) break;\n await this.press(target.ref);\n await this.observe();\n }\n // The root may be left scrolled from prior navigation; reset it to the top\n // so crawls/navigation start from a known position.\n await this.scrollToTop();\n }\n\n /** Height of the cached viewport in points. */\n viewportHeight(): number {\n return this.cachedViewport.height;\n }\n\n /**\n * Vertical span of interactive content in the current cache. Used to decide\n * whether scrolling is even necessary — scroll gestures cost ~2s each, so\n * skipping them on screens that already fit is the single biggest crawl\n * speedup.\n */\n contentBounds(): { minY: number; maxY: number } {\n let minY = Infinity;\n let maxY = -Infinity;\n for (const n of this.cachedNodes) {\n if (!n.rect) continue;\n if (!TAPPABLE.has(n.role ?? n.type ?? '')) continue;\n minY = Math.min(minY, n.rect.y);\n maxY = Math.max(maxY, n.rect.y + n.rect.height);\n }\n return { minY: minY === Infinity ? 0 : minY, maxY: maxY === -Infinity ? 0 : maxY };\n }\n\n /**\n * Tapping the status bar scrolls the active scroll view to the top — native\n * iOS behavior, one fast tap instead of multiple ~2s scroll gestures. Falls\n * back to gesture scrolling if the tap doesn't take.\n */\n async scrollToTop(): Promise<void> {\n try {\n await this.backend.press({ x: Math.round(this.cachedViewport.width / 2), y: 6 });\n await this.observe();\n return;\n } catch {\n /* fall back to gesture scroll below */\n }\n for (let i = 0; i < 6; i++) {\n const before = this.screenSignature();\n await this.scroll('up');\n await this.observe();\n if (this.screenSignature() === before) return;\n }\n }\n\n /**\n * Tap an element by its label, scrolling it into view first if it's\n * off-screen. The crawler and the map navigator use this so a target below\n * the fold (a long Settings list) is still reachable. Re-resolves the ref\n * after each scroll.\n */\n async tapLabel(label: string): Promise<boolean> {\n for (let i = 0; i < 12; i++) {\n const el = this.interactiveElements().find((e) => e.label === label);\n if (el && this.onScreen(el.rect)) {\n try {\n await this.press(el.ref);\n return true;\n } catch (error) {\n if (!/off-?screen/i.test(describeError(error))) throw error;\n // straddled the edge — fall through to a nudge scroll and retry\n }\n }\n // Known position → scroll toward it. Not in the realized tree at all →\n // sweep to the top first (rows may be scrolled past above), then scan down.\n const dir: 'up' | 'down' = el?.rect ? (el.rect.y < 0 ? 'up' : 'down') : i < 5 ? 'up' : 'down';\n await this.scroll(dir);\n await this.observe();\n }\n return false;\n }\n\n /**\n * Vision-path fallback: tap raw coordinates when the accessibility tree is\n * missing or wrong (canvas, games, custom controls). Coordinates are in the\n * same space as observe()'s rects and the screenshot pixels (@1x points).\n */\n async pressAt(x: number, y: number): Promise<ActionEvidence> {\n return this.tapAndDiff(() => this.backend.press({ x, y }));\n }\n\n /**\n * Coordinate drag: touch down at (x,y), move by (dx,dy). The primitive for\n * controls a tap can't operate — picker wheels (drag vertically on the wheel\n * column), sliders, and custom carousels. Same coordinate space as rects.\n */\n async pan(x: number, y: number, dx: number, dy: number, durationMs?: number): Promise<void> {\n await this.backend.pan(x, y, dx, dy, durationMs);\n }\n\n /**\n * Set-of-Marks visual observation: screenshot with `@ref` labels drawn on the\n * elements, so a vision model can ground itself in pixels and still act by ref.\n */\n async screenshotWithRefs(path: string): Promise<string> {\n const result = await this.backend.screenshot({ path, overlayRefs: true });\n return result.path;\n }\n\n protected async currentViewport(): Promise<{ width: number; height: number }> {\n try {\n const snap = await this.backend.snapshot({ interactiveOnly: true, depth: 1 });\n const root = snap.nodes.find((n) => (n.type === 'Application' || n.type === 'Window') && n.rect);\n return { width: root?.rect?.width ?? 390, height: root?.rect?.height ?? 844 };\n } catch {\n return { width: 390, height: 844 };\n }\n }\n\n /** Long-press an element ref. */\n async longPress(ref: string, durationMs = 800): Promise<void> {\n await this.backend.longPress(ref, durationMs);\n }\n\n /** Focus a field and replace its text, self-diffing the cache for evidence. */\n async fill(ref: string, text: string): Promise<ActionEvidence> {\n return this.tapAndDiff(() => this.backend.fill(ref, text));\n }\n\n /** Type into whatever currently has keyboard focus. */\n async typeText(text: string): Promise<void> {\n await this.backend.typeText(text);\n }\n\n /**\n * Press the keyboard's return/go key. Submits a search bar that acts on\n * Return (Safari's address bar, web forms) rather than filtering results as\n * you type.\n */\n async pressReturn(): Promise<void> {\n await this.backend.pressKey('return');\n }\n\n /** Scroll the active scroll view one step. */\n async scroll(direction: 'up' | 'down' | 'left' | 'right'): Promise<void> {\n await this.backend.scroll(direction);\n }\n\n /** Block until `text` appears on screen; returns a confirmation note. */\n async waitForText(text: string, timeoutMs = 5000): Promise<string> {\n await this.backend.waitForText(text, timeoutMs);\n return `\"${text}\" appeared on screen`;\n }\n\n // Read a modal alert (if any) from the current snapshot cache — cheap, no\n // extra snapshot, since observe() already caches the Alert node\n // (interactiveOnly keeps it).\n private alertFromCache(): AlertInfo | null {\n const alert = this.cachedNodes.find((n) => (n.type ?? n.role) === 'Alert');\n if (!alert) return null;\n const texts = this.cachedNodes\n .filter((n) => (n.type ?? n.role) === 'StaticText' && n.label)\n .map((n) => (n.label ?? '').trim());\n const buttons: UiElement[] = [];\n for (const n of this.cachedNodes) {\n if (!n.ref || !n.rect || (n.role ?? n.type) !== 'Button') continue;\n const label = (n.label ?? n.identifier ?? '').trim();\n if (label)\n buttons.push({\n ref: normRef(n.ref),\n label,\n role: 'Button',\n value: n.value,\n rect: n.rect,\n enabled: n.enabled,\n blocked: n.interactionBlocked,\n });\n }\n const title = (alert.label ?? texts[0] ?? 'Alert').trim();\n return { title, message: texts.find((t) => t !== title), buttons };\n }\n\n /**\n * System dialogs (permissions, sign-in prompts) block everything else; the\n * driver exposes them as a first-class action instead of hoping a tap lands.\n */\n async handleAlert(action: 'get' | 'accept' | 'dismiss'): Promise<AlertOutcome> {\n await this.observe().catch(() => undefined);\n const info = this.alertFromCache();\n if (info) {\n const description = describeAlert(info);\n if (action === 'get') return { present: true, description };\n const btn = pickAlertButton(info.buttons, action);\n if (!btn?.rect) return { present: true, handled: false, description };\n await this.pressAt(btn.rect.x + btn.rect.width / 2, btn.rect.y + btn.rect.height / 2);\n await this.observe().catch(() => undefined);\n const still = this.alertFromCache();\n // Handled if this alert is gone; a *different* alert surfacing (stacked\n // prompts) still counts — this one was cleared.\n return {\n present: true,\n handled: still == null || still.title !== info.title,\n button: btn.label,\n description,\n };\n }\n // Fallback: the backend's command for an app's own alert not surfaced as a node.\n try {\n const result = await this.backend.systemAlert(action);\n const alert = result.alert;\n return {\n present: alert != null,\n handled: result.handled,\n button: result.button,\n description: alert\n ? `${alert.title ?? ''} ${alert.message ?? ''}`.trim() +\n (alert.buttons?.length ? ` [buttons: ${alert.buttons.join(', ')}]` : '')\n : undefined,\n };\n } catch (error) {\n if (/alert not found/i.test(describeError(error))) return { present: false };\n throw error;\n }\n }\n\n /**\n * Clear the launch permission gauntlet — real apps stack location /\n * notification / tracking prompts on first open, each blocking the app.\n * Grants by default so the crawl sees the most surface. Returns the buttons\n * tapped. Bounded so a non-clearing dialog can't loop forever.\n */\n async clearBlockingAlerts(action: 'accept' | 'dismiss' = 'accept', max = 6): Promise<string[]> {\n const tapped: string[] = [];\n let lastTitle = '';\n for (let i = 0; i < max; i++) {\n const info = this.alertFromCache();\n if (!info) {\n await this.observe().catch(() => undefined);\n if (!this.alertFromCache()) break;\n }\n const r = await this.handleAlert(action);\n if (!r.present || !r.button || !r.handled) break;\n if (r.description === lastTitle) break; // no progress — same dialog persists\n lastTitle = r.description ?? '';\n tapped.push(r.button);\n }\n return tapped;\n }\n\n /** Go to the home screen. */\n async goHome(): Promise<void> {\n await this.backend.home();\n }\n\n /** Navigate back (nav-bar back / hardware back). */\n async goBack(): Promise<void> {\n await this.backend.back();\n }\n\n /** Save a screenshot to `path`; returns the written path. */\n async screenshot(path: string): Promise<string> {\n const result = await this.backend.screenshot({ path });\n return result.path;\n }\n\n /** Close the backend's transport session. */\n async closeSession(): Promise<void> {\n await this.backend.closeSession();\n }\n\n protected findNode(ref: string): SnapshotNode | undefined {\n const want = normRef(ref);\n return this.cachedNodes.find((n) => n.ref && normRef(n.ref) === want);\n }\n\n // Ensure the cache is fresh enough to resolve refs / draw boxes.\n protected async ensureCache(): Promise<void> {\n if (this.cachedNodes.length === 0) await this.observe();\n }\n}\n","// ---------------------------------------------------------------------------\n// %variable% secret substitution (Stagehand's pattern):\n// the model/caller plans against NAMES; values are injected at the last moment\n// before backend.fill/typeText and never rendered into Actions, results,\n// observations, or traces. Redaction is best-effort belt-and-braces — after\n// typing into a non-secure field the next snapshot's value contains the\n// secret, and redact() at observe/result assembly keeps it out of outbound\n// text. The hard guarantee is at the substitution point: values never enter\n// stored Actions by construction.\n// ---------------------------------------------------------------------------\n\nconst MIN_SECRET_LENGTH = 4;\n\n/**\n * `%variable%` secret substitution (Stagehand's pattern):\n * the model/caller plans against NAMES; values are injected at the last moment\n * before backend.fill/typeText and never rendered into Actions, results,\n * observations, or traces. Redaction is best-effort belt-and-braces; the hard\n * guarantee is at the substitution point — values never enter stored Actions\n * by construction.\n */\nexport class SecretStore {\n private readonly values = new Map<string, string>();\n\n constructor(values?: Record<string, string>) {\n if (values) for (const [k, v] of Object.entries(values)) this.set(k, v);\n }\n\n /**\n * Store a secret under `name`. Rejects values shorter than 4 chars — a\n * 2-char secret would redact innocent UI text everywhere.\n */\n set(name: string, value: string): void {\n if (value.length < MIN_SECRET_LENGTH) {\n throw new Error(`secret \"${name}\" is too short (<${MIN_SECRET_LENGTH} chars) to redact safely`);\n }\n this.values.set(name, value);\n }\n\n /** The stored secret NAMES (never the values). */\n names(): string[] {\n return [...this.values.keys()];\n }\n\n /** %name% → value. Unknown %x% stays literal. */\n substitute(text: string): string {\n return text.replace(/%([A-Za-z0-9_-]+)%/g, (whole, name: string) => this.values.get(name) ?? whole);\n }\n\n /** value → %name% across outbound text (messages, rendered observations). */\n redact(text: string): string {\n let out = text;\n for (const [name, value] of this.values) {\n out = out.split(value).join(`%${name}%`);\n }\n return out;\n }\n\n /** Per-call vars layered over the store (call-scoped, never persisted). */\n withOverrides(vars?: Record<string, string>): SecretStore {\n if (!vars || Object.keys(vars).length === 0) return this;\n const merged = new SecretStore();\n for (const [k, v] of this.values) merged.values.set(k, v);\n for (const [k, v] of Object.entries(vars)) merged.set(k, v);\n return merged;\n }\n}\n","import type { Rect, ScrollDirection } from './device.ts';\nimport {\n AbortedError,\n ActionFailedError,\n PhoneUseError,\n type PhoneUseErrorCode,\n TimeoutError,\n} from './errors.ts';\nimport {\n type DeviceCore,\n matchInElements,\n type Resolution,\n type ResolveOpts,\n TAPPABLE,\n type UiElement,\n} from './observe.ts';\nimport { SecretStore } from './secrets.ts';\n\n// ---------------------------------------------------------------------------\n// The observe→act seam: observe() returns\n// portable Action descriptors carrying RE-RESOLVABLE element queries; act()\n// re-resolves against the live tree and executes with no re-inference. A\n// compiled skill is a stored Action[]. The resolution ladder (DeviceCore) is\n// the one query engine — this module contains dispatch, auto-wait, abort, and\n// secrets wiring, never matching logic.\n//\n// Never-throw contract: executeAction returns {success:false,...} for every\n// device-legible outcome (not found, ambiguous, wait deadline, gesture\n// failure). It throws PhoneUseError subclasses only for infrastructure:\n// aborts, closed sessions on non-observe verbs, unsupported capabilities,\n// unknown errors.\n// ---------------------------------------------------------------------------\n\n/**\n * A RE-RESOLVABLE element query — how a portable {@link Action} names its\n * target. Resolved against the live tree by the resolution ladder at act()\n * time; no stale handles.\n */\nexport type ElementQuery = {\n /** Label to match (exact → substring → fuzzy, the ladder's rungs). */\n label?: string | undefined;\n /** Accessibility identifier — rung 0 of the ladder, wins when present. */\n id?: string | undefined;\n /** Disambiguator: restrict matches to this role (e.g. \"Button\"). */\n role?: string | undefined;\n /** Disambiguator: label of another element; pick the geometrically closest match. */\n near?: string | undefined;\n};\n\n/** Verbs a portable {@link Action} can carry. */\nexport type ActionVerb =\n | 'tap'\n | 'longPress'\n | 'fill'\n | 'type'\n | 'pressKey'\n | 'scroll'\n | 'openApp'\n | 'openUrl'\n | 'back'\n | 'home'\n | 'alert'\n | 'waitForText';\n\n/**\n * The observe→act seam: a portable action\n * descriptor carrying a re-resolvable {@link ElementQuery}. `observe()` returns\n * these; `act()` re-resolves against the live tree and executes with no\n * re-inference. A compiled skill is a stored `Action[]`.\n */\nexport type Action = {\n /** Versioned, documented UNSTABLE pre-1.0. */\n formatVersion: 0;\n /** What to do. */\n verb: ActionVerb;\n /** Target query for element-directed verbs (tap/longPress/fill). */\n target?: ElementQuery | undefined;\n /** Verb parameters (text, direction, app, url, ...). */\n params?:\n | {\n /** fill/type text — may contain %name% secret references. */\n text?: string | undefined;\n direction?: ScrollDirection | undefined;\n app?: string | undefined;\n url?: string | undefined;\n durationMs?: number | undefined;\n key?: 'return' | undefined;\n alertAction?: 'accept' | 'dismiss' | undefined;\n submit?: boolean | undefined;\n relaunch?: boolean | undefined;\n }\n | undefined;\n /**\n * Provenance from observe/record time. ADVISORY ONLY — act() always\n * re-resolves; this exists for traces, drift diagnosis, and human review.\n */\n observed?:\n | {\n via?: string | undefined;\n label?: string | undefined;\n role?: string | undefined;\n rect?: Rect | undefined;\n app?: string | undefined;\n screenTitle?: string | undefined;\n }\n | undefined;\n};\n\n/** The stored-Action[] artifact (public TYPE, unstable FORMAT pre-1.0). */\nexport type CompiledSkill = {\n formatVersion: 0;\n name: string;\n description?: string | undefined;\n params?: string[] | undefined;\n precondition?: string | undefined;\n actions: Action[];\n};\n\n/** An interactive element as surfaced by `observe()` (alias of {@link UiElement}). */\nexport type ObservedElement = UiElement;\n\n/** What `observe()` returns: elements, rendered text, and portable actions. */\nexport type ObserveResult = {\n /** Always true for a completed observation. */\n success: boolean;\n /** Human-readable summary of the observation. */\n message: string;\n /** Frontmost app name, when known. */\n app?: string | undefined;\n /** Frontmost app bundle id, when known. */\n bundleId?: string | undefined;\n /** Navigation-bar title of the current screen, when present. */\n screenTitle?: string | undefined;\n /** Structured channel (secret-redacted values). */\n elements: ObservedElement[];\n /** Compressed text channel (secret-redacted). */\n rendered: string;\n /** Portable descriptors: a tap per tappable, a fill per input field. */\n actions: Action[];\n};\n\n/**\n * Structured outcome of every action verb. Never-throw contract: device-legible\n * failures (not found, ambiguous, wait deadline, gesture failure) come back as\n * `{success: false, ...}`; only infrastructure errors (abort, closed session,\n * unsupported capability) throw PhoneUseError subclasses.\n */\nexport type ActionResult = {\n /** Did the action execute as intended. */\n success: boolean;\n /** Human-readable outcome (secret-redacted). */\n message: string;\n /** tapAndDiff verdict where applicable: did the screen actually change. */\n changed?: boolean | undefined;\n /** How the target resolved (match provenance, ref, label, role, rect). */\n resolved?: { via: string; ref: string; label: string; role: string; rect?: Rect | undefined } | undefined;\n /** The ambiguity contract, surfaced structurally. */\n candidates?: ObservedElement[] | undefined;\n /** Auto-wait cost when the slow path ran (elapsed ms, poll count). */\n waited?: { ms: number; polls: number } | undefined;\n /** Set on structured failures with an error flavor (e.g. TIMEOUT). */\n code?: PhoneUseErrorCode | undefined;\n};\n\n/** Per-call options accepted by every action verb. */\nexport type ActOptions = {\n /** Abort the call; the in-flight gesture may still land (state indeterminate). */\n signal?: AbortSignal | undefined;\n /** Auto-wait deadline (default 5000 ms). */\n timeoutMs?: number | undefined;\n /** Per-call secret overrides, layered on the device store. */\n vars?: Record<string, string> | undefined;\n};\n\n// --- abort plumbing ---------------------------------------------------------\n\nfunction throwIfAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted) throw new AbortedError();\n}\n\n/** Race a backend promise against the caller's abort. The abandoned in-flight\n * call may still land on the device — documented abort semantics (state\n * indeterminate); no retry follows an abort. */\nasync function raceWithAbort<T>(promise: Promise<T>, signal: AbortSignal | undefined): Promise<T> {\n if (!signal) return promise;\n throwIfAborted(signal);\n let onAbort: (() => void) | undefined;\n const aborted = new Promise<never>((_, reject) => {\n onAbort = () => reject(new AbortedError());\n signal.addEventListener('abort', onAbort, { once: true });\n });\n try {\n return await Promise.race([promise, aborted]);\n } finally {\n if (onAbort) signal.removeEventListener('abort', onAbort);\n }\n}\n\nfunction sleep(ms: number, signal: AbortSignal | undefined): Promise<void> {\n return raceWithAbort(new Promise<void>((r) => setTimeout(r, ms)), signal);\n}\n\n// --- observe-side synthesis ---------------------------------------------------\n\nfunction queryFor(el: UiElement): ElementQuery {\n return el.id ? { id: el.id } : { label: el.label };\n}\n\nfunction provenance(core: DeviceCore, el: UiElement, via?: string) {\n return {\n ...(via === undefined ? {} : { via }),\n label: el.label,\n role: el.role,\n ...(el.rect === undefined ? {} : { rect: el.rect }),\n ...(core.currentApp() === undefined ? {} : { app: core.currentApp() }),\n ...(core.screenTitle() ? { screenTitle: core.screenTitle() } : {}),\n };\n}\n\n/** Synthesize portable actions from the CURRENT cache (observe-time). */\nexport function toActions(core: DeviceCore): Action[] {\n const actions: Action[] = [];\n for (const el of core.interactiveElements()) {\n const kind = el.role;\n if (TAPPABLE.has(kind)) {\n actions.push({\n formatVersion: 0,\n verb: 'tap',\n target: queryFor(el),\n observed: provenance(core, el, el.id ? 'id' : 'exact label'),\n });\n }\n }\n for (const el of core.inputFields(true)) {\n actions.push({\n formatVersion: 0,\n verb: 'fill',\n target: queryFor(el),\n params: { text: '' },\n observed: provenance(core, el, el.id ? 'id' : 'exact label'),\n });\n }\n return actions;\n}\n\nconst NO_SECRETS = new SecretStore();\n\n/**\n * Take one fresh snapshot and assemble the full {@link ObserveResult}:\n * deduped element channel, secret-redacted rendered text, and a portable\n * Action per tappable / input field.\n */\nexport async function buildObserveResult(\n core: DeviceCore,\n secrets: SecretStore = NO_SECRETS,\n): Promise<ObserveResult> {\n const obs = await core.observe();\n const redact = (s: string) => secrets.redact(s);\n // Tappables + input fields: one structured element channel (deduped by ref).\n const seen = new Set<string>();\n const elements: ObservedElement[] = [];\n for (const el of [...core.interactiveElements(), ...core.inputFields(true)]) {\n if (seen.has(el.ref)) continue;\n seen.add(el.ref);\n elements.push({\n ...el,\n label: redact(el.label),\n ...(el.value === undefined || el.value === null ? {} : { value: redact(el.value) }),\n });\n }\n return {\n success: true,\n message: elements.length\n ? `observed ${elements.length} interactive elements`\n : obs.elements.slice(0, 120),\n ...(obs.app === undefined ? {} : { app: obs.app }),\n ...(obs.bundleId === undefined ? {} : { bundleId: obs.bundleId }),\n ...(core.screenTitle() ? { screenTitle: core.screenTitle() } : {}),\n elements,\n rendered: redact(core.renderObservation(true)),\n actions: toActions(core),\n };\n}\n\n// --- act-side dispatch ---------------------------------------------------------\n\nfunction toResolveOpts(q: ElementQuery): ResolveOpts {\n return {\n ...(q.role === undefined ? {} : { role: q.role }),\n ...(q.near === undefined ? {} : { near: q.near }),\n };\n}\n\nfunction queryText(q: ElementQuery): string {\n const t = q.id ?? q.label;\n if (t === undefined || t === '') {\n throw new ActionFailedError('action target needs an id or label');\n }\n return t;\n}\n\nfunction isActionable(el: UiElement): boolean {\n return el.enabled !== false && !el.blocked;\n}\n\nconst CACHE_FRESH_MS = 2000;\nconst POLL_STEPS_MS = [150, 300, 600, 800];\n\ntype WaitOutcome =\n | { ok: true; el: UiElement; via: string; waited: { ms: number; polls: number } | undefined }\n | { ok: false; result: ActionResult };\n\n/**\n * Resolve + auto-wait (visible+hittable+enabled+settled on every\n * action, no caller sleep — and it must not double latency).\n * Fast path: a fresh cache resolving to an actionable target executes with\n * ZERO extra snapshots. Slow path: poll in place (never scroll — scrolling is\n * the ladder's job, and polling must not dismiss transient menus) until the\n * target is actionable AND the tree signature is stable between polls.\n */\nasync function resolveWithWait(\n core: DeviceCore,\n q: ElementQuery,\n opts: ActOptions,\n pool: 'tappable' | 'fields',\n): Promise<WaitOutcome> {\n const signal = opts.signal;\n const deadline = Date.now() + (opts.timeoutMs ?? 5000);\n const text = queryText(q);\n const rOpts = toResolveOpts(q);\n // Tap targets resolve against interactive (tappable) elements; fill targets\n // against input fields — two pools, one matcher (the ladder's rungs).\n const inCache = (): Resolution =>\n pool === 'fields'\n ? matchInElements(core.inputFields(true), text, rOpts)\n : core.resolveInCache(text, rOpts);\n\n // Fast path: fresh cache + actionable target → go now, zero snapshots.\n if (core.cacheAgeMs() < CACHE_FRESH_MS) {\n const r = inCache();\n if (r.el && isActionable(r.el)) return { ok: true, el: r.el, via: r.via ?? 'cache', waited: undefined };\n if (r.candidates?.length) return { ok: false, result: ambiguityResult(text, r) };\n }\n\n // Not in the (possibly stale) cache at all. For tappables, run one full\n // ladder pass (scroll search) — not-on-screen is a search problem;\n // not-yet-enabled is a wait problem. Fields skip the scroll ladder (fields\n // live on the current form) and go straight to the poll.\n throwIfAborted(signal);\n let r: Resolution;\n if (pool === 'tappable') {\n r = await raceWithAbort(core.resolveElement(text, rOpts), signal);\n } else {\n await raceWithAbort(core.observe(), signal);\n r = inCache();\n }\n if (!r.el && r.candidates?.length) return { ok: false, result: ambiguityResult(text, r) };\n if (r.el && isActionable(r.el)) return { ok: true, el: r.el, via: r.via ?? 'ladder', waited: undefined };\n\n // Wait loop: poll in place until actionable + settled, or deadline.\n const started = Date.now();\n let polls = 0;\n let lastSig = core.stateSignature();\n let step = 0;\n while (Date.now() < deadline) {\n await sleep(POLL_STEPS_MS[Math.min(step, POLL_STEPS_MS.length - 1)]!, signal);\n step++;\n polls++;\n throwIfAborted(signal);\n await raceWithAbort(core.observe(), signal);\n const sig = core.stateSignature();\n const settled = sig === lastSig;\n lastSig = sig;\n const rr = inCache();\n if (rr.el && isActionable(rr.el) && settled) {\n return { ok: true, el: rr.el, via: rr.via ?? 'wait', waited: { ms: Date.now() - started, polls } };\n }\n if (!rr.el && rr.candidates?.length) return { ok: false, result: ambiguityResult(text, rr) };\n r = rr;\n }\n return {\n ok: false,\n result: {\n success: false,\n code: 'TIMEOUT',\n message: r.el\n ? `timed out after ${opts.timeoutMs ?? 5000}ms waiting for \"${text}\" to become enabled/settled`\n : `timed out after ${opts.timeoutMs ?? 5000}ms — no element matching \"${text}\" on this screen`,\n waited: { ms: Date.now() - started, polls },\n },\n };\n}\n\nfunction ambiguityResult(text: string, r: Resolution): ActionResult {\n const list = (r.candidates ?? [])\n .map(\n (c) => `${c.role} \"${c.label}\"${c.rect ? ` at (${Math.round(c.rect.x)},${Math.round(c.rect.y)})` : ''}`,\n )\n .join('; ');\n return {\n success: false,\n message: `\"${text}\" is ambiguous — ${r.candidates?.length ?? 0} matches: ${list}. Disambiguate with role or near.`,\n candidates: r.candidates ?? [],\n };\n}\n\nfunction resolvedOf(el: UiElement, via: string) {\n return {\n via,\n ref: el.ref,\n label: el.label,\n role: el.role,\n ...(el.rect === undefined ? {} : { rect: el.rect }),\n };\n}\n\n/**\n * THE dispatcher: resolve → auto-wait → execute → diff. One brain — used by\n * device.tap/type/act, and (items 5-6) by the harness and the skill runner.\n */\nexport async function executeAction(\n core: DeviceCore,\n action: Action,\n opts: ActOptions = {},\n secrets: SecretStore = NO_SECRETS,\n): Promise<ActionResult> {\n const signal = opts.signal;\n throwIfAborted(signal);\n const store = secrets.withOverrides(opts.vars);\n const redact = (s: string) => store.redact(s);\n\n try {\n switch (action.verb) {\n case 'tap':\n case 'longPress':\n case 'fill': {\n if (!action.target) return { success: false, message: `${action.verb} needs a target query` };\n const wait = await resolveWithWait(\n core,\n action.target,\n opts,\n action.verb === 'fill' ? 'fields' : 'tappable',\n );\n if (!wait.ok) return wait.result;\n const { el, via, waited } = wait;\n if (action.verb === 'longPress') {\n await raceWithAbort(core.longPress(el.ref, action.params?.durationMs), signal);\n return {\n success: true,\n message: redact(`long-pressed \"${el.label}\"`),\n resolved: resolvedOf(el, via),\n waited,\n };\n }\n if (action.verb === 'fill') {\n const text = store.substitute(action.params?.text ?? '');\n const ev = await raceWithAbort(core.fill(el.ref, text), signal);\n if (action.params?.submit) await raceWithAbort(core.pressReturn(), signal);\n return {\n success: true,\n message: redact(`filled \"${el.label}\"${action.params?.submit ? ', pressed Return' : ''}`),\n ...(ev.changed === undefined ? {} : { changed: ev.changed }),\n resolved: resolvedOf(el, via),\n waited,\n };\n }\n const ev = await raceWithAbort(core.press(el.ref), signal);\n return {\n success: true,\n message: redact(`tapped \"${el.label}\"${ev.changed === false ? ' (no change)' : ''}`),\n ...(ev.changed === undefined ? {} : { changed: ev.changed }),\n resolved: resolvedOf(el, via),\n waited,\n };\n }\n case 'type': {\n const text = store.substitute(action.params?.text ?? '');\n await raceWithAbort(core.typeText(text), signal);\n if (action.params?.submit) await raceWithAbort(core.pressReturn(), signal);\n return { success: true, message: redact(`typed ${JSON.stringify(action.params?.text ?? '')}`) };\n }\n case 'pressKey': {\n await raceWithAbort(core.pressReturn(), signal);\n return { success: true, message: 'pressed Return' };\n }\n case 'scroll': {\n const direction = action.params?.direction ?? 'down';\n await raceWithAbort(core.scroll(direction), signal);\n await raceWithAbort(core.observe(), signal);\n return { success: true, message: `scrolled ${direction}` };\n }\n case 'openApp': {\n if (!action.params?.app) return { success: false, message: 'openApp needs params.app' };\n const note = await raceWithAbort(\n core.openApp(action.params.app, action.params.relaunch ?? false),\n signal,\n );\n return { success: true, message: note };\n }\n case 'openUrl': {\n if (!action.params?.url) return { success: false, message: 'openUrl needs params.url' };\n const note = await raceWithAbort(core.openUrl(action.params.url, action.params.app), signal);\n return { success: true, message: note };\n }\n case 'back': {\n await raceWithAbort(core.goBack(), signal);\n return { success: true, message: 'went back' };\n }\n case 'home': {\n await raceWithAbort(core.goHome(), signal);\n return { success: true, message: 'went home' };\n }\n case 'alert': {\n const outcome = await raceWithAbort(core.handleAlert(action.params?.alertAction ?? 'accept'), signal);\n if (!outcome.present) return { success: false, message: 'no system alert is showing' };\n return {\n success: outcome.handled !== false,\n message: `alert ${outcome.handled ? `handled via \"${outcome.button}\"` : 'NOT handled'}: ${outcome.description ?? ''}`,\n };\n }\n case 'waitForText': {\n if (!action.params?.text) return { success: false, message: 'waitForText needs params.text' };\n const note = await raceWithAbort(\n core.waitForText(action.params.text, opts.timeoutMs ?? 5000),\n signal,\n );\n const ok = !/did not appear|not found|timed out/i.test(note);\n return { success: ok, message: redact(note), ...(ok ? {} : { code: 'TIMEOUT' as const }) };\n }\n default:\n return { success: false, message: `unknown verb ${String((action as { verb?: unknown }).verb)}` };\n }\n } catch (error) {\n // Infrastructure failures propagate; device-legible gesture failures are\n // structured results.\n if (error instanceof AbortedError) throw error;\n if (error instanceof PhoneUseError) {\n if (error instanceof ActionFailedError || error instanceof TimeoutError) {\n return { success: false, message: redact(error.message), code: error.code };\n }\n throw error;\n }\n throw error;\n }\n}\n","import { createAgentDeviceClient } from 'agent-device';\nimport type { DeviceBackend } from '../backend.ts';\nimport { BaseDeviceBackend } from '../backend.ts';\nimport type { DeviceConfig } from '../config.ts';\nimport type {\n AlertAction,\n BackendAlertResult,\n Capability,\n OpenAppResult,\n PressTarget,\n ScrollDirection,\n Snapshot,\n} from '../device.ts';\nimport { ALL_CAPABILITIES } from '../device.ts';\nimport { toPhoneUseError } from '../errors.ts';\n\n// ---------------------------------------------------------------------------\n// The agent-device backend: the ONE place agent-device is called. Device\n// pinning is per-request in agent-device (AgentDeviceSelectionOptions), so a\n// backend holds a selection object and spreads it into every call. With no\n// config, selection is {} and the client is default-constructed — requests are\n// byte-identical to the pre-seam process-global path (booted-sim auto-detect)\n// — the backward-compat guarantee against default-selection drift.\n//\n// Every method normalizes errors via toPhoneUseError — no agent-device type\n// or error ever escapes this file.\n// ---------------------------------------------------------------------------\n\ntype AdClient = ReturnType<typeof createAgentDeviceClient>;\n\nclass AgentDeviceBackend extends BaseDeviceBackend {\n private readonly client: AdClient;\n private readonly selection: Record<string, unknown>;\n // Sessions are lazy daemon-side: nothing exists to close until a first real\n // call is made, and asking the daemon anyway would SPAWN one on hosts where\n // it isn't running (observed in the Mac verification sweep).\n private used = false;\n\n constructor(config?: DeviceConfig) {\n super('agent-device', ALL_CAPABILITIES);\n this.client = createAgentDeviceClient(\n config &&\n (config.session !== undefined ||\n config.daemonBaseUrl !== undefined ||\n config.daemonAuthToken !== undefined)\n ? {\n ...(config.session === undefined ? {} : { session: config.session }),\n ...(config.daemonBaseUrl === undefined ? {} : { daemonBaseUrl: config.daemonBaseUrl }),\n ...(config.daemonAuthToken === undefined ? {} : { daemonAuthToken: config.daemonAuthToken }),\n }\n : undefined,\n );\n this.selection = !config\n ? {}\n : {\n platform: config.platform,\n ...(config.device === undefined ? {} : { device: config.device }),\n ...(config.platform === 'ios' && config.udid !== undefined ? { udid: config.udid } : {}),\n ...(config.platform === 'ios' && config.simulatorDeviceSet !== undefined\n ? { iosSimulatorDeviceSet: config.simulatorDeviceSet }\n : {}),\n ...(config.platform === 'android' && config.serial !== undefined ? { serial: config.serial } : {}),\n };\n }\n\n private async guard<T>(capability: Capability, fn: () => Promise<T>): Promise<T> {\n if (capability !== 'closeSession') this.used = true;\n try {\n return await fn();\n } catch (error) {\n throw toPhoneUseError(error, { backend: this.backendName, capability });\n }\n }\n\n override snapshot(opts?: {\n interactiveOnly?: boolean | undefined;\n depth?: number | undefined;\n }): Promise<Snapshot> {\n return this.guard('snapshot', async () => {\n const snap = await this.client.capture.snapshot({\n ...this.selection,\n ...(opts?.interactiveOnly === undefined ? {} : { interactiveOnly: opts.interactiveOnly }),\n ...(opts?.depth === undefined ? {} : { depth: opts.depth }),\n });\n return { nodes: snap.nodes, appName: snap.appName, appBundleId: snap.appBundleId };\n });\n }\n\n override screenshot(opts: { path: string; overlayRefs?: boolean | undefined }): Promise<{ path: string }> {\n return this.guard('screenshot', async () => {\n const result = await this.client.capture.screenshot({\n ...this.selection,\n path: opts.path,\n ...(opts.overlayRefs === undefined ? {} : { overlayRefs: opts.overlayRefs }),\n });\n return { path: result.path };\n });\n }\n\n override press(target: PressTarget): Promise<void> {\n return this.guard('press', async () => {\n await this.client.interactions.press({ ...this.selection, ...target });\n });\n }\n\n override longPress(ref: string, durationMs?: number): Promise<void> {\n return this.guard('longPress', async () => {\n // settle: true preserved exactly from the pre-seam driver.\n await this.client.interactions.longPress({\n ...this.selection,\n ref,\n ...(durationMs === undefined ? {} : { durationMs }),\n settle: true,\n });\n });\n }\n\n override fill(ref: string, text: string): Promise<void> {\n return this.guard('fill', async () => {\n await this.client.interactions.fill({ ...this.selection, ref, text });\n });\n }\n\n override typeText(text: string): Promise<void> {\n return this.guard('type', async () => {\n await this.client.interactions.type({ ...this.selection, text });\n });\n }\n\n override pressKey(_key: 'return'): Promise<void> {\n return this.guard('key', async () => {\n await this.client.command.keyboard({ ...this.selection, action: 'return' });\n });\n }\n\n override scroll(direction: ScrollDirection): Promise<void> {\n return this.guard('scroll', async () => {\n const args = { ...this.selection, direction } as Parameters<AdClient['interactions']['scroll']>[0];\n await this.client.interactions.scroll(args);\n });\n }\n\n override pan(x: number, y: number, dx: number, dy: number, durationMs?: number): Promise<void> {\n return this.guard('pan', async () => {\n await this.client.interactions.pan({\n ...this.selection,\n x,\n y,\n dx,\n dy,\n ...(durationMs === undefined ? {} : { durationMs }),\n });\n });\n }\n\n override waitForText(text: string, timeoutMs?: number): Promise<void> {\n return this.guard('waitForText', async () => {\n await this.client.command.wait({\n ...this.selection,\n text,\n ...(timeoutMs === undefined ? {} : { timeoutMs }),\n });\n });\n }\n\n override systemAlert(action: AlertAction): Promise<BackendAlertResult> {\n return this.guard('alert', async () => {\n const result = (await this.client.command.alert({ ...this.selection, action })) as {\n alert?: { title?: string; message?: string; buttons?: string[] } | null;\n handled?: boolean;\n button?: string;\n };\n return { alert: result.alert, handled: result.handled, button: result.button };\n });\n }\n\n override home(): Promise<void> {\n return this.guard('home', async () => {\n await this.client.command.home({ ...this.selection });\n });\n }\n\n override back(): Promise<void> {\n return this.guard('back', async () => {\n await this.client.command.back({ ...this.selection });\n });\n }\n\n override openApp(opts: {\n app?: string | undefined;\n url?: string | undefined;\n relaunch?: boolean | undefined;\n }): Promise<OpenAppResult> {\n return this.guard('openApp', async () => {\n // Preserve the pre-seam arg branching exactly:\n // {app, relaunch} for app launches; {app, url} | {url} for deep links.\n const args =\n opts.url === undefined\n ? { app: opts.app, ...(opts.relaunch === undefined ? {} : { relaunch: opts.relaunch }) }\n : opts.app !== undefined\n ? { app: opts.app, url: opts.url }\n : { url: opts.url };\n const result = (await this.client.apps.open({ ...this.selection, ...args } as Parameters<\n AdClient['apps']['open']\n >[0])) as { appName?: string; appBundleId?: string };\n return { appName: result.appName, appBundleId: result.appBundleId };\n });\n }\n\n override listApps(): Promise<string[]> {\n return this.guard('listApps', async () => {\n const result = (await this.client.apps.list(\n Object.keys(this.selection).length\n ? (this.selection as Parameters<AdClient['apps']['list']>[0])\n : undefined,\n )) as unknown as string[];\n return result;\n });\n }\n\n override closeSession(): Promise<void> {\n if (!this.used) return Promise.resolve();\n return this.guard('closeSession', async () => {\n // Pre-seam behavior: close({}) — session override only when pinned.\n await this.client.sessions.close({ ...this.selection });\n });\n }\n}\n\n/**\n * Build the agent-device backend: the ONE place agent-device is called. Device\n * pinning is per-request in agent-device, so the backend holds a selection\n * object and spreads it into every call. With no config, selection is `{}` and\n * the client is default-constructed — requests are byte-identical to the\n * pre-seam process-global path (booted-sim auto-detect). Every method\n * normalizes errors via `toPhoneUseError`; no agent-device type or error ever\n * escapes this module.\n */\nexport function createAgentDeviceBackend(config?: DeviceConfig): DeviceBackend {\n return new AgentDeviceBackend(config);\n}\n","import { writeFile } from 'node:fs/promises';\nimport { BaseDeviceBackend } from '../backend.ts';\nimport {\n ALL_CAPABILITIES,\n type AlertAction,\n type BackendAlertResult,\n type Capability,\n type OpenAppResult,\n type PressTarget,\n type ScrollDirection,\n type Snapshot,\n} from '../device.ts';\nimport { PhoneUseError } from '../errors.ts';\n\n// ---------------------------------------------------------------------------\n// CloudSandboxBackend: drives a phone-use cloud sandbox (a simulator on a\n// remote worker) over the worker's sandbox-scoped RPC endpoint. This is the\n// client half of packages/cloud's worker protocol; it lives in the SDK so the\n// CLI/MCP/agent can attach to a sandbox without depending on @phone-use/cloud\n// (which also contains the server side and is not published).\n//\n// Wire protocol (shared with packages/cloud — keep in sync):\n// POST <endpoint>/rpc {method, args} -> {ok:true,result} | {ok:false,error}\n// ---------------------------------------------------------------------------\n\nexport type SandboxRpcMethod =\n | 'snapshot'\n | 'screenshot'\n | 'press'\n | 'longPress'\n | 'fill'\n | 'typeText'\n | 'pressKey'\n | 'scroll'\n | 'pan'\n | 'installApp'\n | 'waitForText'\n | 'systemAlert'\n | 'home'\n | 'back'\n | 'openApp'\n | 'listApps'\n | 'closeSession';\n\nexport type SandboxRpcRequest = { method: SandboxRpcMethod; args: unknown[] };\nexport type SandboxRpcSuccess = { ok: true; result: unknown };\nexport type SandboxRpcFailure = {\n ok: false;\n error: { message: string; code?: string | undefined; retryable?: boolean | undefined };\n};\nexport type SandboxRpcResponse = SandboxRpcSuccess | SandboxRpcFailure;\n\nexport type CloudSandboxBackendOptions = {\n endpoint: string;\n token: string;\n capabilities?: Capability[] | undefined;\n fetch?: typeof globalThis.fetch | undefined;\n};\n\nexport class CloudSandboxBackend extends BaseDeviceBackend {\n private readonly endpoint: string;\n private readonly token: string;\n private readonly fetchImpl: typeof globalThis.fetch;\n\n constructor(opts: CloudSandboxBackendOptions) {\n super('phone-use-cloud', opts.capabilities ?? ALL_CAPABILITIES);\n this.endpoint = opts.endpoint.replace(/\\/+$/, '');\n this.token = opts.token;\n this.fetchImpl = opts.fetch ?? globalThis.fetch;\n }\n\n private async rpc<T>(method: SandboxRpcMethod, ...args: unknown[]): Promise<T> {\n const response = await this.fetchImpl(`${this.endpoint}/rpc`, {\n method: 'POST',\n headers: {\n authorization: `Bearer ${this.token}`,\n 'content-type': 'application/json',\n },\n body: JSON.stringify({ method, args } satisfies SandboxRpcRequest),\n });\n const body = (await response.json().catch(() => ({}))) as\n | SandboxRpcResponse\n | { error?: string; message?: string };\n if (!response.ok || !('ok' in body)) {\n const message =\n ('error' in body && typeof body.error === 'string' ? body.error : undefined) ??\n ('message' in body ? body.message : undefined) ??\n `HTTP ${response.status}`;\n throw new PhoneUseError(message, { code: 'UNKNOWN', retryable: false });\n }\n if (!body.ok) {\n throw new PhoneUseError(body.error.message, {\n code: normalizeErrorCode(body.error.code),\n retryable: body.error.retryable ?? false,\n });\n }\n return body.result as T;\n }\n\n override snapshot(opts?: { interactiveOnly?: boolean; depth?: number }): Promise<Snapshot> {\n return this.rpc('snapshot', opts);\n }\n\n override async screenshot(opts: { path: string; overlayRefs?: boolean }): Promise<{ path: string }> {\n const result = await this.rpc<{ base64: string }>('screenshot', {\n overlayRefs: opts.overlayRefs,\n });\n await writeFile(opts.path, Buffer.from(result.base64, 'base64'));\n return { path: opts.path };\n }\n\n override press(target: PressTarget): Promise<void> {\n return this.rpc('press', target);\n }\n override longPress(ref: string, durationMs?: number): Promise<void> {\n return this.rpc('longPress', ref, durationMs);\n }\n override fill(ref: string, text: string): Promise<void> {\n return this.rpc('fill', ref, text);\n }\n override typeText(text: string): Promise<void> {\n return this.rpc('typeText', text);\n }\n override pressKey(key: 'return'): Promise<void> {\n return this.rpc('pressKey', key);\n }\n override scroll(direction: ScrollDirection): Promise<void> {\n return this.rpc('scroll', direction);\n }\n override pan(x: number, y: number, dx: number, dy: number, durationMs?: number): Promise<void> {\n return this.rpc('pan', x, y, dx, dy, durationMs);\n }\n override waitForText(text: string, timeoutMs?: number): Promise<void> {\n return this.rpc('waitForText', text, timeoutMs);\n }\n override systemAlert(action: AlertAction): Promise<BackendAlertResult> {\n return this.rpc('systemAlert', action);\n }\n override home(): Promise<void> {\n return this.rpc('home');\n }\n override back(): Promise<void> {\n return this.rpc('back');\n }\n override openApp(opts: { app?: string; url?: string; relaunch?: boolean }): Promise<OpenAppResult> {\n return this.rpc('openApp', opts);\n }\n override listApps(): Promise<string[]> {\n return this.rpc('listApps');\n }\n override closeSession(): Promise<void> {\n return this.rpc('closeSession');\n }\n\n /** Upload a zipped .app bundle (base64) and install it on the sandbox device. */\n installApp(base64Zip: string): Promise<{ installed?: string }> {\n return this.rpc('installApp', base64Zip);\n }\n}\n\n/**\n * Build a CloudSandboxBackend from explicit options or the environment:\n * PHONE_USE_SANDBOX_URL + PHONE_USE_SANDBOX_TOKEN (printed by\n * `phone-use sandbox env <id>`).\n */\nexport function createCloudSandboxBackend(config?: Partial<CloudSandboxBackendOptions>): CloudSandboxBackend {\n const endpoint = config?.endpoint ?? process.env.PHONE_USE_SANDBOX_URL;\n const token = config?.token ?? process.env.PHONE_USE_SANDBOX_TOKEN;\n if (!endpoint || !token) {\n throw new PhoneUseError(\n 'cloud sandbox backend needs PHONE_USE_SANDBOX_URL and PHONE_USE_SANDBOX_TOKEN (see `phone-use sandbox env <id>`)',\n { code: 'BACKEND_NOT_FOUND', retryable: false },\n );\n }\n return new CloudSandboxBackend({ ...config, endpoint, token });\n}\n\nfunction normalizeErrorCode(\n code: string | undefined,\n):\n | 'DEVICE_NOT_FOUND'\n | 'DEVICE_IN_USE'\n | 'SESSION_NOT_FOUND'\n | 'TIMEOUT'\n | 'ACTION_FAILED'\n | 'UNSUPPORTED_CAPABILITY'\n | 'BACKEND_NOT_FOUND'\n | 'ABORTED'\n | 'UNKNOWN' {\n const codes = new Set([\n 'DEVICE_NOT_FOUND',\n 'DEVICE_IN_USE',\n 'SESSION_NOT_FOUND',\n 'TIMEOUT',\n 'ACTION_FAILED',\n 'UNSUPPORTED_CAPABILITY',\n 'BACKEND_NOT_FOUND',\n 'ABORTED',\n 'UNKNOWN',\n ]);\n return codes.has(code ?? '') ? (code as ReturnType<typeof normalizeErrorCode>) : 'UNKNOWN';\n}\n","import { BaseDeviceBackend } from '../backend.ts';\nimport type {\n AlertAction,\n BackendAlertResult,\n Capability,\n OpenAppResult,\n PressTarget,\n ScrollDirection,\n Snapshot,\n} from '../device.ts';\nimport { ActionFailedError, DeviceNotFoundError, TimeoutError } from '../errors.ts';\n\n/**\n * A device-runner is addressed purely by URL, so it takes no DeviceConfig\n * platform/udid selection — only where to reach the runner and how to auth.\n */\nexport type DeviceRunnerConfig = {\n endpoint?: string | undefined;\n token?: string | undefined;\n timeoutMs?: number | undefined;\n};\n\nconst RUNNER_CAPABILITIES: readonly Capability[] = [\n 'snapshot',\n 'screenshot',\n 'press',\n 'fill',\n 'type',\n 'scroll',\n 'pan',\n 'openApp',\n 'home',\n];\n\n/**\n * Backend that speaks to an on-device runner: an XCTest-hosted JSON-RPC server\n * running ON the iPhone itself, which holds the automation privileges iOS\n * denies to ordinary apps.\n *\n * The endpoint is just a URL, so the same backend serves every topology:\n * - `http://127.0.0.1:45678` — port-forwarded from a paired host\n * - `http://<phone-ip>:45678` — straight over the LAN / tailnet\n * - `https://relay.example/d/<id>` — the runner dials out to a cloud relay,\n * which is what lets an agent anywhere drive the phone with no inbound\n * ports and no Mac in the loop.\n *\n * The wire format matches the shape proven by rounak/PhoneAgent: newline-free\n * JSON request/response over HTTP POST, one method per call.\n */\nexport class DeviceRunnerBackend extends BaseDeviceBackend {\n readonly #endpoint: string;\n readonly #token: string | undefined;\n readonly #timeoutMs: number;\n\n constructor(config?: DeviceRunnerConfig) {\n // BaseDeviceBackend owns backendName/capabilities — set them via super()\n // rather than redeclaring the fields.\n super('device-runner', RUNNER_CAPABILITIES);\n const endpoint = config?.endpoint ?? process.env.PHONE_USE_RUNNER_URL ?? 'http://127.0.0.1:45678';\n this.#endpoint = endpoint.replace(/\\/+$/, '');\n this.#token = config?.token ?? process.env.PHONE_USE_RUNNER_TOKEN;\n this.#timeoutMs = config?.timeoutMs ?? 30_000;\n }\n\n async #rpc<T>(method: string, params: Record<string, unknown> = {}): Promise<T> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.#timeoutMs);\n let res: Response;\n try {\n res = await fetch(this.#endpoint, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n ...(this.#token ? { authorization: `Bearer ${this.#token}` } : {}),\n },\n body: JSON.stringify({ jsonrpc: '2.0', id: Date.now(), method, params }),\n signal: controller.signal,\n });\n } catch (cause) {\n if (controller.signal.aborted) {\n throw new TimeoutError(`runner did not answer ${method} within ${this.#timeoutMs}ms`);\n }\n throw new DeviceNotFoundError(\n `cannot reach the on-device runner at ${this.#endpoint} — is it activated on the phone?`,\n { cause },\n );\n } finally {\n clearTimeout(timer);\n }\n\n if (!res.ok) {\n throw new ActionFailedError(`runner returned HTTP ${res.status} for ${method}`);\n }\n const body = (await res.json()) as { result?: T; error?: { message?: string } };\n if (body.error) {\n throw new ActionFailedError(body.error.message ?? `runner rejected ${method}`);\n }\n return body.result as T;\n }\n\n override async snapshot(opts?: {\n interactiveOnly?: boolean | undefined;\n depth?: number | undefined;\n }): Promise<Snapshot> {\n // The runner speaks its own compact wire shape; map it onto the SDK's\n // Snapshot contract so every consumer (CLI, MCP, agent, bench) is unaware\n // it is talking to a phone rather than a simulator.\n const wire = await this.#rpc<{\n app?: string;\n elements: Array<{\n ref: string;\n role?: string;\n label?: string;\n value?: string;\n enabled?: boolean;\n rect?: { x: number; y: number; w: number; h: number };\n }>;\n }>('get_tree', {\n interactiveOnly: opts?.interactiveOnly ?? false,\n depth: opts?.depth,\n });\n return {\n appBundleId: wire.app,\n appName: wire.app,\n nodes: (wire.elements ?? []).map((e) => ({\n ref: e.ref,\n role: e.role,\n type: e.role,\n label: e.label,\n value: e.value,\n enabled: e.enabled,\n rect: e.rect ? { x: e.rect.x, y: e.rect.y, width: e.rect.w, height: e.rect.h } : undefined,\n })),\n };\n }\n\n override async screenshot(opts: {\n path: string;\n overlayRefs?: boolean | undefined;\n }): Promise<{ path: string }> {\n const { base64 } = await this.#rpc<{ base64: string }>('get_screen_image', {\n overlayRefs: opts.overlayRefs ?? false,\n });\n const { writeFile } = await import('node:fs/promises');\n await writeFile(opts.path, Buffer.from(base64, 'base64'));\n return { path: opts.path };\n }\n\n override async press(target: PressTarget): Promise<void> {\n // PressTarget is {ref} | {x,y} — never a bare string, so narrow on the key.\n if ('ref' in target) {\n await this.#rpc('tap_element', { ref: target.ref });\n return;\n }\n await this.#rpc('tap', { x: target.x, y: target.y });\n }\n\n override async fill(ref: string, text: string): Promise<void> {\n await this.#rpc('enter_text', { ref, text, replace: true });\n }\n\n override async typeText(text: string): Promise<void> {\n await this.#rpc('enter_text', { text, replace: false });\n }\n\n override async scroll(direction: ScrollDirection): Promise<void> {\n await this.#rpc('scroll', { direction });\n }\n\n override async pan(x: number, y: number, dx: number, dy: number, durationMs = 300): Promise<void> {\n await this.#rpc('swipe', { x, y, dx, dy, durationMs });\n }\n\n override async home(): Promise<void> {\n await this.#rpc('home');\n }\n\n override async openApp(opts: {\n app?: string | undefined;\n url?: string | undefined;\n relaunch?: boolean | undefined;\n }): Promise<OpenAppResult> {\n return this.#rpc<OpenAppResult>('open_app', {\n app: opts.app,\n url: opts.url,\n relaunch: opts.relaunch ?? false,\n });\n }\n\n override async systemAlert(action: AlertAction): Promise<BackendAlertResult> {\n return this.#rpc<BackendAlertResult>('alert', { action });\n }\n\n override async closeSession(): Promise<void> {\n // The runner outlives any single client; nothing to tear down.\n }\n\n /** Liveness probe used by `phone-use doctor` and the relay health check. */\n async ping(): Promise<{ ok: boolean; ios?: string; device?: string }> {\n return this.#rpc('get_context');\n }\n}\n\nexport const createDeviceRunnerBackend = (config?: DeviceRunnerConfig): DeviceRunnerBackend =>\n new DeviceRunnerBackend(config);\n","import { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\n\n/** Per-call options an {@link ExecRunner} accepts. */\nexport type ExecOptions = {\n /** Kill the process after this many ms (rejects in the killed shape). */\n timeoutMs?: number | undefined;\n /** Replacement environment for the child process. */\n env?: Record<string, string> | undefined;\n};\n\n/** What an {@link ExecRunner} resolves with on exit 0. */\nexport type ExecResult = { stdout: string; stderr: string };\n\n/**\n * The process-execution seam (dependency-inject the spawn/exec runner\n * so unit tests run without the real binaries). Runners are dumb: resolve on\n * exit 0, reject with the execFile error shape otherwise — error normalization\n * to PhoneUseError happens at the call site, once.\n */\nexport type ExecRunner = (file: string, args: string[], opts?: ExecOptions) => Promise<ExecResult>;\n\nconst pExecFile = promisify(execFile);\n\nexport const defaultExecRunner: ExecRunner = async (file, args, opts) => {\n const { stdout, stderr } = await pExecFile(file, args, {\n encoding: 'utf8',\n // simctl `list devices -j` on a runtime-rich Mac can exceed the 1 MiB\n // default and fail spuriously — a failure the VPS test tier can never see.\n maxBuffer: 16 * 1024 * 1024,\n ...(opts?.timeoutMs === undefined ? {} : { timeout: opts.timeoutMs }),\n ...(opts?.env === undefined ? {} : { env: opts.env }),\n });\n return { stdout, stderr };\n};\n\n/** The execFile rejection shape runners produce (structural, for call sites). */\nexport type ExecError = Error & {\n code?: number | string | undefined;\n stdout?: string | undefined;\n stderr?: string | undefined;\n killed?: boolean | undefined;\n signal?: string | undefined;\n};\n\nexport function isExecError(err: unknown): err is ExecError {\n return err instanceof Error && ('code' in err || 'killed' in err || 'stderr' in err);\n}\n","import {\n type Action,\n type ActionResult,\n type ActOptions,\n buildObserveResult,\n type ElementQuery,\n executeAction,\n type ObserveResult,\n} from './actions.ts';\nimport type { DeviceBackend } from './backend.ts';\nimport type { Capability, ScrollDirection } from './device.ts';\nimport { SessionNotFoundError } from './errors.ts';\nimport { DeviceCore } from './observe.ts';\nimport { SecretStore } from './secrets.ts';\n\n/** The platform a {@link Device} runs on. */\nexport type DevicePlatform = 'ios' | 'android';\n/** Lifecycle state of a {@link Device} handle. */\nexport type DeviceStatus = 'running' | 'closed';\n\n/**\n * The Device lifecycle handle: id, pinned backend, close/dispose, idle lease +\n * reaper — plus the action verb surface layered onto the same type.\n * `ios.launch()` and `ios.connect()` return it; the future android engine will\n * share `createDeviceHandle`.\n */\nexport interface Device {\n /** udid (iOS) / serial (Android). */\n readonly id: string;\n /** Which platform this device runs. */\n readonly platform: DevicePlatform;\n /** Simulator/device name when known. */\n readonly name?: string | undefined;\n /** Name of the backend driving this device. */\n readonly backendName: string;\n /** The backend's declared capability set. */\n readonly capabilities: ReadonlySet<Capability>;\n /**\n * The pinned backend — `new DeviceContext(device.backend)` works today.\n * Backend calls through this handle count as activity for the idle lease.\n */\n readonly backend: DeviceBackend;\n /** true when launch() created the device — close() then also deletes it. */\n readonly createdByUs: boolean;\n /** Current lifecycle state. */\n readonly status: DeviceStatus;\n /** Sugar for `status === 'closed'`. */\n readonly isClosed: boolean;\n /** Re-arm the idle lease (ms overrides the configured window for this arm only). */\n extendLease(ms?: number): void;\n /** Canonical, idempotent shutdown. `await using` is sugar over this. */\n close(): Promise<void>;\n /** `await using` support — delegates to {@link Device.close}. */\n [Symbol.asyncDispose](): Promise<void>;\n\n // --- the action surface: flat hot path ------------------------------------\n /** Look at the screen: elements + rendered text + portable Action[]. */\n observe(opts?: { signal?: AbortSignal | undefined }): Promise<ObserveResult>;\n /** Tap by label/id query. Auto-waits; never throws for normal outcomes. */\n tap(target: string | ElementQuery, opts?: ActOptions): Promise<ActionResult>;\n /** Type text (optionally into a field resolved by query); %name% secrets substituted. */\n type(\n text: string,\n opts?: ActOptions & { field?: string | ElementQuery | undefined; submit?: boolean | undefined },\n ): Promise<ActionResult>;\n /** Execute a portable Action deterministically — no re-inference. */\n act(action: Action, opts?: ActOptions): Promise<ActionResult>;\n\n // --- grouped breadth -------------------------------------------------------\n /** App management: open by name/deep link, list installed, current app. */\n readonly apps: {\n /** Open an app by name/bundle id, or a deep link when `url` is set. */\n open(\n app: string,\n opts?: { relaunch?: boolean | undefined; url?: string | undefined; signal?: AbortSignal | undefined },\n ): Promise<ActionResult>;\n /** List installed app bundle ids. */\n list(opts?: { signal?: AbortSignal | undefined }): Promise<string[]>;\n /** The frontmost app name from the last observation (no new snapshot). */\n current(): string | undefined;\n };\n /** Screen-level verbs: scroll, screenshot, waitForText, alert, back, home. */\n readonly screen: {\n /** Scroll the active scroll view one step. */\n scroll(direction: ScrollDirection, opts?: { signal?: AbortSignal | undefined }): Promise<ActionResult>;\n /** Save a screenshot to `path`. */\n screenshot(opts: {\n path: string;\n signal?: AbortSignal | undefined;\n }): Promise<{ success: boolean; message: string; path?: string | undefined }>;\n /** Block until `text` appears on screen or the timeout elapses. */\n waitForText(\n text: string,\n opts?: { timeoutMs?: number | undefined; signal?: AbortSignal | undefined },\n ): Promise<ActionResult>;\n /** Read ('get'), accept, or dismiss a blocking system alert. */\n alert(\n action: 'get' | 'accept' | 'dismiss',\n opts?: { signal?: AbortSignal | undefined },\n ): Promise<ActionResult>;\n /** Navigate back. */\n back(opts?: { signal?: AbortSignal | undefined }): Promise<ActionResult>;\n /** Go to the home screen. */\n home(opts?: { signal?: AbortSignal | undefined }): Promise<ActionResult>;\n };\n /** %name% secret store — values substituted at execution, redacted everywhere else. */\n readonly secrets: SecretStore;\n}\n\n// The idle lease: an unref'd timer, so a LEAKED handle can never hold the\n// process open — and on expiry the reaper closes the device, so a leaked\n// handle can't poison the host with an orphaned booted sim either (the\n// bench-hang failure mode). Limits, honestly: this protects in-process leaks\n// only; a kill -9'd process orphans the sim until external cleanup — created\n// sims carry the `phone-use-` name prefix precisely so\n// `xcrun simctl list devices -j` can find and delete them.\nexport class IdleLease {\n private timer: ReturnType<typeof setTimeout> | null = null;\n private readonly windowMs: number | false;\n private readonly onExpire: () => void;\n\n constructor(windowMs: number | false, onExpire: () => void) {\n this.windowMs = windowMs;\n this.onExpire = onExpire;\n this.touch();\n }\n\n /** Re-arm with the configured window (no-op when disabled). */\n touch(): void {\n this.arm(this.windowMs);\n }\n\n /** Re-arm with a one-shot override window. */\n extend(ms?: number): void {\n this.arm(ms ?? this.windowMs);\n }\n\n private arm(ms: number | false): void {\n if (this.timer) clearTimeout(this.timer);\n this.timer = null;\n if (ms === false) return;\n const t = setTimeout(this.onExpire, ms);\n // Fake-timer objects may lack unref — guard, don't crash.\n t.unref?.();\n this.timer = t;\n }\n\n dispose(): void {\n if (this.timer) clearTimeout(this.timer);\n this.timer = null;\n }\n}\n\n/** Inputs to {@link createDeviceHandle} — what an engine supplies per device. */\nexport type CreateDeviceHandleOptions = {\n /** udid (iOS) / serial (Android). */\n id: string;\n /** Which platform the device runs. */\n platform: DevicePlatform;\n /** Simulator/device name when known. */\n name?: string | undefined;\n /** The backend pinned to this device. */\n backend: DeviceBackend;\n /** true when the engine created the device (close() then also deletes it). */\n createdByUs: boolean;\n /** Idle window in ms; false disables the lease. Default 180_000 (3m). */\n idleTimeoutMs?: number | false | undefined;\n /** Observer for reaper-initiated closes (the SDK never logs). */\n onIdleClose?: ((device: Device) => void) | undefined;\n /** Initial %name% secret values. */\n secrets?: Record<string, string> | undefined;\n /** @internal harness seam — supplies the verb core (DeviceContext extends DeviceCore). */\n coreFactory?: ((backend: DeviceBackend) => DeviceCore) | undefined;\n /** Platform teardown: shutdown (+ delete when createdByUs). */\n doClose: () => Promise<void>;\n};\n\n/**\n * Assemble a Device handle over a backend: lease/reaper, verb surface,\n * close/dispose semantics. Engine authors (ios here, android in item 7b,\n * phone-backend-* third parties) build on this; tests fabricate devices with\n * it over a FakeBackend.\n */\nexport function createDeviceHandle(opts: CreateDeviceHandleOptions): Device {\n let status: DeviceStatus = 'running';\n let closePromise: Promise<void> | null = null;\n\n const close = (): Promise<void> => {\n closePromise ??= (async () => {\n status = 'closed';\n lease.dispose();\n // Best-effort session close; a session may never have opened (agent-device\n // sessions are lazy), so swallow the not-found case.\n await opts.backend.closeSession().catch(() => undefined);\n await opts.doClose();\n })();\n return closePromise;\n };\n\n const lease = new IdleLease(opts.idleTimeoutMs ?? 180_000, () => {\n void close()\n .catch(() => undefined)\n .then(() => opts.onIdleClose?.(device));\n });\n\n // Backend calls through the handle count as lease activity — without this,\n // a long bench run driving DeviceContext(device.backend) would be reaped\n // mid-run, recreating the exact hazard the lease exists to prevent.\n const touchingBackend = new Proxy(opts.backend, {\n get(target, prop, receiver) {\n const value = Reflect.get(target, prop, receiver);\n if (typeof value !== 'function') return value;\n return (...args: unknown[]) => {\n if (status === 'running') lease.touch();\n return (value as (...a: unknown[]) => unknown).apply(target, args);\n };\n },\n });\n\n // The verb surface drives its own DeviceCore over the lease-touching proxy,\n // so every verb call counts as activity. One brain: all logic lives in\n // DeviceCore + executeAction; the Device only wires them together.\n const core = opts.coreFactory?.(touchingBackend) ?? new DeviceCore(touchingBackend);\n const secrets = new SecretStore(opts.secrets);\n\n const assertOpen = (): void => {\n if (status === 'closed') throw new SessionNotFoundError(`device ${opts.id} is closed`);\n };\n\n const toQuery = (target: string | ElementQuery): ElementQuery =>\n typeof target === 'string' ? { label: target } : target;\n\n const device: Device = {\n id: opts.id,\n platform: opts.platform,\n name: opts.name,\n backendName: opts.backend.backendName,\n capabilities: opts.backend.capabilities,\n backend: touchingBackend,\n createdByUs: opts.createdByUs,\n get status() {\n return status;\n },\n get isClosed() {\n return status === 'closed';\n },\n extendLease(ms?: number) {\n if (status === 'running') lease.extend(ms);\n },\n close,\n [Symbol.asyncDispose]: close,\n\n observe() {\n assertOpen();\n return buildObserveResult(core, secrets);\n },\n tap(target, actOpts = {}) {\n assertOpen();\n return executeAction(\n core,\n { formatVersion: 0, verb: 'tap', target: toQuery(target) },\n actOpts,\n secrets,\n );\n },\n type(text, actOpts = {}) {\n assertOpen();\n const { field, submit, ...rest } = actOpts;\n const action: Action =\n field === undefined\n ? { formatVersion: 0, verb: 'type', params: { text, submit } }\n : { formatVersion: 0, verb: 'fill', target: toQuery(field), params: { text, submit } };\n return executeAction(core, action, rest, secrets);\n },\n act(action, actOpts = {}) {\n assertOpen();\n return executeAction(core, action, actOpts, secrets);\n },\n\n apps: {\n open(app, o = {}) {\n assertOpen();\n const action: Action =\n o.url === undefined\n ? { formatVersion: 0, verb: 'openApp', params: { app, relaunch: o.relaunch } }\n : { formatVersion: 0, verb: 'openUrl', params: { app, url: o.url } };\n return executeAction(core, action, { signal: o.signal }, secrets);\n },\n list(o = {}) {\n assertOpen();\n void o;\n return core.listApps();\n },\n current() {\n return core.currentApp();\n },\n },\n screen: {\n scroll(direction, o = {}) {\n assertOpen();\n return executeAction(\n core,\n { formatVersion: 0, verb: 'scroll', params: { direction } },\n { signal: o.signal },\n secrets,\n );\n },\n async screenshot(o) {\n assertOpen();\n const path = await core.screenshot(o.path);\n return { success: true, message: `screenshot saved`, path };\n },\n waitForText(text, o = {}) {\n assertOpen();\n return executeAction(\n core,\n { formatVersion: 0, verb: 'waitForText', params: { text } },\n { signal: o.signal, timeoutMs: o.timeoutMs },\n secrets,\n );\n },\n alert(action, o = {}) {\n assertOpen();\n if (action === 'get') {\n return core.handleAlert('get').then((r) => ({\n success: r.present,\n message: r.present ? `alert: ${r.description ?? ''}` : 'no system alert is showing',\n }));\n }\n return executeAction(\n core,\n { formatVersion: 0, verb: 'alert', params: { alertAction: action } },\n { signal: o.signal },\n secrets,\n );\n },\n back(o = {}) {\n assertOpen();\n return executeAction(core, { formatVersion: 0, verb: 'back' }, { signal: o.signal }, secrets);\n },\n home(o = {}) {\n assertOpen();\n return executeAction(core, { formatVersion: 0, verb: 'home' }, { signal: o.signal }, secrets);\n },\n },\n secrets,\n };\n return device;\n}\n","import type { IosDeviceConfig } from '../config.ts';\nimport { ActionFailedError, DeviceNotFoundError, TimeoutError, toPhoneUseError } from '../errors.ts';\nimport { defaultExecRunner, type ExecRunner, isExecError } from '../exec.ts';\nimport { createDeviceHandle, type Device } from '../lifecycle.ts';\nimport { createAgentDeviceBackend } from './agent-device.ts';\n\n// ---------------------------------------------------------------------------\n// The iOS engine (engine-as-object): ios.launch() creates\n// and boots a DEDICATED simulator via simctl — no more \"whatever is booted\" —\n// and returns a Device whose backend is pinned to that udid. ios.connect()\n// reattaches; its no-arg form is the sole survivor of the old booted-sim\n// auto-detect. Scripts never branch on locality: connect(endpoint) for cloud\n// devices is reserved API — local-only for now.\n//\n// Created sims are named `phone-use-<hex>` deliberately: if a process is\n// kill -9'd, the in-process reaper can't run, and the name prefix is how\n// orphans are found (`xcrun simctl list devices -j` | filter the prefix).\n// ---------------------------------------------------------------------------\n\ntype CommonIosOptions = {\n /** Custom simulator device set directory (maps to `simctl --set`). */\n simulatorDeviceSet?: string | undefined;\n /** agent-device session/daemon pinning, passed through to the backend. */\n session?: string | undefined;\n daemonBaseUrl?: string | undefined;\n daemonAuthToken?: string | undefined;\n /** Idle lease window in ms (false disables). Default 180_000 (3 min). */\n idleTimeoutMs?: number | false | undefined;\n /** Observer for reaper-initiated closes. */\n onIdleClose?: ((device: Device) => void) | undefined;\n /** Initial %name% secret values (see Device.secrets). */\n secrets?: Record<string, string> | undefined;\n /** @internal harness seam — supplies the verb core (see createDeviceHandle). */\n coreFactory?:\n | ((backend: import('../backend.ts').DeviceBackend) => import('../observe.ts').DeviceCore)\n | undefined;\n /**\n * Probe the agent-device daemon right away (one listApps) so a missing\n * daemon fails at launch instead of on first use. Default false: sessions\n * open lazily and a probe requires the daemon to exist.\n */\n failFast?: boolean | undefined;\n /** @internal test seam — DI'd process runner. */\n exec?: ExecRunner | undefined;\n};\n\n/** Options for `ios.launch()` — device type, runtime, name, boot ceiling. */\nexport type IosLaunchOptions = CommonIosOptions & {\n /** simctl device type, e.g. \"iPhone 16\" (the default). */\n deviceType?: string | undefined;\n /** simctl runtime id; omitted → newest compatible. */\n runtime?: string | undefined;\n /** Simulator name; default `phone-use-<hex>` (the orphan-discovery prefix). */\n name?: string | undefined;\n /** Boot wait ceiling for `simctl bootstatus` (default 120_000 ms). */\n bootTimeoutMs?: number | undefined;\n};\n\n/** Options for `ios.connect()`. */\nexport type IosConnectOptions = CommonIosOptions & {\n /** Boot wait ceiling when connect has to boot a shut-down sim (default 120_000 ms). */\n bootTimeoutMs?: number | undefined;\n};\n\nconst UDID_RE = /^[0-9A-F]{8}(-[0-9A-F]{4}){3}-[0-9A-F]{12}$/i;\n\ntype SimctlDeviceRow = { udid: string; state: string; name?: string; isAvailable?: boolean };\ntype SimctlList = { devices: Record<string, SimctlDeviceRow[]> };\n\nfunction simctlArgs(setPath: string | undefined, args: string[]): string[] {\n return setPath === undefined ? ['simctl', ...args] : ['simctl', '--set', setPath, ...args];\n}\n\n// Exit 149 = \"operation not allowed in current state\" (already booted /\n// already shut down). Code first, stderr regex as fallback — Apple rewords\n// messages; the numeric code is the stable signal.\nfunction isAlreadyInState(err: unknown): boolean {\n if (!isExecError(err)) return false;\n if (err.code === 149) return true;\n return /current state.*(Booted|Shutdown)/i.test(err.stderr ?? '');\n}\n\nasync function runSimctl(\n exec: ExecRunner,\n setPath: string | undefined,\n args: string[],\n opts: { timeoutMs?: number | undefined; tolerateState?: boolean | undefined } = {},\n): Promise<string> {\n try {\n const r = await exec(\n 'xcrun',\n simctlArgs(setPath, args),\n opts.timeoutMs === undefined ? undefined : { timeoutMs: opts.timeoutMs },\n );\n return r.stdout;\n } catch (err) {\n if (opts.tolerateState && isAlreadyInState(err)) return '';\n if (isExecError(err)) {\n if (err.killed || err.signal) {\n throw new TimeoutError(\n `simctl ${args[0]} timed out${opts.timeoutMs ? ` after ${opts.timeoutMs}ms` : ''}`,\n {\n cause: err,\n },\n );\n }\n throw new ActionFailedError(\n `simctl ${args[0]} failed (exit ${String(err.code ?? '?')}): ${(err.stderr ?? err.message).trim()}`,\n { details: { backendCode: String(err.code ?? 'EXEC') }, cause: err },\n );\n }\n throw toPhoneUseError(err);\n }\n}\n\nfunction parseCreatedUdid(stdout: string): string {\n const lines = stdout\n .split('\\n')\n .map((l) => l.trim())\n .filter(Boolean);\n const last = lines[lines.length - 1] ?? '';\n if (!UDID_RE.test(last)) {\n throw new ActionFailedError(\n `could not parse udid from simctl create output: ${JSON.stringify(stdout.slice(0, 200))}`,\n );\n }\n return last;\n}\n\nfunction parseList(stdout: string): SimctlDeviceRow[] {\n let parsed: SimctlList;\n try {\n parsed = JSON.parse(stdout) as SimctlList;\n } catch (err) {\n throw new ActionFailedError('could not parse simctl list output as JSON', { cause: err });\n }\n return Object.values(parsed.devices ?? {}).flat();\n}\n\nfunction makeBackendConfig(udid: string, opts: CommonIosOptions): IosDeviceConfig {\n return {\n platform: 'ios',\n udid,\n ...(opts.simulatorDeviceSet === undefined ? {} : { simulatorDeviceSet: opts.simulatorDeviceSet }),\n // The daemon binds one session to one device: a udid-pinned Device on the\n // shared \"default\" session collides with whatever bound it first (live\n // Mac finding). A udid-derived session name is what makes two Devices\n // independent; deterministic so reconnects reuse the same session.\n session: opts.session ?? `phone-use-${udid}`,\n ...(opts.daemonBaseUrl === undefined ? {} : { daemonBaseUrl: opts.daemonBaseUrl }),\n ...(opts.daemonAuthToken === undefined ? {} : { daemonAuthToken: opts.daemonAuthToken }),\n };\n}\n\nasync function bootAndWait(\n exec: ExecRunner,\n setPath: string | undefined,\n udid: string,\n bootTimeoutMs: number,\n): Promise<void> {\n await runSimctl(exec, setPath, ['boot', udid], { tolerateState: true });\n // -b boots if needed, closing the boot/bootstatus race; blocks until booted.\n await runSimctl(exec, setPath, ['bootstatus', udid, '-b'], { timeoutMs: bootTimeoutMs });\n}\n\nasync function finishHandle(\n udid: string,\n name: string | undefined,\n createdByUs: boolean,\n opts: CommonIosOptions,\n exec: ExecRunner,\n): Promise<Device> {\n const backend = createAgentDeviceBackend(makeBackendConfig(udid, opts));\n if (opts.failFast) await backend.listApps();\n return createDeviceHandle({\n id: udid,\n platform: 'ios',\n name,\n backend,\n createdByUs,\n idleTimeoutMs: opts.idleTimeoutMs,\n onIdleClose: opts.onIdleClose,\n secrets: opts.secrets,\n coreFactory: opts.coreFactory,\n doClose: async () => {\n await runSimctl(exec, opts.simulatorDeviceSet, ['shutdown', udid], { tolerateState: true });\n if (createdByUs) await runSimctl(exec, opts.simulatorDeviceSet, ['delete', udid]);\n },\n });\n}\n\n/**\n * Create and boot a DEDICATED simulator via simctl — no more \"whatever is\n * booted\" — and return a {@link Device} pinned to its udid. Created sims are\n * named `phone-use-<hex>` deliberately: if the process is kill -9'd the\n * in-process reaper can't run, and the name prefix is how orphans are found.\n * `close()` shuts the sim down AND deletes it (we created it); a failed boot\n * best-effort-deletes before rethrowing.\n */\nasync function launch(options: IosLaunchOptions = {}): Promise<Device> {\n const exec = options.exec ?? defaultExecRunner;\n const deviceType = options.deviceType ?? 'iPhone 16';\n const name = options.name ?? `phone-use-${Math.random().toString(16).slice(2, 10)}`;\n const bootTimeoutMs = options.bootTimeoutMs ?? 120_000;\n\n const createArgs = [\n 'create',\n name,\n deviceType,\n ...(options.runtime === undefined ? [] : [options.runtime]),\n ];\n const udid = parseCreatedUdid(await runSimctl(exec, options.simulatorDeviceSet, createArgs));\n\n try {\n await bootAndWait(exec, options.simulatorDeviceSet, udid, bootTimeoutMs);\n } catch (err) {\n // We created it and it never booted — best-effort delete so the failure\n // doesn't leak a sim, then rethrow the original error.\n await runSimctl(exec, options.simulatorDeviceSet, ['delete', udid]).catch(() => undefined);\n throw err;\n }\n\n return finishHandle(udid, name, true, options, exec);\n}\n\n/**\n * Reattach to an existing simulator by udid (booting it if shut down). The\n * no-arg form is the sole survivor of the old booted-sim auto-detect: it\n * attaches to the first booted, available sim. `close()` on a connected\n * device shuts it down but never deletes it.\n */\nasync function connect(udid?: string, options: IosConnectOptions = {}): Promise<Device> {\n const exec = options.exec ?? defaultExecRunner;\n const bootTimeoutMs = options.bootTimeoutMs ?? 120_000;\n\n if (udid === undefined) {\n // The surviving auto-detect: attach to the first booted, available sim.\n const rows = parseList(\n await runSimctl(exec, options.simulatorDeviceSet, ['list', 'devices', 'booted', '-j']),\n );\n const booted = rows.find((d) => d.state === 'Booted' && d.isAvailable !== false);\n if (!booted) throw new DeviceNotFoundError('no booted simulator — use ios.launch() or boot one');\n return finishHandle(booted.udid, booted.name, false, options, exec);\n }\n\n const rows = parseList(await runSimctl(exec, options.simulatorDeviceSet, ['list', 'devices', '-j']));\n const row = rows.find((d) => d.udid.toLowerCase() === udid.toLowerCase());\n if (!row) throw new DeviceNotFoundError(`no simulator with udid ${udid}`);\n if (row.state !== 'Booted') await bootAndWait(exec, options.simulatorDeviceSet, row.udid, bootTimeoutMs);\n return finishHandle(row.udid, row.name, false, options, exec);\n}\n\n/**\n * The iOS engine object (Playwright-style): `ios.launch()` for a dedicated\n * simulator, `ios.connect()` to reattach. Both return the same Device type.\n */\nexport const ios = {\n /** Create + boot a dedicated simulator and return a Device pinned to it. */\n launch,\n /** Reattach to an existing simulator (no-arg: first booted sim). */\n connect,\n} as const;\n","/**\n * @phone-use/sdk — the device runtime SDK: engine-as-object lifecycle\n * (ios.launch/connect → Device), Device backends, config, errors, capabilities,\n * and the action verb surface.\n *\n * The test double (FakeBackend) lives on the \"@phone-use/sdk/testing\" subpath,\n * deliberately not re-exported here.\n */\n/** The published package version (kept in sync with package.json by the release flow). */\nexport const VERSION = '0.3.0';\n\nexport {\n type Action,\n type ActionResult,\n type ActionVerb,\n type ActOptions,\n buildObserveResult,\n type CompiledSkill,\n type ElementQuery,\n executeAction,\n type ObservedElement,\n type ObserveResult,\n toActions,\n} from './actions.ts';\nexport {\n type BackendFactory,\n BaseDeviceBackend,\n type DeviceBackend,\n getBackendFactory,\n listBackends,\n registerBackend,\n} from './backend.ts';\nexport { createAgentDeviceBackend } from './backends/agent-device.ts';\nexport {\n CloudSandboxBackend,\n type CloudSandboxBackendOptions,\n createCloudSandboxBackend,\n type SandboxRpcMethod,\n type SandboxRpcRequest,\n type SandboxRpcResponse,\n} from './backends/cloud-sandbox.ts';\nexport { createDeviceRunnerBackend, DeviceRunnerBackend } from './backends/device-runner.ts';\nexport { type IosConnectOptions, type IosLaunchOptions, ios } from './backends/ios.ts';\nexport type { AndroidDeviceConfig, CommonDeviceConfig, DeviceConfig, IosDeviceConfig } from './config.ts';\nexport type {\n AlertAction,\n BackendAlertResult,\n Capability,\n OpenAppResult,\n PressTarget,\n Rect,\n ScrollDirection,\n Snapshot,\n SnapshotNode,\n} from './device.ts';\nexport { ALL_CAPABILITIES } from './device.ts';\nexport {\n AbortedError,\n ActionFailedError,\n DeviceInUseError,\n DeviceNotFoundError,\n PhoneUseError,\n type PhoneUseErrorCode,\n type PhoneUseErrorDetails,\n SessionNotFoundError,\n TimeoutError,\n toPhoneUseError,\n UnsupportedCapabilityError,\n} from './errors.ts';\nexport {\n type CreateDeviceHandleOptions,\n createDeviceHandle,\n type Device,\n type DevicePlatform,\n type DeviceStatus,\n} from './lifecycle.ts';\nexport type {\n ActionEvidence,\n AlertOutcome,\n Observation,\n RenderState,\n Resolution,\n ResolveOpts,\n UiElement,\n} from './observe.ts';\nexport { DeviceCore, describeError, labelMatches, matchInElements } from './observe.ts';\nexport { SecretStore } from './secrets.ts';\n\n// Built-in backend registration — explicit, here, so importing the barrel\n// registers it (documented; sideEffects:false refers to bundler tree-shaking\n// of the *published* dist, where the barrel is the entry).\nimport { registerBackend as _register } from './backend.ts';\nimport { createAgentDeviceBackend as _createAd } from './backends/agent-device.ts';\n\n_register('agent-device', _createAd);\n"],"mappings":"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"}
|