agent-device 0.16.13 → 0.17.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/android-multitouch-helper/dist/{agent-device-android-multitouch-helper-0.16.13.apk → agent-device-android-multitouch-helper-0.17.0.apk} +0 -0
- package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.17.0.apk.sha256 +1 -0
- package/android-multitouch-helper/dist/{agent-device-android-multitouch-helper-0.16.13.manifest.json → agent-device-android-multitouch-helper-0.17.0.manifest.json} +4 -4
- package/android-snapshot-helper/dist/{agent-device-android-snapshot-helper-0.16.13.apk → agent-device-android-snapshot-helper-0.17.0.apk} +0 -0
- package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.17.0.apk.sha256 +1 -0
- package/android-snapshot-helper/dist/{agent-device-android-snapshot-helper-0.16.13.manifest.json → agent-device-android-snapshot-helper-0.17.0.manifest.json} +6 -6
- package/dist/src/1352.js +1 -1
- package/dist/src/221.js +4 -4
- package/dist/src/2415.js +29 -29
- package/dist/src/2805.js +1 -1
- package/dist/src/5792.js +1 -1
- package/dist/src/6232.js +1 -1
- package/dist/src/7599.js +4 -3
- package/dist/src/8020.js +1 -0
- package/dist/src/8699.js +1 -1
- package/dist/src/940.js +1 -1
- package/dist/src/9533.js +1 -1
- package/dist/src/android-snapshot-helper.d.ts +1 -0
- package/dist/src/apple.js +1 -1
- package/dist/src/args.js +20 -14
- package/dist/src/cli.js +9 -9
- package/dist/src/command-metadata.js +1 -1
- package/dist/src/contracts.d.ts +1 -0
- package/dist/src/find.js +1 -1
- package/dist/src/finders.d.ts +1 -0
- package/dist/src/generic.js +9 -9
- package/dist/src/index.d.ts +19 -1
- package/dist/src/interaction.js +1 -1
- package/dist/src/lease.js +1 -1
- package/dist/src/react-native.js +1 -1
- package/dist/src/record-trace.js +3 -3
- package/dist/src/selectors.d.ts +1 -0
- package/dist/src/session.js +11 -11
- package/dist/src/snapshot.js +2 -2
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedGesture.h +4 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedGesture.m +71 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Alert.swift +41 -7
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +154 -11
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandJournal.swift +11 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Exceptions.swift +12 -4
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift +26 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Lifecycle.swift +8 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift +7 -1
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift +571 -56
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Transport.swift +21 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TvRemote.swift +11 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests.swift +13 -2
- package/ios-runner/README.md +13 -0
- package/package.json +1 -1
- package/server.json +2 -2
- package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.16.13.apk.sha256 +0 -1
- package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.16.13.apk.sha256 +0 -1
package/dist/src/args.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{listCliCommandNames as e}from"./5792.js";import{getCliCommandSchema as t,getCommandSchema as o,applyCommandDefaults as a,GLOBAL_FLAG_KEYS as s,getFlagDefinition as n,getFlagDefinitions as r}from"./1352.js";import{parseSourceValue as i,buildPrimaryEnvVarName as l}from"./1010.js";import{AppError as
|
|
1
|
+
import{listCliCommandNames as e}from"./5792.js";import{getCliCommandSchema as t,getCommandSchema as o,applyCommandDefaults as a,GLOBAL_FLAG_KEYS as s,getFlagDefinition as n,getFlagDefinitions as r}from"./1352.js";import{parseSourceValue as i,buildPrimaryEnvVarName as l}from"./1010.js";import{AppError as c}from"./9152.js";function d(e,t){for(let[o,a]of Object.entries(t))void 0!==a&&(e[o]=a);return e}let p=[{label:"help workflow",description:"Normal bootstrap, exploration, and validation loop"},{label:"help debugging",description:"Logs, network, alerts, diagnostics, and traces"},{label:"help react-native",description:"React Native app automation hazards, overlays, Metro, and routing"},{label:"help react-devtools",description:"React Native performance, profiling, component tree, and renders"},{label:"help physical-device",description:"Connected phone/tablet setup and iOS signing prerequisites"},{label:"help remote",description:"Remote/cloud config, tenants, leases, and local service tunnels"},{label:"help macos",description:"Desktop, frontmost-app, and menu bar surfaces"},{label:"help dogfood",description:"Exploratory QA report workflow"}],u=["Default loop: devices/apps -> open -> snapshot -i -> press/fill/get/is/wait/find -> verify -> close.",'Use selectors or refs as positional targets: id="submit", label="Allow", or @e12 from snapshot -i.',"Plain snapshot reads state; snapshot -i refreshes current interactive refs only.","Default snapshot text is an agent-facing, token-efficient view for planning and targeting actions.","Read-only visible/state question: use snapshot/get/is/find; use snapshot -i only when refs are needed.","Anti-pattern: snapshot -i followed by snapshot -i | grep ...; prior refs stay valid until app state changes, and --force-full is the explicit full re-read.","Truncated text/input preview: expand first with snapshot -s @e12, not get text.","React Native apps: read help react-native for Metro, DevTools routing, and RN-specific blockers; use react-native dismiss-overlay for LogBox/RedBox overlays.","Android RN/Expo Metro: direct Android localhost URL opens with a port auto-configure host reachability.",'Expo Go/dev clients: use the provided URL when given; on iOS prefer open "Expo Go" <url>; Android URL opens infer the foreground package for logs/perf when possible.',"Install flows: install/install-from-source first, then open the installed id with --relaunch.",'Text: fill \'id="field-email"\' "qa@example.com" replaces; type appends after press.','Clearing text: do not use fill <target> ""; use a visible clear/reset control or report that clearing is unsupported.',"Android IME capture: if fill says input was captured by the keyboard/IME, inspect keyboard state and switch/disable handwriting before retrying; do not loop fill/type.","Implicit default sessions are scoped to the current worktree; use --session only when intentionally sharing a named session.","Run mutating commands serially within one session; parallelize only read-only commands or separate sessions/devices.","Clipboard limits: iOS Allow Paste cannot be automated through XCUITest; prefill with clipboard write. Android non-ASCII should use fill/type, not raw adb input.","After mutation: refs are stale. If the next target is known, use its selector directly; otherwise refresh with snapshot -i, scoped with -s when a stable container is known.","Raw coordinates are fallback-only: use snapshot -i -c --json rects when iOS refs no-op or child refs are missing.",'Batch JSON steps use "command" and structured "input"; legacy "positionals"/"flags" steps still run in CLI but are deprecated until the next major version.',"Navigation: app-owned back uses back; system back uses back --system.","Verification commands must name the expected text/selector; bare screenshots/snapshots are not enough.","Debug evidence: Session state contains request diagnostics and runner.log; use logs clear --restart/mark/path, trace, and network dump --include headers for app evidence.","Use agent-device commands in final plans; raw platform tools, pseudo commands, and helper prose are wrong.","Full operating guide: agent-device help workflow. Exploratory QA: agent-device help dogfood."],f=["Default config files: ~/.agent-device/config.json, ./agent-device.json","Use --config <path> or AGENT_DEVICE_CONFIG to load one explicit config file."],h=[{label:"AGENT_DEVICE_SESSION",description:"Explicit session name"},{label:"AGENT_DEVICE_PLATFORM",description:"Default platform binding"},{label:"AGENT_DEVICE_SESSION_LOCK",description:"Bound-session conflict mode"},{label:"AGENT_DEVICE_DAEMON_BASE_URL",description:"Connect to remote daemon"},{label:"AGENT_DEVICE_DAEMON_AUTH_TOKEN",description:"Remote daemon service/API token"},{label:"AGENT_DEVICE_CLOUD_BASE_URL",description:"Bridge/control-plane API origin for cloud auth and /api-keys"}],g=["agent-device open Settings --platform ios","agent-device open TextEdit --platform macos","agent-device snapshot -i","agent-device react-devtools get tree --depth 3",'agent-device fill @e3 "test@example.com"',"agent-device replay ./session.ad","agent-device test ./suite --platform android"],m={workflow:{summary:"Normal agent-device bootstrap, exploration, and validation loop",body:`agent-device help workflow
|
|
2
2
|
|
|
3
3
|
Version-matched operating guide for normal agent-device work.
|
|
4
4
|
|
|
@@ -27,7 +27,8 @@ Bootstrap:
|
|
|
27
27
|
agent-device prepare ios-runner --platform ios --timeout 240000
|
|
28
28
|
If app id is unknown, plan devices, apps, then open <discovered-app-id>. Discovery is not enough when the task asks to open/start the app.
|
|
29
29
|
Install arguments are app/package id then artifact path. If the task says install, use install; use reinstall only when explicitly requested. Fresh runtime state is open --relaunch after install.
|
|
30
|
-
In Apple CI, run prepare ios-runner after boot/install and before replay/test. prepare ios-runner builds/reuses the XCTest runner
|
|
30
|
+
In Apple CI, run prepare ios-runner after boot/install and before replay/test. prepare ios-runner builds/reuses the XCTest runner, health-checks it with a lightweight command, and retries one stuck/non-connecting runner launch before the first snapshot pays that setup cost.
|
|
31
|
+
CI may cache ~/.agent-device/ios-runner/derived with an exact key that includes the agent-device package and Xcode version. Avoid broad restore-key fallbacks; prepare ios-runner already recovers bad restored runner artifacts and one retryable non-connecting runner launch. Runner build/start output is written to the session's runner.log; daemon.log is for daemon lifecycle/startup issues.
|
|
31
32
|
Do not open artifact paths or invent package ids. If apps lookup misses the target and no URL/artifact is provided, ask or stop.
|
|
32
33
|
|
|
33
34
|
Snapshots and refs:
|
|
@@ -112,7 +113,8 @@ Validation and evidence:
|
|
|
112
113
|
Prefer provided testIDs/ids/selectors for verification; use visible text when no durable selector is provided.
|
|
113
114
|
If task says snapshot, use snapshot. If it asks visual evidence, use screenshot.
|
|
114
115
|
Icon/tappable visual proof: screenshot --overlay-refs. Flag is --overlay-refs.
|
|
115
|
-
|
|
116
|
+
If snapshot returns a sparse/AX-unavailable state, refs are not reliable. Use plain screenshot, not screenshot --overlay-refs, navigate with coordinates if needed, then retry snapshot -i after reaching another screen; the AX failure may be screen-specific.
|
|
117
|
+
Startup/CPU/memory/frame first pass: perf metrics --json (bare perf and metrics are aliases). Focused frame/jank health: perf frames --json. Replay maintenance: replay -u ./flow.ad.
|
|
116
118
|
Recording: record start/stop. By default, stop burns touch overlays into the video; use record start --hide-touches for the fastest raw recording. Android adb screenrecord has a 180s platform limit, so longer Android recordings are returned as multiple MP4 chunks. For gesture-heavy iOS simulator proof videos, prefer --hide-touches because overlay timing depends on a stable runner session while gestures are executing. Tracing: trace start ./trace.log, trace stop ./trace.log. Paths are positional.
|
|
117
119
|
Stable known flow: batch ./steps.json, not workflow batch.
|
|
118
120
|
Inline batch JSON example:
|
|
@@ -187,6 +189,9 @@ Alerts:
|
|
|
187
189
|
|
|
188
190
|
Diagnostics and traces:
|
|
189
191
|
Use --debug for CLI/daemon diagnostic ids and log paths.
|
|
192
|
+
Open output includes Session state; JSON also includes runnerLogPath and requestLogPath.
|
|
193
|
+
Session requests/<request-id>.ndjson holds daemon request diagnostics; session runner.log holds Apple runner/xcodebuild output.
|
|
194
|
+
daemon.log is global daemon lifecycle evidence, not the primary per-run log.
|
|
190
195
|
Use trace for low-level session diagnostics around one repro:
|
|
191
196
|
agent-device trace start ./traces/diagnostics.trace
|
|
192
197
|
agent-device press 'id="load-diagnostics"'
|
|
@@ -262,7 +267,7 @@ Example:
|
|
|
262
267
|
agent-device react-devtools profile report @c5
|
|
263
268
|
agent-device network dump --include headers
|
|
264
269
|
|
|
265
|
-
Use snapshot, screenshot, logs, network, and perf for device/app runtime evidence. Use react-devtools only when component internals or React rendering behavior matters.`},"react-native":{summary:"React Native app automation hazards and routing",body:`agent-device help react-native
|
|
270
|
+
Use snapshot, screenshot, logs, network, and perf metrics for device/app runtime evidence. Use react-devtools only when component internals or React rendering behavior matters.`},"react-native":{summary:"React Native app automation hazards and routing",body:`agent-device help react-native
|
|
266
271
|
|
|
267
272
|
Use this when the target app is React Native, Expo, or a React Native dev client.
|
|
268
273
|
This topic covers React Native-specific automation hazards and routes deeper
|
|
@@ -291,17 +296,18 @@ Overlays and busy RN UIs:
|
|
|
291
296
|
Do not manually press warning/error text bodies, collapsed banner bodies, full-screen warning parents, or broad LogBox/RedBox refs. The dismiss-overlay command owns the narrow LogBox/RedBox targeting policy.
|
|
292
297
|
Report the overlay in the final summary. Use screenshot --overlay-refs before dismissing only if visual evidence is required.
|
|
293
298
|
If snapshot times out because the UI never becomes idle, Android accessibility may be blocked by busy or continuously changing app UI. After that timeout, use screenshot as visual truth instead of repeatedly retrying snapshots.
|
|
299
|
+
If iOS snapshot reports AX unavailable or returns only a sparse root, the current screen's accessibility state is invalid. Use plain screenshot as visual truth, coordinate navigation to leave the bad screen, then take a fresh snapshot -i before returning to selector/@ref commands.
|
|
294
300
|
Android runtime permission dialogs and native alerts are handled by alert wait/accept/dismiss. If alert reports no alert, treat the visible surface as app-owned UI and use snapshot -i plus press by label/ref.
|
|
295
301
|
|
|
296
302
|
React DevTools routing:
|
|
297
303
|
Keep the agent-device react-devtools prefix on every React DevTools command.
|
|
298
304
|
Use help react-devtools for status/wait, component trees, props/state/hooks, profile windows, slow renders, rerenders, and remote bridge rules.
|
|
299
|
-
If React DevTools cannot connect, report status and continue with logs, network, perf, screenshot, and trace evidence instead of blocking the whole flow.
|
|
305
|
+
If React DevTools cannot connect, report status and continue with logs, network, perf metrics, screenshot, and trace evidence instead of blocking the whole flow.
|
|
300
306
|
|
|
301
307
|
Slow-flow investigation:
|
|
302
308
|
Keep one session, open the app, and snapshot -i.
|
|
303
309
|
Use help react-devtools for the narrow React profile window.
|
|
304
|
-
Use help debugging for logs clear --restart, logs mark, network dump --include headers, perf --json, traces, and runtime failure evidence.
|
|
310
|
+
Use help debugging for logs clear --restart, logs mark, network dump --include headers, perf metrics --json, traces, and runtime failure evidence.
|
|
305
311
|
For 15-20s async work, use wait with the exact expected text or selector instead of repeated snapshots.
|
|
306
312
|
Report React render offenders separately from network/backend waits and device frame/CPU/memory findings.`},"physical-device":{summary:"Connected phone/tablet setup and iOS signing prerequisites",body:`agent-device help physical-device
|
|
307
313
|
|
|
@@ -441,14 +447,14 @@ Rules:
|
|
|
441
447
|
Re-snapshot after each mutation.
|
|
442
448
|
Keep commands in the report reproducible; use selectors or refs from fresh snapshots, not guessed coordinates.
|
|
443
449
|
Prefer refs for exploration and selectors for deterministic replay.
|
|
444
|
-
Use logs, network, screenshot --overlay-refs, trace, perf, or react-devtools only when they add evidence to a specific issue.
|
|
450
|
+
Use logs, network, screenshot --overlay-refs, trace, perf metrics, perf frames, or react-devtools only when they add evidence to a specific issue.
|
|
445
451
|
Never delete screenshots, videos, traces, or report artifacts during a session.
|
|
446
452
|
Escalate to help debugging or help react-devtools when runtime symptoms require those tools.`}};function v(e){let t=e.endsWith("?"),o=t?e.slice(0,-1):e;return t?`[${o}]`:`<${o}>`}function w(e){return r().filter(t=>e.has(t.key)&&void 0!==t.usageLabel&&void 0!==t.usageDescription)}function b(e,t){return y(e,t.map(e=>({label:e.usageLabel??"",description:e.usageDescription??""})))}function y(e,t){if(0===t.length)return`${e}
|
|
447
453
|
(none)`;let o=Math.max(...t.map(e=>e.label.length))+2,a=[e];for(let e of t)a.push(` ${e.label.padEnd(o)}${e.description}`);return a.join("\n")}function k(e,t){return 0===t.length?`${e}
|
|
448
|
-
(none)`:[e,...t.map(e=>` ${e}`)].join("\n")}let x=new Set(["config","remoteConfig","help","version","batchSteps","githubActionsArtifact"]),I=new Set(["appsFilter","iosSimulatorDeviceSet","sessionLocked","sessionLockConflicts"]),A=function(){let o=new Map;for(let e of r()){let t=o.get(e.key);t?t.push(e):o.set(e.key,[e])}let a=new Map;for(let e of s)a.set(e,new Set(["*"]));for(let o of e())for(let e of t(o).allowedFlags??[]){let t=a.get(e);t&&t.has("*")||(t?t.add(o):a.set(e,new Set([o])))}return[...o.entries()].map(([e,t])=>({key:e,flagDefinitions:t,config:{enabled:!x.has(e),key:e},env:{names:I.has(e)?[]:[l(e)]},supportsCommand(t){let o=a.get(e);return!!o&&(!!o.has("*")||!!t&&o.has(t))}})).sort((e,t)=>e.key.localeCompare(t.key))}(),R=new Map(A.map(e=>[e.key,e]));function S(e){return R.get(e)}function N(e){return A.filter(t=>t.config.enabled&&t.supportsCommand(e))}function U(e,t){return S(e)?.supportsCommand(t)??!1}function E(e,t,o,a){return i(function(e){let t=e.flagDefinitions.find(e=>void 0===e.setValue);if(t)return t;let o=function(e){let t=e.flagDefinitions[0];if(!t)throw Error(`Missing flag definition for option ${e.key}`);return t}(e);if("enum"===o.type){let t=o.enumValues??e.flagDefinitions.map(e=>e.setValue).filter(e=>void 0!==e);return{...o,setValue:void 0,enumValues:t}}return o}(e),t,o,a)}function D(e){let t={json:!1,help:!1,version:!1},a=null,s=[],r=[],i=!0;for(let p=0;p<e.length;p+=1){var l,
|
|
454
|
+
(none)`:[e,...t.map(e=>` ${e}`)].join("\n")}let x=new Set(["config","remoteConfig","help","version","batchSteps","githubActionsArtifact"]),I=new Set(["appsFilter","iosSimulatorDeviceSet","sessionLocked","sessionLockConflicts"]),A=function(){let o=new Map;for(let e of r()){let t=o.get(e.key);t?t.push(e):o.set(e.key,[e])}let a=new Map;for(let e of s)a.set(e,new Set(["*"]));for(let o of e())for(let e of t(o).allowedFlags??[]){let t=a.get(e);t&&t.has("*")||(t?t.add(o):a.set(e,new Set([o])))}return[...o.entries()].map(([e,t])=>({key:e,flagDefinitions:t,config:{enabled:!x.has(e),key:e},env:{names:I.has(e)?[]:[l(e)]},supportsCommand(t){let o=a.get(e);return!!o&&(!!o.has("*")||!!t&&o.has(t))}})).sort((e,t)=>e.key.localeCompare(t.key))}(),R=new Map(A.map(e=>[e.key,e]));function S(e){return R.get(e)}function N(e){return A.filter(t=>t.config.enabled&&t.supportsCommand(e))}function U(e,t){return S(e)?.supportsCommand(t)??!1}function E(e,t,o,a){return i(function(e){let t=e.flagDefinitions.find(e=>void 0===e.setValue);if(t)return t;let o=function(e){let t=e.flagDefinitions[0];if(!t)throw Error(`Missing flag definition for option ${e.key}`);return t}(e);if("enum"===o.type){let t=o.enumValues??e.flagDefinitions.map(e=>e.setValue).filter(e=>void 0!==e);return{...o,setValue:void 0,enumValues:t}}return o}(e),t,o,a)}function D(e){let t={json:!1,help:!1,version:!1},a=null,s=[],r=[],i=!0;for(let p=0;p<e.length;p+=1){var l,d;let u=e[p];if(i&&"--"===u){i=!1;continue}if(!i){a?s.push(u):a=M(u);continue}let f=u.startsWith("--"),h=u.startsWith("-")&&u.length>1;if(!f&&!h){a?s.push(u):a=M(u);continue}let[g,m]=f?C(u):[u,void 0],v=n(g);if(l=a,d=v,"react-devtools"===l&&(!d||!U(d.key,l))){s.push(u);continue}if(!v){if(function(e,t,a){var s;if(s=a,!/^-\d+(\.\d+)?$/.test(s)||!e)return!1;let n=o(e);if(!n||n.allowsExtraPositionals)return!0;let r=n.positionalArgs??[];return 0!==r.length&&(t.length<r.length||r.some(e=>e.includes("?")))}(a,s,u)){a?s.push(u):a=u;continue}throw new c("INVALID_ARGS",`Unknown flag: ${g}`)}let w=function(e,t,o,a){if(void 0!==e.setValue){if(void 0!==o)throw new c("INVALID_ARGS",`Flag ${t} does not take a value.`);return{value:e.setValue,consumeNext:!1}}if("boolean"===e.type){if(void 0!==o)throw new c("INVALID_ARGS",`Flag ${t} does not take a value.`);return{value:!0,consumeNext:!1}}if("booleanOrString"===e.type){if(void 0!==o){if(0===o.trim().length)throw new c("INVALID_ARGS",`Flag ${t} requires a non-empty value when provided.`);return{value:o,consumeNext:!1}}return void 0===a||L(a)||!function(e){let t=e.trim();return!(!t||/^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(t))&&!!(t.startsWith("./")||t.startsWith("../")||t.startsWith("~/")||t.startsWith("/")||t.includes("/")||t.includes("\\"))}(a)?{value:!0,consumeNext:!1}:{value:a,consumeNext:!0}}let s=o??a;if(void 0===s||void 0===o&&L(s))throw new c("INVALID_ARGS",`Flag ${t} requires a value.`);if("string"===e.type)return{value:s,consumeNext:void 0===o};if("enum"===e.type){if(!e.enumValues?.includes(s))throw new c("INVALID_ARGS",`Invalid ${_(t)}: ${s}`);return{value:s,consumeNext:void 0===o}}let n=Number(s);if(!Number.isFinite(n)||"number"==typeof e.min&&n<e.min||"number"==typeof e.max&&n>e.max)throw new c("INVALID_ARGS",`Invalid ${_(t)}: ${s}`);return{value:Math.floor(n),consumeNext:void 0===o}}(v,g,m,e[p+1]);w.consumeNext&&(p+=1);let b=t[v.key];if(v.multiple){let e=Array.isArray(b)?[...b,w.value]:void 0===b?[w.value]:[b,w.value];t[v.key]=e}else t[v.key]=w.value;r.push({key:v.key,token:g})}return{command:a,positionals:s,flags:t,warnings:[],providedFlags:r}}function O(e,t){let o=t?.strictFlags??!0,s=[...e.warnings],n=d({json:!1,help:!1,version:!1},t?.defaultFlags??{});d(n,e.flags);let r=e.providedFlags.filter(t=>!U(t.key,e.command));if(r.length>0){var i,l;let t=r.map(e=>e.token),a=(i=e.command,l=t,i?1===l.length?`Flag ${l[0]} is not supported for command ${i}.`:`Flags ${l.join(", ")} are not supported for command ${i}.`:1===l.length?`Flag ${l[0]} requires a command that supports it.`:`Flags ${l.join(", ")} require a command that supports them.`);if(o)throw new c("INVALID_ARGS",a);for(let e of(s.push(a),r))delete n[e.key]}for(let t of Object.keys(n))void 0!==n[t]&&(U(t,e.command)||delete n[t]);if(function(e){if("back"===e.command&&!(new Set(e.providedFlags.filter(e=>"backMode"===e.key).map(e=>e.token)).size<=1))throw new c("INVALID_ARGS","back accepts only one explicit mode flag: use either --in-app or --system.")}(e),a(e.command,n),"batch"===e.command&&1!=+!!n.steps+ +!!n.stepsFile)throw new c("INVALID_ARGS","batch requires exactly one step source: --steps or --steps-file.");return function(e){if(e.flags.help)return e;if("snapshot"===e.command&&e.flags.snapshotDiff){let{snapshotDiff:t,...o}=e.flags;return{command:"diff",positionals:["snapshot",...e.positionals],flags:o,warnings:e.warnings}}return e}({command:e.command,positionals:e.positionals,flags:n,warnings:s})}function C(e){let t=e.indexOf("=");return -1===t?[e,void 0]:[e.slice(0,t),e.slice(t+1)]}function _(e){return e.replace(/^-+/,"")}function L(e){if(!e.startsWith("-")||"-"===e)return!1;let[t]=e.startsWith("--")?C(e):[e,void 0];return void 0!==n(t)}function T(){let o,a,n,r,i,l,c,d;return o=`agent-device <command> [args] [--json]
|
|
449
455
|
|
|
450
456
|
CLI to control iOS and Android devices for AI agents.
|
|
451
|
-
`,a=y("Commands:",e().map(e=>{let o=t(e);return{name:e,schema:o,usage:function(e,t){if(t.listUsageOverride)return t.listUsageOverride;let o=(t.positionalArgs??[]).map(o=>{var a,s,n;let r,i,l,
|
|
457
|
+
`,a=y("Commands:",e().map(e=>{let o=t(e);return{name:e,schema:o,usage:function(e,t){if(t.listUsageOverride)return t.listUsageOverride;let o=(t.positionalArgs??[]).map(o=>{var a,s,n;let r,i,l,c;return a=e,s=t,i=(r=(n=o).endsWith("?"))?n.slice(0,-1):n,c=(l=/^[a-z-]+(?:\|[a-z-]+)+$/i.test(i))||void 0!==s.usageOverride&&s.usageOverride.startsWith(`${a} ${i}`),r?l?`[${i}]`:c?i:`[${i}]`:c?i:`<${i}>`});return[e,...o].join(" ")}(e,o)}}).map(e=>({label:e.usage,description:e.schema.summary??e.schema.helpDescription}))),n=b("Flags:",w(s)),r=k("Agent Quickstart:",u),i=y("Agent Workflows:",p),l=k("Configuration:",f),c=y("Environment:",h),d=k("Examples:",g),`${o}
|
|
452
458
|
${a}
|
|
453
459
|
|
|
454
460
|
${n}
|
|
@@ -459,21 +465,21 @@ ${i}
|
|
|
459
465
|
|
|
460
466
|
${l}
|
|
461
467
|
|
|
462
|
-
${d}
|
|
463
|
-
|
|
464
468
|
${c}
|
|
469
|
+
|
|
470
|
+
${d}
|
|
465
471
|
`}function F(e){return function(e){var t,a;let n,i=(n=m[e])?`${n.body}
|
|
466
472
|
|
|
467
473
|
Related:
|
|
468
474
|
agent-device help command list and global flags
|
|
469
475
|
agent-device help <command> command-specific flags
|
|
470
476
|
agent-device help workflow normal app automation loop
|
|
471
|
-
`:null;if(i)return i;let l=o(e);if(!l)return null;let
|
|
477
|
+
`:null;if(i)return i;let l=o(e);if(!l)return null;let c=(t=e,(a=l).usageOverride?a.usageOverride:[t,...(a.positionalArgs??[]).map(v),...(a.allowedFlags??[]).flatMap(e=>{var t;return(t=e,r().filter(e=>e.key===t)).map(e=>e.usageLabel??e.names[0])}).map(e=>`[${e}]`)].join(" ")),d=w(new Set(l.allowedFlags??[])),p=w(s),u=[];return d.length>0&&u.push(b("Command flags:",d)),u.push(b("Global flags:",p)),`agent-device ${c}
|
|
472
478
|
|
|
473
479
|
${l.helpDescription}
|
|
474
480
|
|
|
475
481
|
Usage:
|
|
476
|
-
agent-device ${
|
|
482
|
+
agent-device ${c}
|
|
477
483
|
|
|
478
484
|
${u.join("\n\n")}
|
|
479
|
-
`}(M(e))}function M(e){return"long-press"===e?"longpress":"metrics"===e?"perf":e}export{T as usage,
|
|
485
|
+
`}(M(e))}function M(e){return"long-press"===e?"longpress":"metrics"===e?"perf":e}export{T as usage,O as finalizeParsedArgs,N as getConfigurableOptionSpecs,S as getOptionSpec,d as mergeDefinedFlags,E as parseOptionValueFromSource,D as parseRawArgs,F as usageForCommand};
|
package/dist/src/cli.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import e from"node:path";import{styleText as t}from"node:util";import{pathToFileURL as n}from"node:url";import r from"node:fs";import o from"node:crypto";import{buildMobileSnapshotPresentation as i,displayNodeLabel as s,buildSnapshotDisplayLines as a,localCommandPolicy as l,createAgentDevice as c,formatSnapshotLine as d}from"./9533.js";import{asAppError as u,normalizeError as f,AppError as p}from"./9152.js";import{ensureCompanionTunnel as m,stopCompanionTunnel as h}from"./1974.js";import{REACT_DEVTOOLS_COMPANION_RUN_ARG as g}from"./2301.js";import{REMOTE_CONFIG_FIELD_SPECS as v,resolveRemoteConfigProfile as w,resolveRemoteConfigPath as y}from"./208.js";import{createRequestId as I,withDiagnosticsScope as $,getDiagnosticsMeta as A,flushDiagnosticsToSessionFile as S,emitDiagnostic as C}from"./7599.js";import{resolveDaemonPaths as x}from"./9238.js";import{stopMetroTunnel as b}from"./metro.js";import{runCmdStreaming as _,runCmd as D}from"./9818.js";import{serializeCloseResult as N,serializeOpenResult as P,serializeInstallFromSourceResult as k,serializeDevice as R,serializeSessionListEntry as U,serializeDeployResult as E,serializeSnapshotResult as T}from"./6232.js";import{readCommandMessage as B}from"./1998.js";import{gestureCliReaders as M,selectorCliReaders as L,parseInstallSourceConfig as O,replayCliReaders as j,systemCliReaders as
|
|
1
|
+
import e from"node:path";import{styleText as t}from"node:util";import{pathToFileURL as n}from"node:url";import r from"node:fs";import o from"node:crypto";import{buildMobileSnapshotPresentation as i,displayNodeLabel as s,buildSnapshotDisplayLines as a,localCommandPolicy as l,createAgentDevice as c,formatSnapshotLine as d}from"./9533.js";import{asAppError as u,normalizeError as f,AppError as p}from"./9152.js";import{ensureCompanionTunnel as m,stopCompanionTunnel as h}from"./1974.js";import{REACT_DEVTOOLS_COMPANION_RUN_ARG as g}from"./2301.js";import{REMOTE_CONFIG_FIELD_SPECS as v,resolveRemoteConfigProfile as w,resolveRemoteConfigPath as y}from"./208.js";import{createRequestId as I,withDiagnosticsScope as $,getDiagnosticsMeta as A,flushDiagnosticsToSessionFile as S,emitDiagnostic as C}from"./7599.js";import{resolveDaemonPaths as x}from"./9238.js";import{stopMetroTunnel as b}from"./metro.js";import{runCmdStreaming as _,runCmd as D}from"./9818.js";import{serializeCloseResult as N,serializeOpenResult as P,serializeInstallFromSourceResult as k,serializeDevice as R,serializeSessionListEntry as U,serializeDeployResult as E,serializeSnapshotResult as T}from"./6232.js";import{readCommandMessage as B}from"./1998.js";import{gestureCliReaders as M,selectorCliReaders as L,parseInstallSourceConfig as O,replayCliReaders as j,systemCliReaders as H,observabilityCliReaders as K,appCliReaders as F}from"./8699.js";import{captureCliReaders as G,commonInputFromFlags as V}from"./6085.js";import{interactionCliReaders as q}from"./8502.js";import{runCommand as J}from"./command-surface.js";import{resolveUserPath as z,expandUserHomePath as W}from"./3267.js";import{createLocalArtifactAdapter as Z}from"./7719.js";import{isClientBackedCliCommandName as Y}from"./5792.js";import{isCommandName as X}from"./command-metadata.js";import{mergeDefinedFlags as Q,parseOptionValueFromSource as ee,getConfigurableOptionSpecs as et,getOptionSpec as en,usage as er,parseRawArgs as eo,usageForCommand as ei,finalizeParsedArgs as es}from"./args.js";import{readVersion as ea}from"./9671.js";import{createAgentDeviceClient as el,sendToDaemon as ec}from"./9542.js";import{maybeRunUpgradeNotifier as ed}from"./113.js";function eu(e){return e.width>0&&e.height>0}function ef(e,t){return!!e&&!!t&&e.x>=t.x-2&&e.y>=t.y-2&&e.x+e.width<=t.x+t.width+2&&e.y+e.height<=t.y+t.height+2}function ep(e){return"number"!=typeof e.parentIndex}function em(e){let t=(e.type??"").toLowerCase(),n=(e.identifier??"").trim().toLowerCase();return t.includes("edittext")||t.includes("textfield")||"composer"===n}function eh(e){let t=(e.type??"").toLowerCase();return t.includes("scroll")||t.includes("list")||t.includes("recyclerview")}function eg(e){var t;let n=s(e);if(!n||n!==e.identifier?.trim()||(t=n,!/^[\w.]+:id\/[\w.-]+$/i.test(t)))return n;let r=(e.type??"").toLowerCase();return r.includes("view")||r.includes("layout")||r.includes("image")||r.includes("list")||r.includes("recyclerview")||r.includes("collection")?"":n}function ev(e){let t=e.trim().replace(/\s+/g," ").toLowerCase();return!t||/^(true|false|\d+)$/.test(t)?null:t}function ew(e,t){let n=[],r=[t];for(;r.length>0;){let t=r.pop();for(let o of e)o.parentIndex===t&&(n.push(o),r.push(o.index))}return n}function ey(e,t,n){let r=[t];for(;r.length>0;){let t=r.pop();if(!n.has(t))for(let o of(n.add(t),e))o.parentIndex!==t||n.has(o.index)||r.push(o.index)}}let eI=["button","switch","checkbox","radio"],e$=["button","image","textview","view"];function eA(e){if(!0===e.hittable||em(e))return!1;let t=(e.type??"").toLowerCase();return t.includes("text")||t.includes("image")||t.includes("icon")}function eS(e){if(!e.rect||!eu(e.rect)||ep(e)||em(e))return!1;let t=(e.type??"").toLowerCase();return"text"===t||eb(t,e$)}function eC(e,t){let n=ex(e);return ex(t)>n?t:e}function ex(e){let t=(e.type??"").toLowerCase(),n=0;return eb(t,eI)?n+=100:t.includes("image")?n+=30:t.includes("textview")||"text"===t?n+=20:t.includes("view")&&(n+=10),!0===e.hittable&&(n+=20),!1!==e.enabled&&(n+=5),n}function eb(e,t){return t.some(t=>e.includes(t))}function e_(e){process.stdout.write(`${JSON.stringify(e,null,2)}
|
|
2
2
|
`)}function eD(e,t={}){let n=e instanceof p?f(e):e;process.stderr.write(`Error (${n.code}): ${n.message}
|
|
3
3
|
`),n.hint&&process.stderr.write(`Hint: ${n.hint}
|
|
4
4
|
`),n.diagnosticId&&process.stderr.write(`Diagnostic ID: ${n.diagnosticId}
|
|
5
5
|
`),n.logPath&&process.stderr.write(`Diagnostics Log: ${n.logPath}
|
|
6
6
|
`),t.showDetails&&n.details&&process.stderr.write(`${JSON.stringify(n.details,null,2)}
|
|
7
7
|
`)}function eN(e){return e&&e.summaryLines.length>0?`
|
|
8
|
-
${e.summaryLines.join("\n")}`:""}function eP(e){return`x=${e.x},y=${e.y},w=${e.width},h=${e.height}`}function ek(e){return e>0?`+${e}`:String(e)}function eR(e){let t=e.nearestText?` near ${JSON.stringify(e.nearestText)}`:"",n=e.regionIndex?` r${e.regionIndex}`:"";return`${e.likelyKind}${t}${n}`}function eU(e){return e.min===e.max?ek(e.min):`${ek(e.min)}..${ek(e.max)}`}function eE(t){let n=process.cwd(),r=e.relative(n,t);return""!==r&&(r.startsWith("..")||e.isAbsolute(r))?t:""===r?".":`.${e.sep}${r}`}function eT(e){return"number"==typeof e&&Number.isFinite(e)?e:0}function eB(){let e=process.env.FORCE_COLOR;return"string"==typeof e?"0"!==e:"string"!=typeof process.env.NO_COLOR&&!!process.stdout.isTTY}function eM(e,n){return n?t("dim",e):e}function eL(e){let t=e.warnings;return Array.isArray(t)?t.filter(e=>"string"==typeof e&&e.length>0):[]}function eO(e,t){var n;let r="scroll-area"===(n=e.type)||"list"===n||"collection"===n||"table"===n?n:null;if(!r)return[];let o=[];if(e.node.hiddenContentAbove&&"below"!==t&&o.push(`[content above ${r} hidden]`),e.node.hiddenContentBelow&&"above"!==t&&o.push(`[content below ${r} hidden]`),0===o.length)return[];let i=" ".repeat(e.depth+1);return o.map(e=>`${i}${e}`)}let ej={slug:"react-devtools-companion",runArg:g,displayName:"React DevTools companion"};async function
|
|
9
|
-
`,{encoding:"utf8",mode:384}),r.chmodSync(e,384)}function eQ(e,t){C({level:"warn",phase:"remote_connection_state_invalid",data:{session:e.session,cause:t instanceof Error?t.message:t?String(t):void 0}}),eq(e)}let e0=v.map(e=>e.key);function e1(e){let t={};for(let n of e0){let r=e[n];void 0!==r&&(t[n]=r)}return t}let e2=new Set(["connect","connection","close","disconnect","metro","session"]),e3=new Set(["open"]);async function e8(e){let t,n,{command:r,flags:o,client:i}=e;if(!o.remoteConfig)return{flags:o,runtime:e.runtime};let s=x(o.stateDir).baseDir,a=w({configPath:o.remoteConfig,cwd:process.cwd(),env:process.env}),l={...e1(a.profile),...o,remoteConfig:a.resolvedPath},c=eF({stateDir:s,session:l.session??"default"});if(c&&c.remoteConfigPath!==a.resolvedPath)throw new p("INVALID_ARGS","A different remote connection is already active for this session. Run connect --force or disconnect before using a different --remote-config.",{session:c.session,activeRemoteConfig:c.remoteConfigPath,requestedRemoteConfig:a.resolvedPath});let d=c??function(e,t){if(!e.tenant)throw new p("INVALID_ARGS","remote command requires tenant in remote config or via --tenant <id>.");if(!e.runId)throw new p("INVALID_ARGS","remote command requires runId in remote config or via --run-id <id>.");if(!e.daemonBaseUrl)throw new p("INVALID_ARGS","remote command requires daemonBaseUrl in remote config, config, env, or --daemon-base-url.");let n=new Date().toISOString();return{version:1,session:e.session??"default",remoteConfigPath:t,remoteConfigHash:eJ(t),daemon:eV(e),tenant:e.tenant,runId:e.runId,leaseId:e.leaseId,leaseBackend:e.leaseBackend??e7(e),platform:e.platform,target:e.target,connectedAt:n,updatedAt:n}}(l,a.resolvedPath),u={...l,session:d.session},f=function(e,t){if(e)return tt(e,t)?e:void 0}(d.runtime,u.platform)??e.runtime,m=d,h=!c;if(g=r,!e2.has(g)){let e=d.leaseBackend??function(e,t){let n=e7(e);if(n)return n;throw new p("INVALID_ARGS",`${t} requires --platform ios|android or --lease-backend when the remote connection has not resolved a lease yet.`)}(o,r);var g,v,y,I,$,A=d,S=o,C=e;if(A.leaseBackend&&A.leaseBackend!==C)throw new p("INVALID_ARGS","Active remote connection is already bound to a different lease backend. Re-run connect --force to replace it.",{session:A.session,leaseBackend:A.leaseBackend});if(A.platform&&S.platform&&A.platform!==S.platform)throw new p("INVALID_ARGS","Active remote connection is already bound to a different platform. Re-run connect --force to replace it.",{session:A.session,platform:A.platform});if(A.target&&S.target&&A.target!==S.target)throw new p("INVALID_ARGS","Active remote connection is already bound to a different target. Re-run connect --force to replace it.",{session:A.session,target:A.target});let t=await tn(i,m,e);u.leaseId=t.leaseId,u.leaseBackend=e,u.platform=m.platform??u.platform,u.target=m.target??u.target,(m.leaseId!==t.leaseId||m.leaseBackend!==e)&&(m={...m,leaseId:t.leaseId,leaseBackend:e,platform:m.platform??o.platform,target:m.target??o.target,updatedAt:new Date().toISOString()},h=!0)}if(v=r,y=e.batchSteps,(e3.has(v)||"batch"===v&&y&&y.some(e=>{let t=e.command.trim().toLowerCase();return e3.has(t)&&void 0===e.runtime}))&&te(u)&&(!m.leaseId&&u.leaseId&&(m={...m,leaseId:u.leaseId,leaseBackend:u.leaseBackend}),e.forceRuntimePrepare||!f||!tt(f,u.platform))){if(!m.leaseId)throw new p("INVALID_ARGS",`${r} requires a resolved remote lease before Metro runtime can be prepared.`);let e=await e5(u,i,d.remoteConfigPath,d.session,{tenantId:d.tenant,runId:d.runId,leaseId:m.leaseId});f=e.runtime;let o=(I=m.metro,$=e.cleanup,I?.projectRoot!==$?.projectRoot||I?.profileKey!==$?.profileKey||I?.consumerKey!==$?.consumerKey);t=o?m.metro:void 0,n=o?e.cleanup:void 0,m={...m,runtime:e.runtime,metro:e.cleanup,updatedAt:new Date().toISOString()},h=!0}if(h)try{eG({stateDir:s,state:m})}catch(e){throw await e9(n),e}return await e9(t),{flags:{...u,session:m.session,leaseId:m.leaseId,leaseBackend:m.leaseBackend,platform:m.platform??u.platform,target:m.target??u.target},runtime:f}}async function e5(e,t,n,r,o){if(!e.metroProjectRoot&&!e.metroPublicBaseUrl&&!e.metroProxyBaseUrl)return{};if("ios"!==e.platform&&"android"!==e.platform)throw new p("INVALID_ARGS",'Deferred Metro preparation requires platform "ios" or "android".');if(!e.metroPublicBaseUrl&&!e.metroProxyBaseUrl)throw new p("INVALID_ARGS","Deferred Metro preparation requires metroPublicBaseUrl or metroProxyBaseUrl when Metro settings are provided.");let i=await t.metro.prepare({projectRoot:e.metroProjectRoot,kind:e.metroKind,publicBaseUrl:e.metroPublicBaseUrl,proxyBaseUrl:e.metroProxyBaseUrl,bearerToken:e.metroBearerToken,bridgeScope:o,launchUrl:e.launchUrl,companionProfileKey:n,companionConsumerKey:r,port:e.metroPreparePort,listenHost:e.metroListenHost,statusHost:e.metroStatusHost,startupTimeoutMs:e.metroStartupTimeoutMs,probeTimeoutMs:e.metroProbeTimeoutMs,reuseExisting:!e.metroNoReuseExisting&&void 0,installDependenciesIfNeeded:!e.metroNoInstallDeps&&void 0,runtimeFilePath:e.metroRuntimeFile});return{runtime:"ios"===e.platform?i.iosRuntime:i.androidRuntime,cleanup:e.metroProxyBaseUrl?{projectRoot:i.projectRoot,profileKey:n,consumerKey:r}:void 0}}async function e9(e){if(e)try{await b(e)}catch{}}async function e6(e){try{await
|
|
8
|
+
${e.summaryLines.join("\n")}`:""}function eP(e){return`x=${e.x},y=${e.y},w=${e.width},h=${e.height}`}function ek(e){return e>0?`+${e}`:String(e)}function eR(e){let t=e.nearestText?` near ${JSON.stringify(e.nearestText)}`:"",n=e.regionIndex?` r${e.regionIndex}`:"";return`${e.likelyKind}${t}${n}`}function eU(e){return e.min===e.max?ek(e.min):`${ek(e.min)}..${ek(e.max)}`}function eE(t){let n=process.cwd(),r=e.relative(n,t);return""!==r&&(r.startsWith("..")||e.isAbsolute(r))?t:""===r?".":`.${e.sep}${r}`}function eT(e){return"number"==typeof e&&Number.isFinite(e)?e:0}function eB(){let e=process.env.FORCE_COLOR;return"string"==typeof e?"0"!==e:"string"!=typeof process.env.NO_COLOR&&!!process.stdout.isTTY}function eM(e,n){return n?t("dim",e):e}function eL(e){let t=e.warnings;return Array.isArray(t)?t.filter(e=>"string"==typeof e&&e.length>0):[]}function eO(e,t){var n;let r="scroll-area"===(n=e.type)||"list"===n||"collection"===n||"table"===n?n:null;if(!r)return[];let o=[];if(e.node.hiddenContentAbove&&"below"!==t&&o.push(`[content above ${r} hidden]`),e.node.hiddenContentBelow&&"above"!==t&&o.push(`[content below ${r} hidden]`),0===o.length)return[];let i=" ".repeat(e.depth+1);return o.map(e=>`${i}${e}`)}let ej={slug:"react-devtools-companion",runArg:g,displayName:"React DevTools companion"};async function eH(e){return await m({...e,definition:ej,localBaseUrl:e.localBaseUrl??"http://127.0.0.1:8097",registerPath:"/api/react-devtools/companion/register",unregisterPath:"/api/react-devtools/companion/unregister",devicePort:e.devicePort??8097})}async function eK(e){return await h({...e,definition:ej})}function eF(e){var t;let n,o=ez(e);if(!r.existsSync(o))return null;try{n=JSON.parse(r.readFileSync(o,"utf8"))}catch(t){return eQ(e,t),null}return!(!(t=n)||"object"!=typeof t||Array.isArray(t))&&1===t.version&&"string"==typeof t.session&&"string"==typeof t.remoteConfigPath&&"string"==typeof t.remoteConfigHash&&(void 0===t.daemon||"object"==typeof t.daemon&&null!==t.daemon&&!Array.isArray(t.daemon))&&"string"==typeof t.tenant&&"string"==typeof t.runId&&(void 0===t.leaseId||"string"==typeof t.leaseId)&&(void 0===t.leaseBackend||"string"==typeof t.leaseBackend)&&"string"==typeof t.connectedAt&&"string"==typeof t.updatedAt?n:(eQ(e),null)}function eG(t){let n=ez({stateDir:t.stateDir,session:t.state.session});r.mkdirSync(e.dirname(n),{recursive:!0}),eX(n,t.state),eX(eW(t.stateDir),{session:t.state.session})}function eV(e){return{baseUrl:function(e){if(!e)return;let t=new URL(e);for(let e of(t.username="",t.password="",[...t.searchParams.keys()]))/(auth|key|password|secret|token)/i.test(e)&&t.searchParams.delete(e);return t.toString().replace(/\/+$/,"")}(e.daemonBaseUrl),transport:e.daemonTransport,serverMode:e.daemonServerMode}}function eq(e){r.rmSync(ez(e),{force:!0});let t=eW(e.stateDir);eY(e.stateDir)===e.session&&r.rmSync(t,{force:!0})}function eJ(e){try{return o.createHash("sha256").update(r.readFileSync(e)).digest("hex")}catch(t){throw new p("INVALID_ARGS",`Remote config file not found: ${e}`,{cause:t instanceof Error?t.message:String(t)})}}function ez(t){return e.join(t.stateDir,"remote-connections",`${function(e){let t=e.replaceAll(/[^a-zA-Z0-9._-]/g,"_");if(!t)return"default";if(t===e)return t;let n=o.createHash("sha256").update(e).digest("hex").slice(0,8);return`${t}-${n}`}(t.session)}.json`)}function eW(t){return e.join(t,"remote-connections",".active-session.json")}function eZ(e){let t=eY(e.stateDir);return t?eF({stateDir:e.stateDir,session:t}):null}function eY(e){let t=eW(e);if(r.existsSync(t))try{let e=JSON.parse(r.readFileSync(t,"utf8"));return"string"==typeof e.session?e.session:void 0}catch{return}}function eX(e,t){r.writeFileSync(e,`${JSON.stringify(t,null,2)}
|
|
9
|
+
`,{encoding:"utf8",mode:384}),r.chmodSync(e,384)}function eQ(e,t){C({level:"warn",phase:"remote_connection_state_invalid",data:{session:e.session,cause:t instanceof Error?t.message:t?String(t):void 0}}),eq(e)}let e0=v.map(e=>e.key);function e1(e){let t={};for(let n of e0){let r=e[n];void 0!==r&&(t[n]=r)}return t}let e2=new Set(["connect","connection","close","disconnect","metro","session"]),e3=new Set(["open"]);async function e8(e){let t,n,{command:r,flags:o,client:i}=e;if(!o.remoteConfig)return{flags:o,runtime:e.runtime};let s=x(o.stateDir).baseDir,a=w({configPath:o.remoteConfig,cwd:process.cwd(),env:process.env}),l={...e1(a.profile),...o,remoteConfig:a.resolvedPath},c=eF({stateDir:s,session:l.session??"default"});if(c&&c.remoteConfigPath!==a.resolvedPath)throw new p("INVALID_ARGS","A different remote connection is already active for this session. Run connect --force or disconnect before using a different --remote-config.",{session:c.session,activeRemoteConfig:c.remoteConfigPath,requestedRemoteConfig:a.resolvedPath});let d=c??function(e,t){if(!e.tenant)throw new p("INVALID_ARGS","remote command requires tenant in remote config or via --tenant <id>.");if(!e.runId)throw new p("INVALID_ARGS","remote command requires runId in remote config or via --run-id <id>.");if(!e.daemonBaseUrl)throw new p("INVALID_ARGS","remote command requires daemonBaseUrl in remote config, config, env, or --daemon-base-url.");let n=new Date().toISOString();return{version:1,session:e.session??"default",remoteConfigPath:t,remoteConfigHash:eJ(t),daemon:eV(e),tenant:e.tenant,runId:e.runId,leaseId:e.leaseId,leaseBackend:e.leaseBackend??e7(e),platform:e.platform,target:e.target,connectedAt:n,updatedAt:n}}(l,a.resolvedPath),u={...l,session:d.session},f=function(e,t){if(e)return tt(e,t)?e:void 0}(d.runtime,u.platform)??e.runtime,m=d,h=!c;if(g=r,!e2.has(g)){let e=d.leaseBackend??function(e,t){let n=e7(e);if(n)return n;throw new p("INVALID_ARGS",`${t} requires --platform ios|android or --lease-backend when the remote connection has not resolved a lease yet.`)}(o,r);var g,v,y,I,$,A=d,S=o,C=e;if(A.leaseBackend&&A.leaseBackend!==C)throw new p("INVALID_ARGS","Active remote connection is already bound to a different lease backend. Re-run connect --force to replace it.",{session:A.session,leaseBackend:A.leaseBackend});if(A.platform&&S.platform&&A.platform!==S.platform)throw new p("INVALID_ARGS","Active remote connection is already bound to a different platform. Re-run connect --force to replace it.",{session:A.session,platform:A.platform});if(A.target&&S.target&&A.target!==S.target)throw new p("INVALID_ARGS","Active remote connection is already bound to a different target. Re-run connect --force to replace it.",{session:A.session,target:A.target});let t=await tn(i,m,e);u.leaseId=t.leaseId,u.leaseBackend=e,u.platform=m.platform??u.platform,u.target=m.target??u.target,(m.leaseId!==t.leaseId||m.leaseBackend!==e)&&(m={...m,leaseId:t.leaseId,leaseBackend:e,platform:m.platform??o.platform,target:m.target??o.target,updatedAt:new Date().toISOString()},h=!0)}if(v=r,y=e.batchSteps,(e3.has(v)||"batch"===v&&y&&y.some(e=>{let t=e.command.trim().toLowerCase();return e3.has(t)&&void 0===e.runtime}))&&te(u)&&(!m.leaseId&&u.leaseId&&(m={...m,leaseId:u.leaseId,leaseBackend:u.leaseBackend}),e.forceRuntimePrepare||!f||!tt(f,u.platform))){if(!m.leaseId)throw new p("INVALID_ARGS",`${r} requires a resolved remote lease before Metro runtime can be prepared.`);let e=await e5(u,i,d.remoteConfigPath,d.session,{tenantId:d.tenant,runId:d.runId,leaseId:m.leaseId});f=e.runtime;let o=(I=m.metro,$=e.cleanup,I?.projectRoot!==$?.projectRoot||I?.profileKey!==$?.profileKey||I?.consumerKey!==$?.consumerKey);t=o?m.metro:void 0,n=o?e.cleanup:void 0,m={...m,runtime:e.runtime,metro:e.cleanup,updatedAt:new Date().toISOString()},h=!0}if(h)try{eG({stateDir:s,state:m})}catch(e){throw await e9(n),e}return await e9(t),{flags:{...u,session:m.session,leaseId:m.leaseId,leaseBackend:m.leaseBackend,platform:m.platform??u.platform,target:m.target??u.target},runtime:f}}async function e5(e,t,n,r,o){if(!e.metroProjectRoot&&!e.metroPublicBaseUrl&&!e.metroProxyBaseUrl)return{};if("ios"!==e.platform&&"android"!==e.platform)throw new p("INVALID_ARGS",'Deferred Metro preparation requires platform "ios" or "android".');if(!e.metroPublicBaseUrl&&!e.metroProxyBaseUrl)throw new p("INVALID_ARGS","Deferred Metro preparation requires metroPublicBaseUrl or metroProxyBaseUrl when Metro settings are provided.");let i=await t.metro.prepare({projectRoot:e.metroProjectRoot,kind:e.metroKind,publicBaseUrl:e.metroPublicBaseUrl,proxyBaseUrl:e.metroProxyBaseUrl,bearerToken:e.metroBearerToken,bridgeScope:o,launchUrl:e.launchUrl,companionProfileKey:n,companionConsumerKey:r,port:e.metroPreparePort,listenHost:e.metroListenHost,statusHost:e.metroStatusHost,startupTimeoutMs:e.metroStartupTimeoutMs,probeTimeoutMs:e.metroProbeTimeoutMs,reuseExisting:!e.metroNoReuseExisting&&void 0,installDependenciesIfNeeded:!e.metroNoInstallDeps&&void 0,runtimeFilePath:e.metroRuntimeFile});return{runtime:"ios"===e.platform?i.iosRuntime:i.androidRuntime,cleanup:e.metroProxyBaseUrl?{projectRoot:i.projectRoot,profileKey:n,consumerKey:r}:void 0}}async function e9(e){if(e)try{await b(e)}catch{}}async function e6(e){try{await eK({projectRoot:process.cwd(),stateDir:e.stateDir,profileKey:e.state.remoteConfigPath,consumerKey:e.state.session})}catch{}}async function e4(e,t){if(t.leaseId)try{await e.leases.release({tenant:t.tenant,runId:t.runId,leaseId:t.leaseId,daemonBaseUrl:t.daemon?.baseUrl,daemonTransport:t.daemon?.transport,daemonServerMode:t.daemon?.serverMode})}catch{}}function e7(e){return e.leaseBackend?e.leaseBackend:"android"===e.platform?"android-instance":"ios"===e.platform?"ios-instance":void 0}function te(e){return!!(e.metroPublicBaseUrl||e.metroProxyBaseUrl||e.metroProjectRoot||e.metroKind)}function tt(e,t){return!e.platform||!t||"ios"!==t&&"android"!==t||e.platform===t}async function tn(e,t,n){if(t.leaseId&&t.leaseBackend===n){let r=await tr(e,t.leaseId,{tenant:t.tenant,runId:t.runId,leaseBackend:n});if(r)return r}return await e.leases.allocate({tenant:t.tenant,runId:t.runId,leaseBackend:n})}async function tr(e,t,n){try{return await e.leases.heartbeat({tenant:n.tenant,runId:n.runId,leaseId:t,leaseBackend:n.leaseBackend})}catch(e){var r;if((r=e)instanceof p&&"UNAUTHORIZED"===r.code&&(r.details?.reason==="LEASE_NOT_FOUND"||r.details?.reason==="LEASE_EXPIRED"||r.details?.reason==="LEASE_REVOKED"))return;throw e}}async function to(e){return await ti({command:e.command,flags:e.flags,stateDir:e.stateDir,allowInteractiveLogin:"connect"===e.command&&!e.flags.noLogin,env:e.env})}async function ti(e){let t=e.env??e.io?.env??process.env;if(!e.flags.daemonBaseUrl)return{flags:e.flags,source:"none"};if(ty(e.flags.daemonAuthToken))return{flags:e.flags,source:"flag"};if(ty(t.AGENT_DEVICE_DAEMON_AUTH_TOKEN))return{flags:e.flags,source:"env"};if(!function(e,t){if("1"===t.AGENT_DEVICE_CLOUD_AUTH||"true"===t.AGENT_DEVICE_CLOUD_AUTH||ty(t.AGENT_DEVICE_CLOUD_BASE_URL))return!0;try{let t=new URL(e).hostname.toLowerCase();return"agent-device.dev"===t||t.endsWith(".agent-device.dev")}catch{return!1}}(e.flags.daemonBaseUrl,t))return{flags:e.flags,source:"none"};let n=await td({stateDir:e.stateDir,flags:e.flags,env:t,io:e.io});if(n)return{flags:{...e.flags,daemonAuthToken:n.accessToken},source:"cli-session"};if(!e.allowInteractiveLogin){if(e.flags.noLogin)throw new p("UNAUTHORIZED","Remote daemon authentication is required.",{hint:"Run agent-device auth login, unset --no-login, or set AGENT_DEVICE_DAEMON_AUTH_TOKEN."});throw tm(e.command,t)}let r=await ta({stateDir:e.stateDir,flags:e.flags,env:t,io:e.io});return{flags:{...e.flags,daemonAuthToken:r.accessToken},source:"login"}}async function ts(e){let t=e.env??e.io?.env??process.env;if(ty(e.flags.daemonAuthToken))return{accessToken:e.flags.daemonAuthToken,cloudBaseUrl:th(t)};if(ty(t.AGENT_DEVICE_DAEMON_AUTH_TOKEN))return{accessToken:t.AGENT_DEVICE_DAEMON_AUTH_TOKEN,cloudBaseUrl:th(t)};let n=await td({stateDir:e.stateDir,flags:e.flags,env:t,io:e.io});if(n)return{accessToken:n.accessToken,cloudBaseUrl:n.cloudBaseUrl};if(e.flags.noLogin)throw new p("UNAUTHORIZED","Cloud connection profile authentication is required.",{hint:"Run agent-device auth login, unset --no-login, or set AGENT_DEVICE_DAEMON_AUTH_TOKEN."});let r=await ta({stateDir:e.stateDir,flags:e.flags,env:t,io:e.io,commandLabel:"agent-device connect"});return{accessToken:r.accessToken,cloudBaseUrl:r.session.cloudBaseUrl}}async function ta(t){let n,o,i,s=t.env??t.io?.env??process.env,a=(d=s,u=t.io,n=u?.stdinIsTTY??process.stdin.isTTY,o=u?.stdoutIsTTY??process.stdout.isTTY,"true"!==(f=d).CI&&"true"!==f.GITHUB_ACTIONS&&"true"!==f.BUILDKITE&&n&&o?(m=d).SSH_TTY||m.SSH_CONNECTION||"true"===m.CODESPACES||m.GITPOD_WORKSPACE_ID||"true"===m.REMOTE_CONTAINERS?"device-code":"local-browser":"non-interactive");if("non-interactive"===a)throw tm(t.commandLabel??"agent-device connect",s);let l=th(s),c=await tp({baseUrl:l,pathName:"/api/control-plane/device-auth/start",body:{client:"agent-device",tenant:t.flags.tenant,runId:t.flags.runId,daemonBaseUrl:t.flags.daemonBaseUrl,session:t.flags.session},fetchImpl:t.io?.fetch});var d,u,f,m,h,g,v=c;if(!ty(v.deviceCode)||!ty(v.userCode)||!ty(v.verificationUri))throw new p("COMMAND_FAILED","Cloud auth start returned an unusable response.");let w=c.verificationUriComplete??c.verificationUri,y="local-browser"===a?c.verificationUri:(h=c.verificationUri,g=c.userCode,(i=new URL(h)).searchParams.set("user_code",g),i.toString());"local-browser"===a?(tv(t.io,`Opening ${c.verificationUri}...
|
|
10
10
|
`),await tg(w,t.io)):tv(t.io,`Open this URL on your machine:
|
|
11
11
|
${y}
|
|
12
12
|
|
|
@@ -16,8 +16,8 @@ Waiting for approval for 10 minutes...
|
|
|
16
16
|
${e}
|
|
17
17
|
`)}}function tv(e,t){(e?.stderr??process.stderr).write(t)}function tw(e,t){if(!e)return!1;let n=Date.parse(e);return!Number.isFinite(n)||n<=(t?.()??Date.now())}function ty(e){return"string"==typeof e&&e.trim().length>0}async function tI(e){await new Promise(t=>setTimeout(t,e))}async function t$(t){let n=await ts({stateDir:t.stateDir,flags:t.flags,env:t.env,io:{env:t.env,fetch:t.fetchImpl}}),i=await tA({cloudBaseUrl:n.cloudBaseUrl,accessToken:n.accessToken,fetchImpl:t.fetchImpl}),s=function(e){try{return w(e)}catch(n){let t=u(n);throw new p("COMMAND_FAILED","Cloud connection profile returned invalid remote config.",{generatedConfigPath:e.configPath,cause:t.message},t)}}({configPath:function(t){var n;let i=function e(t){return Array.isArray(t)?t.map(e):t&&"object"==typeof t?Object.fromEntries(Object.entries(t).filter(([,e])=>void 0!==e).sort(([e],[t])=>e.localeCompare(t)).map(([t,n])=>[t,e(n)])):t}(t.profile),s=e.join(t.stateDir,"remote-connections","generated");r.mkdirSync(s,{recursive:!0,mode:448});let a=e.join(s,`cloud-${(n=i,o.createHash("sha256").update(JSON.stringify(n)).digest("hex").slice(0,16))}.json`);r.writeFileSync(a,`${JSON.stringify(i,null,2)}
|
|
18
18
|
`,{mode:384});try{r.chmodSync(a,384)}catch{}return a}({stateDir:t.stateDir,profile:i}),cwd:t.cwd,env:t.env});return{flags:{...e1(s.profile),...t.flags,remoteConfig:s.resolvedPath,daemonAuthToken:n.accessToken},remoteConfigPath:s.resolvedPath}}async function tA(e){let t=e.fetchImpl??fetch,n=await t(new URL("/api/control-plane/connection-profile",e.cloudBaseUrl),{method:"GET",headers:{authorization:`Bearer ${e.accessToken}`},signal:AbortSignal.timeout(15e3)}),r=await n.text(),o={};if(r.trim())try{o=JSON.parse(r)}catch(e){throw new p("COMMAND_FAILED",`Cloud connection profile endpoint returned invalid JSON (${n.status}).`,{status:n.status},e instanceof Error?e:void 0)}if(!n.ok)throw new p("UNAUTHORIZED","Cloud connection profile endpoint rejected the request.",{status:n.status,response:o});var i=o;if(!i||"object"!=typeof i||Array.isArray(i))throw new p("COMMAND_FAILED","Cloud connection profile response is invalid.");let s=i.connection;if(!s||"object"!=typeof s)throw new p("COMMAND_FAILED","Cloud connection profile response is missing profile.");if(void 0!==s.remoteConfigProfile){var a=s.remoteConfigProfile;if(!a||"object"!=typeof a||Array.isArray(a))throw new p("COMMAND_FAILED","Cloud connection profile remoteConfigProfile is invalid.");if(0===Object.keys(a).length)throw new p("COMMAND_FAILED","Cloud connection profile remoteConfigProfile is empty.");return a}throw new p("COMMAND_FAILED","Cloud connection profile did not include remoteConfigProfile.")}function tS(e,t,n){var r;if(e.json)return void e_({success:!0,data:t});let o=n?.();o&&(r=o,process.stdout.write(r.endsWith("\n")?r:`${r}
|
|
19
|
-
`))}let tC=async({flags:e,client:t})=>{var n,r,i,s;let a=x(e.stateDir).baseDir,l=e.remoteConfig?function(e){if(!e.remoteConfig)throw new p("INVALID_ARGS","connect requires --remote-config <path>.");let t=w({configPath:e.remoteConfig,cwd:process.cwd(),env:process.env});return{flags:e,remoteConfigPath:t.resolvedPath}}(e):await t$({flags:e,stateDir:a,cwd:process.cwd(),env:process.env}),c=l.flags,d=c.tenant,u=c.runId;if(!d)throw new p("INVALID_ARGS","connect requires tenant in remote config or via --tenant <id>.");if(!u)throw new p("INVALID_ARGS","connect requires runId in remote config or via --run-id <id>.");if(!c.daemonBaseUrl)throw new p("INVALID_ARGS","connect requires daemonBaseUrl in remote config, config, env, or --daemon-base-url.");let f=c.session?null:eZ({stateDir:a}),m=c.session??f?.session??function(e){for(let t=0;t<8;t+=1){let t=`adc-${o.randomBytes(3).toString("hex")}`;if(!eF({stateDir:e,session:t}))return t}return`adc-${Date.now().toString(36)}-${o.randomBytes(2).toString("hex")}`}(a),h=eJ(l.remoteConfigPath),g=eV(c),v=f?.session===m?f:eF({stateDir:a,session:m});if(v&&(n=v,r={flags:c,session:m,remoteConfigPath:l.remoteConfigPath,remoteConfigHash:h,desiredLeaseBackend:e7(c),daemon:g},n.remoteConfigPath!==r.remoteConfigPath||n.remoteConfigHash!==r.remoteConfigHash||n.session!==r.session||n.tenant!==r.flags.tenant||n.runId!==r.flags.runId||void 0!==r.desiredLeaseBackend&&n.leaseBackend!==r.desiredLeaseBackend||void 0!==r.flags.platform&&n.platform!==r.flags.platform||void 0!==r.flags.target&&n.target!==r.flags.target||(i=n.daemon,s=r.daemon,(i?.baseUrl??void 0)!==(s?.baseUrl??void 0)||(i?.transport??void 0)!==(s?.transport??void 0)||(i?.serverMode??void 0)!==(s?.serverMode??void 0)))&&!c.force)throw new p("INVALID_ARGS","A different remote connection is already active for this session. Re-run connect with --force to replace it.",{session:m,remoteConfig:v.remoteConfigPath});let y=new Date().toISOString(),I={version:1,session:m,remoteConfigPath:l.remoteConfigPath,remoteConfigHash:h,daemon:g,tenant:d,runId:u,leaseId:v&&!c.force?v.leaseId:void 0,leaseBackend:v&&!c.force?v.leaseBackend:e7(c),platform:c.platform??(v&&!c.force?v.platform:void 0),target:c.target??(v&&!c.force?v.target:void 0),runtime:v&&!c.force?v.runtime:void 0,metro:v&&!c.force?v.metro:void 0,connectedAt:v&&!c.force?v.connectedAt:y,updatedAt:y};eG({stateDir:a,state:I}),v&&c.force&&(await e9(v.metro),await e6({stateDir:a,state:v}),await e4(t,v));let $=tN(I),A=function(e,t){if(!t.runtime&&(te(e)||tk(t.remoteConfigPath)))return tP(t.remoteConfigPath)}(c,I);return tS(c,tR(I,A),()=>[`Connected remote session "${m}" tenant "${d}" run "${u}" ${I.leaseId?`lease ${I.leaseId}`:"lease pending"}`,$?.message,A?.message].filter(e=>!!e).join("\n")),!0},tx=async({flags:e,client:t})=>{let{session:n,stateDir:r,state:o}=t_(e);if(!o)return tD(e,n),!0;let i=o.session;try{await t.sessions.close({shutdown:e.shutdown})}catch{}await e9(o.metro),await e6({stateDir:r,state:o});let s=!1;if(o.leaseId)try{s=(await t.leases.release({tenant:o.tenant,runId:o.runId,leaseId:o.leaseId})).released}catch{}return eq({stateDir:r,session:i}),tS(e,{connected:!1,session:i,released:s},()=>`Disconnected remote session "${i}".`),!0},tb=async({positionals:e,flags:t})=>{if("status"!==e[0])throw new p("INVALID_ARGS","connection accepts only: status");let{session:n,state:r}=t_(t);if(!r)return tD(t,n),!0;let o=tN(r),i=function(e){if(!e.runtime&&tk(e.remoteConfigPath))return tP(e.remoteConfigPath)}(r);return tS(t,tR(r,i),()=>[`Connected remote session "${r.session}".`,`tenant=${r.tenant} runId=${r.runId} leaseId=${r.leaseId??"pending"} backend=${r.leaseBackend??"pending"}`,`remoteConfig=${r.remoteConfigPath}`,r.runtime?"metro=prepared":"metro=not-prepared",o?.message,i?.message].filter(e=>!!e).join("\n")),!0};function t_(e){let t=e.session??"default",n=x(e.stateDir).baseDir;return{session:t,stateDir:n,state:eF({stateDir:n,session:t})??(e.session?null:eZ({stateDir:n}))}}function tD(e,t){tS(e,{connected:!1,session:t},()=>`No remote connection for "${t}".`)}function tN(e){if(!e.leaseId)return{status:"deferred",nextSteps:["agent-device install-from-source <artifact-url> --platform ios|android","agent-device open <app-id> --relaunch","agent-device snapshot -i","agent-device devices"],message:"Lease allocation is pending; run install-from-source, open, snapshot, or devices when ready to allocate or refresh the lease."+(void 0===e.platform&&void 0===e.leaseBackend?" Add --platform ios|android if the profile does not set a platform.":"")}}function tP(e){let t=`agent-device metro prepare --remote-config ${e}`;return{status:"deferred",nextStep:t,message:`Metro runtime is not prepared yet; it will be prepared automatically on first open, or run "${t}" to inspect it before launch.`}}function tk(e){try{let t=w({configPath:e,cwd:process.cwd(),env:process.env}).profile;return!!(t.metroPublicBaseUrl||t.metroProxyBaseUrl||t.metroProjectRoot||t.metroKind)}catch{return!1}}function tR(e,t){let n=tN(e);return{connected:!0,session:e.session,tenant:e.tenant,runId:e.runId,leaseAllocated:!!e.leaseId,leaseId:e.leaseId,leaseBackend:e.leaseBackend,platform:e.platform,target:e.target,remoteConfig:e.remoteConfigPath,remoteConfigHash:e.remoteConfigHash,daemonBaseUrlFingerprint:function(e){if(e)return o.createHash("sha256").update(e).digest("hex").slice(0,12)}(e.daemon?.baseUrl),metro:e.metro?{prepared:!0,projectRoot:e.metro.projectRoot}:{prepared:!1},...n?{leasePreparation:n}:{},...t?{runtimePreparation:t}:{},connectedAt:e.connectedAt,updatedAt:e.updatedAt}}let tU=async({positionals:e,flags:t})=>{let n=e[0]??"status",o=x(t.stateDir).baseDir;if("status"===n){var i;let e,n=(e=tl({stateDir:(i={stateDir:o}).stateDir}))?{authenticated:!0,source:"cli-session",sessionId:e.id,cloudBaseUrl:e.cloudBaseUrl,workspaceId:e.workspaceId,accountId:e.accountId,name:e.name,createdAt:e.createdAt,expiresAt:e.expiresAt,expired:tw(e.expiresAt,i.now)}:{authenticated:!1,source:"none"};return tS(t,n,()=>{var e;return(e=n).authenticated?["Authenticated with cloud CLI session.",`cloud=${e.cloudBaseUrl}`,`session=${e.sessionId}`,e.workspaceId?`workspace=${e.workspaceId}`:null,e.accountId?`account=${e.accountId}`:null,e.expiresAt?`expiresAt=${e.expiresAt}`:null,e.expired?"status=expired":null].filter(e=>!!e).join("\n"):"Not authenticated."}),!0}if("login"===n){let e=await ta({stateDir:o,flags:t,commandLabel:"agent-device auth login"});return tS(t,{authenticated:!0,source:"cli-session",sessionId:e.session.id,cloudBaseUrl:e.session.cloudBaseUrl,workspaceId:e.session.workspaceId,accountId:e.session.accountId,expiresAt:e.session.expiresAt,agentTokenExpiresAt:e.expiresAt},()=>"Authenticated with cloud CLI session."),!0}if("logout"===n){let e,n=(e=tc({stateDir:o}.stateDir),!!r.existsSync(e)&&(r.rmSync(e,{force:!0}),!0));return tS(t,{authenticated:!1,removed:n},()=>n?"Removed stored cloud CLI session.":"No stored cloud CLI session."),!0}throw new p("INVALID_ARGS","auth accepts only: status, login, logout")};function tE(e){return tB(E(e))}function tT(e){let t=e.ref??"",n=e.x,r=e.y;return t&&"number"==typeof n&&"number"==typeof r?{data:e,text:`Tapped @${t} (${n}, ${r})`}:tB(e)}function tB(e){return{data:e,text:B(e)}}function tM(e){let t=e.kind?` ${e.kind}`:"",n=e.target?` target=${e.target}`:"",r="boolean"==typeof e.booted?` booted=${e.booted}`:"";return`${e.name} (${e.platform}${t}${n})${r}`}function tL(e,t,n){"string"==typeof n&&e.push(` ${t}: ${n}`)}function tO(e,t){return t.map(t=>void 0!==e[t]&&null!==e[t]?`${t}=${e[t]}`:"").filter(Boolean).join(" ")||void 0}function tj(e){if(!Array.isArray(e))return;let t=e.filter(e=>"string"==typeof e&&e.length>0);return t.length>0?t.join("\n"):void 0}function tK(e){return e.filter(e=>!!e).join("\n")||void 0}function tH(e,t){return e?`Performance: ${e}`:`Frame health: unavailable - ${t}`}function tF(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:void 0}function tG(e){return"number"==typeof e&&Number.isFinite(e)?e:void 0}function tV(e){return`${Number.isInteger(e)?e:e.toFixed(1)}%`}function tq(e){let t=Math.max(0,Math.round(e));if(t<1e3)return`${t}ms`;let n=Math.round(t/1e3);if(n<60)return`${n}s`;let r=Math.floor(n/60),o=n%60;return o>0?`${r}m ${o}s`:`${r}m`}function tJ(e){return({result:t})=>e(t)}let tz=tJ(function(e){return tB(e)}),tW={boot:tJ(function(e){let t=e.platform??"unknown",n=e.device??e.id??"unknown";return{data:e,text:`Boot ready: ${n} (${t})`}}),click:tJ(tT),press:tJ(tT),batch:tJ(function(e){let t="number"==typeof e.total?e.total:0,n="number"==typeof e.executed?e.executed:0,r="number"==typeof e.totalDurationMs?e.totalDurationMs:void 0,o=[`Batch completed: ${n}/${t} steps${void 0!==r?` in ${r}ms`:""}`];for(let t of Array.isArray(e.results)?e.results:[]){let e=function(e){let t=tF(e);if(!t)return;let n="number"==typeof t.step?t.step:void 0,r="string"==typeof t.command?t.command:"step",o=!1!==t.ok,i=function(e,t,n){var r;return t?B(tF(e.data))??n:(r=tF(e.error),("string"==typeof r?.message&&r.message.length>0?r.message:null)??n)}(t,o,r),s=void 0!==n?`${n}. `:"- ",a="number"==typeof t.durationMs?t.durationMs:void 0,l=void 0!==a?` (${a}ms)`:"";return`${s}${o?"OK":"FAILED"} ${i}${l}`}(t);e&&o.push(e)}return{data:e,text:o.join("\n")}}),devices:tJ(function(e){return{data:{devices:e.map(R)},text:e.map(tM).join("\n")}}),apps:({input:e,result:t})=>{var n;return{data:{apps:(n={result:t,appsFilter:e.appsFilter}).result},stderr:"all"===n.appsFilter?"Showing all apps, including system apps.\n":"Showing user-installed apps. Use --all to include system apps.\n",text:n.result.length>0?n.result.join("\n"):"all"===n.appsFilter?"No apps found.":"No user-installed apps found."}},session:tJ(function(e){let t={sessions:e.sessions.map(U)};return{data:t,text:JSON.stringify(t,null,2)}}),open:tJ(function(e){let t=P(e),n=[B(t)].filter(e=>!!e);return"string"==typeof t.sessionStateDir&&n.push(`Session state: ${t.sessionStateDir}`),{data:t,text:n.join("\n")||null}}),close:tJ(function(e){return tB(N(e))}),install:tJ(tE),reinstall:tJ(tE),"install-from-source":tJ(function(e){return tB(k(e))}),snapshot:({input:e,result:t})=>{var n;let r;return{data:r=T((n={result:t,raw:e.raw,interactiveOnly:e.interactiveOnly,scope:e.scope,depth:e.depth}).result),jsonData:function(e){let{unchanged:t,...n}=e;return n}(r),text:function(e,t={}){var n,r,o,l;let c,u,f,p,m,h=e.nodes,g=Array.isArray(h)?h:[],v="string"==typeof e.backend?e.backend:void 0,w=function(e,t,n){let r;if(n.raw||!((r=e.androidSnapshot)&&"object"==typeof r&&"android-helper"===r.backend))return{nodes:t,filteredCount:0};let o=function(e){var t,n;if(0===e.length)return e;let r=new Set,o=new Map,i=new Map(e.map(e=>[e.index,e]));(function(e,t){for(let n of e)!n.rect||eu(n.rect)||ep(n)||ey(e,n.index,t)})(e,r),function(e,t,n,r){for(let o of e){if(n.has(o.index)||o.rect||ep(o))continue;let i=function(e,t,n){let r=e;for(;"number"==typeof r.parentIndex;){let e=t.get(r.parentIndex);if(!e)break;if(n(e))return e;r=e}return null}(o,t,eh);i&&function(e,t,n){if(!n)return;let r=e.get(t.index)??t;e.set(t.index,{...r,hiddenContentAbove:!0===r.hiddenContentAbove||"above"===n||void 0,hiddenContentBelow:!0===r.hiddenContentBelow||"below"===n||void 0})}(r,i,function(e,t){let n=t.filter(t=>t.parentIndex===e.parentIndex&&t.rect&&eu(t.rect)).map(e=>e.index);return 0===n.length?null:e.index<Math.min(...n)?"above":e.index>Math.max(...n)?"below":null}(o,e)),ey(e,o.index,n)}}(e,i,r,o);for(let n of e){if(r.has(n.index)||!(!0===(t=n).hittable&&!em(t)&&t.rect&&eu(t.rect)&&0===eg(t).trim().length))continue;let i=function(e,t,n){let r=[],o=[],i=new Set;for(let s of e){if(n.has(s.index)||!eA(s)||!ef(s.rect,t.rect))continue;let e=eg(s).trim().replace(/\s+/g," "),a=ev(e);o.push(s.index),!e||!a||i.has(a)||(i.add(a),r.push(e))}return{label:r.join(", "),removableIndexes:o}}(ew(e,n.index),n,r);if(i.label)for(let t of(o.set(n.index,{...n,...o.get(n.index),label:i.label}),i.removableIndexes))ey(e,t,r)}for(let t of e){if(r.has(t.index)||!(!0===(n=t).hittable&&!em(n)&&n.rect&&eu(n.rect)&&ev(eg(n))))continue;let o=ev(eg(t));if(!o)continue;let i=ew(e,t.index).filter(e=>!r.has(e.index)&&function(e,t,n){if(!eS(t)||!ef(t.rect,e.rect))return!1;let r=ev(eg(t));return!!(r&&n!==r&&n.includes(r))}(t,e,o));for(let t of i.filter(eA))ey(e,t.index,r);let s=i.filter(e=>!eA(e)),a=new Set(s.map(e=>ev(eg(e))).filter(e=>!!e));if(!(s.length<2)&&!(a.size<2))for(let t of s)ey(e,t.index,r)}let s=new Map;for(let t of e){if(r.has(t.index)||!eS(t))continue;let n=ev(eg(t));if(!n)continue;let i=s.get(n);if(i&&function(e,t,n){var r,o,i,s;return!n.has(e.index)&&(r=e.rect,o=t.rect,!r||!o||Math.abs(r.y+r.height/2-(o.y+o.height/2))<=Math.max(r.height,o.height,1))&&(i=e,s=t,(i.parentIndex===s.parentIndex?3>=Math.abs(i.index-s.index):i.parentIndex!==s.index&&s.parentIndex!==i.index&&1>=Math.abs((i.depth??0)-(s.depth??0))&&2>=Math.abs(i.index-s.index))||function(e,t){let n=e.parentIndex===t.index?t:t.parentIndex===e.index?e:null,r=n?.index===e.index?t:n?.index===t.index?e:null;return!!n&&!!r&&eC(n,r).index===n.index}(e,t))}(i,t,r)){let a=function(e,t,n,r,o){var i,s,a;let l=eC(t,n),c=l.index===t.index?n:t,d=(c.type??"").toLowerCase().includes("image")?"has image":null,u=o.get(l.index)??l,f=o.get(c.index)?.presentationHints??c.presentationHints;return o.set(l.index,{...u,presentationHints:(i=u.presentationHints,s=f,a=d,[...new Set([...Array.isArray(i)?i:[],...Array.isArray(s)?s:[],...a?[a]:[]])])}),ey(e,c.index,r),o.get(l.index)??l}(e,i,t,r,o);s.set(n,a);continue}s.set(n,t)}return e.filter(e=>!r.has(e.index)).map(e=>o.get(e.index)??e)}(t);return{nodes:o,filteredCount:t.length-o.length}}(e,g,t),y=(c="string"==typeof(n=e).appName?n.appName:void 0,u="string"==typeof n.appBundleId?n.appBundleId:void 0,f=[],c&&f.push(`Page: ${c}`),u&&f.push(`App: ${u}`),f.length>0?`${f.join("\n")}
|
|
20
|
-
`:""),I=function(e,t,n,r={nodes:t,filteredCount:0}){let o=eL(e),i=function(e,t){if(!0===t.scoped||!0===t.depthLimited||e.length>3)return null;let n=1===e.length?"node":"nodes";return`Hint: sparse accessibility snapshot returned ${e.length} ${n}
|
|
19
|
+
`))}let tC=async({flags:e,client:t})=>{var n,r,i,s;let a=x(e.stateDir).baseDir,l=e.remoteConfig?function(e){if(!e.remoteConfig)throw new p("INVALID_ARGS","connect requires --remote-config <path>.");let t=w({configPath:e.remoteConfig,cwd:process.cwd(),env:process.env});return{flags:e,remoteConfigPath:t.resolvedPath}}(e):await t$({flags:e,stateDir:a,cwd:process.cwd(),env:process.env}),c=l.flags,d=c.tenant,u=c.runId;if(!d)throw new p("INVALID_ARGS","connect requires tenant in remote config or via --tenant <id>.");if(!u)throw new p("INVALID_ARGS","connect requires runId in remote config or via --run-id <id>.");if(!c.daemonBaseUrl)throw new p("INVALID_ARGS","connect requires daemonBaseUrl in remote config, config, env, or --daemon-base-url.");let f=c.session?null:eZ({stateDir:a}),m=c.session??f?.session??function(e){for(let t=0;t<8;t+=1){let t=`adc-${o.randomBytes(3).toString("hex")}`;if(!eF({stateDir:e,session:t}))return t}return`adc-${Date.now().toString(36)}-${o.randomBytes(2).toString("hex")}`}(a),h=eJ(l.remoteConfigPath),g=eV(c),v=f?.session===m?f:eF({stateDir:a,session:m});if(v&&(n=v,r={flags:c,session:m,remoteConfigPath:l.remoteConfigPath,remoteConfigHash:h,desiredLeaseBackend:e7(c),daemon:g},n.remoteConfigPath!==r.remoteConfigPath||n.remoteConfigHash!==r.remoteConfigHash||n.session!==r.session||n.tenant!==r.flags.tenant||n.runId!==r.flags.runId||void 0!==r.desiredLeaseBackend&&n.leaseBackend!==r.desiredLeaseBackend||void 0!==r.flags.platform&&n.platform!==r.flags.platform||void 0!==r.flags.target&&n.target!==r.flags.target||(i=n.daemon,s=r.daemon,(i?.baseUrl??void 0)!==(s?.baseUrl??void 0)||(i?.transport??void 0)!==(s?.transport??void 0)||(i?.serverMode??void 0)!==(s?.serverMode??void 0)))&&!c.force)throw new p("INVALID_ARGS","A different remote connection is already active for this session. Re-run connect with --force to replace it.",{session:m,remoteConfig:v.remoteConfigPath});let y=new Date().toISOString(),I={version:1,session:m,remoteConfigPath:l.remoteConfigPath,remoteConfigHash:h,daemon:g,tenant:d,runId:u,leaseId:v&&!c.force?v.leaseId:void 0,leaseBackend:v&&!c.force?v.leaseBackend:e7(c),platform:c.platform??(v&&!c.force?v.platform:void 0),target:c.target??(v&&!c.force?v.target:void 0),runtime:v&&!c.force?v.runtime:void 0,metro:v&&!c.force?v.metro:void 0,connectedAt:v&&!c.force?v.connectedAt:y,updatedAt:y};eG({stateDir:a,state:I}),v&&c.force&&(await e9(v.metro),await e6({stateDir:a,state:v}),await e4(t,v));let $=tN(I),A=function(e,t){if(!t.runtime&&(te(e)||tk(t.remoteConfigPath)))return tP(t.remoteConfigPath)}(c,I);return tS(c,tR(I,A),()=>[`Connected remote session "${m}" tenant "${d}" run "${u}" ${I.leaseId?`lease ${I.leaseId}`:"lease pending"}`,$?.message,A?.message].filter(e=>!!e).join("\n")),!0},tx=async({flags:e,client:t})=>{let{session:n,stateDir:r,state:o}=t_(e);if(!o)return tD(e,n),!0;let i=o.session;try{await t.sessions.close({shutdown:e.shutdown})}catch{}await e9(o.metro),await e6({stateDir:r,state:o});let s=!1;if(o.leaseId)try{s=(await t.leases.release({tenant:o.tenant,runId:o.runId,leaseId:o.leaseId})).released}catch{}return eq({stateDir:r,session:i}),tS(e,{connected:!1,session:i,released:s},()=>`Disconnected remote session "${i}".`),!0},tb=async({positionals:e,flags:t})=>{if("status"!==e[0])throw new p("INVALID_ARGS","connection accepts only: status");let{session:n,state:r}=t_(t);if(!r)return tD(t,n),!0;let o=tN(r),i=function(e){if(!e.runtime&&tk(e.remoteConfigPath))return tP(e.remoteConfigPath)}(r);return tS(t,tR(r,i),()=>[`Connected remote session "${r.session}".`,`tenant=${r.tenant} runId=${r.runId} leaseId=${r.leaseId??"pending"} backend=${r.leaseBackend??"pending"}`,`remoteConfig=${r.remoteConfigPath}`,r.runtime?"metro=prepared":"metro=not-prepared",o?.message,i?.message].filter(e=>!!e).join("\n")),!0};function t_(e){let t=e.session??"default",n=x(e.stateDir).baseDir;return{session:t,stateDir:n,state:eF({stateDir:n,session:t})??(e.session?null:eZ({stateDir:n}))}}function tD(e,t){tS(e,{connected:!1,session:t},()=>`No remote connection for "${t}".`)}function tN(e){if(!e.leaseId)return{status:"deferred",nextSteps:["agent-device install-from-source <artifact-url> --platform ios|android","agent-device open <app-id> --relaunch","agent-device snapshot -i","agent-device devices"],message:"Lease allocation is pending; run install-from-source, open, snapshot, or devices when ready to allocate or refresh the lease."+(void 0===e.platform&&void 0===e.leaseBackend?" Add --platform ios|android if the profile does not set a platform.":"")}}function tP(e){let t=`agent-device metro prepare --remote-config ${e}`;return{status:"deferred",nextStep:t,message:`Metro runtime is not prepared yet; it will be prepared automatically on first open, or run "${t}" to inspect it before launch.`}}function tk(e){try{let t=w({configPath:e,cwd:process.cwd(),env:process.env}).profile;return!!(t.metroPublicBaseUrl||t.metroProxyBaseUrl||t.metroProjectRoot||t.metroKind)}catch{return!1}}function tR(e,t){let n=tN(e);return{connected:!0,session:e.session,tenant:e.tenant,runId:e.runId,leaseAllocated:!!e.leaseId,leaseId:e.leaseId,leaseBackend:e.leaseBackend,platform:e.platform,target:e.target,remoteConfig:e.remoteConfigPath,remoteConfigHash:e.remoteConfigHash,daemonBaseUrlFingerprint:function(e){if(e)return o.createHash("sha256").update(e).digest("hex").slice(0,12)}(e.daemon?.baseUrl),metro:e.metro?{prepared:!0,projectRoot:e.metro.projectRoot}:{prepared:!1},...n?{leasePreparation:n}:{},...t?{runtimePreparation:t}:{},connectedAt:e.connectedAt,updatedAt:e.updatedAt}}let tU=async({positionals:e,flags:t})=>{let n=e[0]??"status",o=x(t.stateDir).baseDir;if("status"===n){var i;let e,n=(e=tl({stateDir:(i={stateDir:o}).stateDir}))?{authenticated:!0,source:"cli-session",sessionId:e.id,cloudBaseUrl:e.cloudBaseUrl,workspaceId:e.workspaceId,accountId:e.accountId,name:e.name,createdAt:e.createdAt,expiresAt:e.expiresAt,expired:tw(e.expiresAt,i.now)}:{authenticated:!1,source:"none"};return tS(t,n,()=>{var e;return(e=n).authenticated?["Authenticated with cloud CLI session.",`cloud=${e.cloudBaseUrl}`,`session=${e.sessionId}`,e.workspaceId?`workspace=${e.workspaceId}`:null,e.accountId?`account=${e.accountId}`:null,e.expiresAt?`expiresAt=${e.expiresAt}`:null,e.expired?"status=expired":null].filter(e=>!!e).join("\n"):"Not authenticated."}),!0}if("login"===n){let e=await ta({stateDir:o,flags:t,commandLabel:"agent-device auth login"});return tS(t,{authenticated:!0,source:"cli-session",sessionId:e.session.id,cloudBaseUrl:e.session.cloudBaseUrl,workspaceId:e.session.workspaceId,accountId:e.session.accountId,expiresAt:e.session.expiresAt,agentTokenExpiresAt:e.expiresAt},()=>"Authenticated with cloud CLI session."),!0}if("logout"===n){let e,n=(e=tc({stateDir:o}.stateDir),!!r.existsSync(e)&&(r.rmSync(e,{force:!0}),!0));return tS(t,{authenticated:!1,removed:n},()=>n?"Removed stored cloud CLI session.":"No stored cloud CLI session."),!0}throw new p("INVALID_ARGS","auth accepts only: status, login, logout")};function tE(e){return tB(E(e))}function tT(e){let t=e.ref??"",n=e.x,r=e.y;return t&&"number"==typeof n&&"number"==typeof r?{data:e,text:`Tapped @${t} (${n}, ${r})`}:tB(e)}function tB(e){return{data:e,text:B(e)}}function tM(e){let t=e.kind?` ${e.kind}`:"",n=e.target?` target=${e.target}`:"",r="boolean"==typeof e.booted?` booted=${e.booted}`:"";return`${e.name} (${e.platform}${t}${n})${r}`}function tL(e,t,n){"string"==typeof n&&e.push(` ${t}: ${n}`)}function tO(e,t){return t.map(t=>void 0!==e[t]&&null!==e[t]?`${t}=${e[t]}`:"").filter(Boolean).join(" ")||void 0}function tj(e){if(!Array.isArray(e))return;let t=e.filter(e=>"string"==typeof e&&e.length>0);return t.length>0?t.join("\n"):void 0}function tH(e){return e.filter(e=>!!e).join("\n")||void 0}function tK(e,t){return e?`Performance: ${e}`:`Frame health: unavailable - ${t}`}function tF(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:void 0}function tG(e){return"number"==typeof e&&Number.isFinite(e)?e:void 0}function tV(e){return`${Number.isInteger(e)?e:e.toFixed(1)}%`}function tq(e){let t=Math.max(0,Math.round(e));if(t<1e3)return`${t}ms`;let n=Math.round(t/1e3);if(n<60)return`${n}s`;let r=Math.floor(n/60),o=n%60;return o>0?`${r}m ${o}s`:`${r}m`}function tJ(e){return({result:t})=>e(t)}let tz=tJ(function(e){return tB(e)}),tW={boot:tJ(function(e){let t=e.platform??"unknown",n=e.device??e.id??"unknown";return{data:e,text:`Boot ready: ${n} (${t})`}}),click:tJ(tT),press:tJ(tT),batch:tJ(function(e){let t="number"==typeof e.total?e.total:0,n="number"==typeof e.executed?e.executed:0,r="number"==typeof e.totalDurationMs?e.totalDurationMs:void 0,o=[`Batch completed: ${n}/${t} steps${void 0!==r?` in ${r}ms`:""}`];for(let t of Array.isArray(e.results)?e.results:[]){let e=function(e){let t=tF(e);if(!t)return;let n="number"==typeof t.step?t.step:void 0,r="string"==typeof t.command?t.command:"step",o=!1!==t.ok,i=function(e,t,n){var r;return t?B(tF(e.data))??n:(r=tF(e.error),("string"==typeof r?.message&&r.message.length>0?r.message:null)??n)}(t,o,r),s=void 0!==n?`${n}. `:"- ",a="number"==typeof t.durationMs?t.durationMs:void 0,l=void 0!==a?` (${a}ms)`:"";return`${s}${o?"OK":"FAILED"} ${i}${l}`}(t);e&&o.push(e)}return{data:e,text:o.join("\n")}}),devices:tJ(function(e){return{data:{devices:e.map(R)},text:e.map(tM).join("\n")}}),apps:({input:e,result:t})=>{var n;return{data:{apps:(n={result:t,appsFilter:e.appsFilter}).result},stderr:"all"===n.appsFilter?"Showing all apps, including system apps.\n":"Showing user-installed apps. Use --all to include system apps.\n",text:n.result.length>0?n.result.join("\n"):"all"===n.appsFilter?"No apps found.":"No user-installed apps found."}},session:tJ(function(e){let t={sessions:e.sessions.map(U)};return{data:t,text:JSON.stringify(t,null,2)}}),open:tJ(function(e){let t=P(e),n=[B(t)].filter(e=>!!e);return"string"==typeof t.sessionStateDir&&n.push(`Session state: ${t.sessionStateDir}`),{data:t,text:n.join("\n")||null}}),close:tJ(function(e){return tB(N(e))}),install:tJ(tE),reinstall:tJ(tE),"install-from-source":tJ(function(e){return tB(k(e))}),snapshot:({input:e,result:t})=>{var n;let r;return{data:r=T((n={result:t,raw:e.raw,interactiveOnly:e.interactiveOnly,scope:e.scope,depth:e.depth}).result),jsonData:function(e){let{unchanged:t,...n}=e;return n}(r),text:function(e,t={}){var n,r,o,l;let c,u,f,p,m,h=e.nodes,g=Array.isArray(h)?h:[],v="string"==typeof e.backend?e.backend:void 0,w=function(e,t,n){let r;if(n.raw||!((r=e.androidSnapshot)&&"object"==typeof r&&"android-helper"===r.backend))return{nodes:t,filteredCount:0};let o=function(e){var t,n;if(0===e.length)return e;let r=new Set,o=new Map,i=new Map(e.map(e=>[e.index,e]));(function(e,t){for(let n of e)!n.rect||eu(n.rect)||ep(n)||ey(e,n.index,t)})(e,r),function(e,t,n,r){for(let o of e){if(n.has(o.index)||o.rect||ep(o))continue;let i=function(e,t,n){let r=e;for(;"number"==typeof r.parentIndex;){let e=t.get(r.parentIndex);if(!e)break;if(n(e))return e;r=e}return null}(o,t,eh);i&&function(e,t,n){if(!n)return;let r=e.get(t.index)??t;e.set(t.index,{...r,hiddenContentAbove:!0===r.hiddenContentAbove||"above"===n||void 0,hiddenContentBelow:!0===r.hiddenContentBelow||"below"===n||void 0})}(r,i,function(e,t){let n=t.filter(t=>t.parentIndex===e.parentIndex&&t.rect&&eu(t.rect)).map(e=>e.index);return 0===n.length?null:e.index<Math.min(...n)?"above":e.index>Math.max(...n)?"below":null}(o,e)),ey(e,o.index,n)}}(e,i,r,o);for(let n of e){if(r.has(n.index)||!(!0===(t=n).hittable&&!em(t)&&t.rect&&eu(t.rect)&&0===eg(t).trim().length))continue;let i=function(e,t,n){let r=[],o=[],i=new Set;for(let s of e){if(n.has(s.index)||!eA(s)||!ef(s.rect,t.rect))continue;let e=eg(s).trim().replace(/\s+/g," "),a=ev(e);o.push(s.index),!e||!a||i.has(a)||(i.add(a),r.push(e))}return{label:r.join(", "),removableIndexes:o}}(ew(e,n.index),n,r);if(i.label)for(let t of(o.set(n.index,{...n,...o.get(n.index),label:i.label}),i.removableIndexes))ey(e,t,r)}for(let t of e){if(r.has(t.index)||!(!0===(n=t).hittable&&!em(n)&&n.rect&&eu(n.rect)&&ev(eg(n))))continue;let o=ev(eg(t));if(!o)continue;let i=ew(e,t.index).filter(e=>!r.has(e.index)&&function(e,t,n){if(!eS(t)||!ef(t.rect,e.rect))return!1;let r=ev(eg(t));return!!(r&&n!==r&&n.includes(r))}(t,e,o));for(let t of i.filter(eA))ey(e,t.index,r);let s=i.filter(e=>!eA(e)),a=new Set(s.map(e=>ev(eg(e))).filter(e=>!!e));if(!(s.length<2)&&!(a.size<2))for(let t of s)ey(e,t.index,r)}let s=new Map;for(let t of e){if(r.has(t.index)||!eS(t))continue;let n=ev(eg(t));if(!n)continue;let i=s.get(n);if(i&&function(e,t,n){var r,o,i,s;return!n.has(e.index)&&(r=e.rect,o=t.rect,!r||!o||Math.abs(r.y+r.height/2-(o.y+o.height/2))<=Math.max(r.height,o.height,1))&&(i=e,s=t,(i.parentIndex===s.parentIndex?3>=Math.abs(i.index-s.index):i.parentIndex!==s.index&&s.parentIndex!==i.index&&1>=Math.abs((i.depth??0)-(s.depth??0))&&2>=Math.abs(i.index-s.index))||function(e,t){let n=e.parentIndex===t.index?t:t.parentIndex===e.index?e:null,r=n?.index===e.index?t:n?.index===t.index?e:null;return!!n&&!!r&&eC(n,r).index===n.index}(e,t))}(i,t,r)){let a=function(e,t,n,r,o){var i,s,a;let l=eC(t,n),c=l.index===t.index?n:t,d=(c.type??"").toLowerCase().includes("image")?"has image":null,u=o.get(l.index)??l,f=o.get(c.index)?.presentationHints??c.presentationHints;return o.set(l.index,{...u,presentationHints:(i=u.presentationHints,s=f,a=d,[...new Set([...Array.isArray(i)?i:[],...Array.isArray(s)?s:[],...a?[a]:[]])])}),ey(e,c.index,r),o.get(l.index)??l}(e,i,t,r,o);s.set(n,a);continue}s.set(n,t)}return e.filter(e=>!r.has(e.index)).map(e=>o.get(e.index)??e)}(t);return{nodes:o,filteredCount:t.length-o.length}}(e,g,t),y=(c="string"==typeof(n=e).appName?n.appName:void 0,u="string"==typeof n.appBundleId?n.appBundleId:void 0,f=[],c&&f.push(`Page: ${c}`),u&&f.push(`App: ${u}`),f.length>0?`${f.join("\n")}
|
|
20
|
+
`:""),I=function(e,t,n,r={nodes:t,filteredCount:0}){let o=eL(e),i=function(e,t){if(!0===t.scoped||!0===t.depthLimited||e.length>3)return null;let n=1===e.length?"node":"nodes";return`Hint: sparse accessibility snapshot returned ${e.length} ${n}; snapshot state is invalid or unavailable for this screen. Use plain screenshot, not screenshot --overlay-refs, as visual truth. If screenshot shows the Home Screen or another app, run open for this app again first. Then navigate away with coordinates if needed and retry snapshot -i on the next screen.`}(t,n);i&&o.push(i),!n.raw&&r.filteredCount>0&&o.push(`Collapsed ${r.filteredCount} Android helper node${1===r.filteredCount?"":"s"} from the agent-facing text snapshot; use --raw or --json for the full hierarchy.`);let a=r.filteredCount>0?r.nodes:t;return!n.raw&&function(e){if(e.length<20)return!1;let t=new Map;for(let n of e){let e=(n.type??"").toLowerCase(),r=function(e){var t;let n=e.trim().replace(/\s+/g," ").toLowerCase();return!n||(t=n,/\S+@\S+\.\S+/.test(t))?null:n}(s(n));if(!r)continue;let o=`${e}|${r}`,i=t.get(o)??[];i.push(n),t.set(o,i)}let n=0;for(let e of t.values())!(e.length<=1)&&function(e){for(let r=0;r<e.length;r+=1)for(let o=r+1;o<e.length;o+=1){var t,n;if(t=e[r]?.rect,n=e[o]?.rect,!t||!n||!(t.x+t.width<=n.x+.5||n.x+n.width<=t.x+.5||t.y+t.height<=n.y+.5||n.y+n.height<=t.y+.5))return!0}return!1}(e)&&(n+=e.length);return n>=8}(a)&&o.push("Warning: possible repeated nav subtree detected."),o}(e,g,t,w),$=I.length>0?`${I.join("\n")}
|
|
21
21
|
`:"",A=t.raw?null:(p=e.unchanged)&&"object"==typeof p?"number"!=typeof p.ageMs||"number"!=typeof p.nodeCount?null:{ageMs:p.ageMs,nodeCount:p.nodeCount,interactiveOnly:!0===p.interactiveOnly||void 0,scope:"string"==typeof p.scope?p.scope:void 0}:null;if(A){let e;return`${y}${$}${e=function(e){if(e<1e3)return`${Math.round(e)}ms`;if(e<6e4)return`${(Math.round(e/100)/10).toFixed(1)}s`;let t=e/6e4;return t<60?`${(Math.round(10*t)/10).toFixed(1)}m`:`${(Math.round(t/60*10)/10).toFixed(1)}h`}((r=A).ageMs),r.scope?`Scoped snapshot unchanged for scope "${r.scope}" since previous read ${e} ago.
|
|
22
22
|
Previous refs in this scope remain valid. Use find/get/is for a targeted query, or --force-full to re-emit.`:r.interactiveOnly?`Interactive snapshot unchanged since previous read ${e} ago.
|
|
23
23
|
${r.nodeCount} visible nodes are unchanged. Previous @e refs are still valid. Use find/get/is for a targeted query, or --force-full to re-emit.`:`Snapshot unchanged since previous read ${e} ago.
|
|
@@ -29,18 +29,18 @@ ${$}${g.map(e=>JSON.stringify(e)).join("\n")}
|
|
|
29
29
|
${$}${a(x,{summarizeTextSurfaces:!0}).flatMap(e=>[d(e.node,0,!1,e.type,{summarizeTextSurfaces:!0}),...eO({...e,depth:0})]).join("\n")}${eN(S)}
|
|
30
30
|
`:`${y}${_}
|
|
31
31
|
${$}${(function(e){let t=[],n=[],r=new Map(e.map(e=>[e.node.index,e.node])),o=e=>{for(var o,i,s;n.length>0&&(!e||(o=e,i=n[n.length-1],s=r,!function(e,t,n){let r=e;for(;"number"==typeof r.parentIndex;){if(r.parentIndex===t.index)return!0;let e=n.get(r.parentIndex);if(!e)break;r=e}return!1}(o.node,i.node,s)&&o.depth<=i.depth));)t.push(...eO(n.pop(),"below"))};for(let r of e)o(r),t.push(r.text),t.push(...eO(r,"above")),r.node.hiddenContentBelow&&n.push(r);return o(),t})(a(x,{summarizeTextSurfaces:!0})).join("\n")}${eN(S)}
|
|
32
|
-
`}(r,{raw:n.raw,flatten:n.interactiveOnly,scoped:"string"==typeof n.scope&&n.scope.trim().length>0,depthLimited:"number"==typeof n.depth})}},wait:tz,alert:tz,appstate:tJ(function(e){return{data:e,text:function(e){if("ios"===e.platform){let t=[`Foreground app: ${e.appName??e.appBundleId??"unknown"}`];return e.appBundleId&&t.push(`Bundle: ${e.appBundleId}`),e.source&&t.push(`Source: ${e.source}`),t.join("\n")}if("android"===e.platform){let t=[`Foreground app: ${e.package??"unknown"}`];return e.activity&&t.push(`Activity: ${e.activity}`),t.join("\n")}return null}(e)}}),back:tz,home:tz,rotate:tz,"app-switcher":tz,keyboard:tJ(function(e){if("android"===e.platform&&"status"===e.action){var t;let n=[`Keyboard visible: ${!0===e.visible?"yes":"no"}`,`Input type: ${e.type??e.inputType??"unknown"}`,`Input owner: ${e.inputOwner??"unknown"}`];return e.inputMethodPackage&&n.push(`Input method: ${e.inputMethodPackage}`),e.focusedPackage&&n.push(`Focused package: ${e.focusedPackage}`),e.focusedResourceId&&n.push(`Focused resource: ${e.focusedResourceId}`),n.push(`Next action: ${(t=e.visible,"ime"===e.inputOwner?"Focused input appears to be owned by the keyboard/IME; dismiss or change the IME before retrying text entry.":!0===t?"Keyboard is visible and focused input appears app-owned; fill/type can proceed.":"Keyboard is hidden; focus an app field before type, or use fill with a concrete target.")}`),{data:e,text:n.join("\n")}}return tB(e)}),clipboard:tJ(function(e){return"read"===e.action?{data:e,text:e.text}:tB(e)}),get:({input:e,result:t})=>{var n;let r;return r=(n={result:t,format:e.format}).result,"text"===n.format?{data:r,text:"string"==typeof r.text?r.text:""}:"attrs"===n.format?{data:r,text:JSON.stringify(r.node??{},null,2)}:tB(r)},is:tJ(function(e){return{data:e,text:`Passed: is ${e.predicate??"assertion"}`}}),find:tJ(function(e){return"string"==typeof e.text?{data:e,text:e.text}:"boolean"==typeof e.found?{data:e,text:`Found: ${e.found}`}:e.node?{data:e,text:JSON.stringify(e.node,null,2)}:tB(e)}),perf:tJ(function(e){return{data:e,text:function(e){var t,n,r;let o,i=tF(e.metrics),s=tF(i?.fps),a=(t=i,(o=[function(e){if(e?.available!==!0)return;let t=tG(e.usagePercent);return void 0!==t?`CPU ${tV(t)}`:void 0}(tF(t?.cpu)),function(e){let t;if(e?.available!==!0)return;let n=tG(e.residentMemoryKb)??tG(e.totalPssKb)??tG(e.totalRssKb);return void 0!==n?`memory ${t=n/1024,`${t>=10?Math.round(t):t.toFixed(1)}MB`}`:void 0}(tF(t?.memory))].filter(e=>!!e)).length>0?o.join(", "):void 0);if(!s)return
|
|
32
|
+
`}(r,{raw:n.raw,flatten:n.interactiveOnly,scoped:"string"==typeof n.scope&&n.scope.trim().length>0,depthLimited:"number"==typeof n.depth})}},wait:tz,alert:tz,appstate:tJ(function(e){return{data:e,text:function(e){if("ios"===e.platform){let t=[`Foreground app: ${e.appName??e.appBundleId??"unknown"}`];return e.appBundleId&&t.push(`Bundle: ${e.appBundleId}`),e.source&&t.push(`Source: ${e.source}`),t.join("\n")}if("android"===e.platform){let t=[`Foreground app: ${e.package??"unknown"}`];return e.activity&&t.push(`Activity: ${e.activity}`),t.join("\n")}return null}(e)}}),back:tz,home:tz,rotate:tz,"app-switcher":tz,keyboard:tJ(function(e){if("android"===e.platform&&"status"===e.action){var t;let n=[`Keyboard visible: ${!0===e.visible?"yes":"no"}`,`Input type: ${e.type??e.inputType??"unknown"}`,`Input owner: ${e.inputOwner??"unknown"}`];return e.inputMethodPackage&&n.push(`Input method: ${e.inputMethodPackage}`),e.focusedPackage&&n.push(`Focused package: ${e.focusedPackage}`),e.focusedResourceId&&n.push(`Focused resource: ${e.focusedResourceId}`),n.push(`Next action: ${(t=e.visible,"ime"===e.inputOwner?"Focused input appears to be owned by the keyboard/IME; dismiss or change the IME before retrying text entry.":!0===t?"Keyboard is visible and focused input appears app-owned; fill/type can proceed.":"Keyboard is hidden; focus an app field before type, or use fill with a concrete target.")}`),{data:e,text:n.join("\n")}}return tB(e)}),clipboard:tJ(function(e){return"read"===e.action?{data:e,text:e.text}:tB(e)}),get:({input:e,result:t})=>{var n;let r;return r=(n={result:t,format:e.format}).result,"text"===n.format?{data:r,text:"string"==typeof r.text?r.text:""}:"attrs"===n.format?{data:r,text:JSON.stringify(r.node??{},null,2)}:tB(r)},is:tJ(function(e){return{data:e,text:`Passed: is ${e.predicate??"assertion"}`}}),find:tJ(function(e){return"string"==typeof e.text?{data:e,text:e.text}:"boolean"==typeof e.found?{data:e,text:`Found: ${e.found}`}:e.node?{data:e,text:JSON.stringify(e.node,null,2)}:tB(e)}),perf:tJ(function(e){return{data:e,text:function(e){var t,n,r;let o,i=tF(e.metrics),s=tF(i?.fps),a=(t=i,(o=[function(e){if(e?.available!==!0)return;let t=tG(e.usagePercent);return void 0!==t?`CPU ${tV(t)}`:void 0}(tF(t?.cpu)),function(e){let t;if(e?.available!==!0)return;let n=tG(e.residentMemoryKb)??tG(e.totalPssKb)??tG(e.totalRssKb);return void 0!==n?`memory ${t=n/1024,`${t>=10?Math.round(t):t.toFixed(1)}MB`}`:void 0}(tF(t?.memory))].filter(e=>!!e)).length>0?o.join(", "):void 0);if(!s)return tK(a,"missing frame metric");if(!1===s.available){return tK(a,"string"==typeof(n=s).reason&&n.reason.length>0?n.reason:"not available")}let l=function(e){let t=tG(e.droppedFramePercent),n=tG(e.droppedFrameCount);if(void 0!==t&&void 0!==n){var r,o,i;return[`dropped ${tV(t)}`,(r=n,void 0!==(o=tG(e.totalFrameCount))?`(${Math.round(r)}/${Math.round(o)} frames)`:`(${Math.round(r)} dropped frames)`),void 0!==(i=tG(e.sampleWindowMs))?`window ${tq(i)}`:""].filter(Boolean).join(" ")}}(s);if(!l)return tK(a,"missing dropped-frame summary");let c=[`Frame health: ${l}`],d=(Array.isArray(r=s.worstWindows)?r.filter(e=>!!e&&"object"==typeof e&&!Array.isArray(e)):[]).flatMap(e=>{let t=function(e){let t=tG(e.startOffsetMs),n=tG(e.endOffsetMs),r=tG(e.missedDeadlineFrameCount);if(void 0===t||void 0===n||void 0===r)return;let o=tG(e.worstFrameMs),i=void 0===o?"":`, worst ${tq(o)}`;return`- +${tq(t)}-+${tq(n)}: ${Math.round(r)} missed-deadline frames${i}`}(e);return t?[t]:[]});return d.length>0&&c.push("Worst windows:",...d),c.join("\n")}(e)}}),prepare:tz,logs:tJ(function(e){var t;return{data:e,text:"string"==typeof e.path?e.path:"",stderr:tH([tO(e,["active","state","backend","sizeBytes"]),(t=e,["started","stopped","marked","cleared","restarted","removedRotatedFiles"].map(e=>{var n,r;return n=e,!0===(r=t[e])?`${n}=true`:"number"==typeof r?`${n}=${r}`:""}).filter(Boolean).join(" ")||void 0),"string"==typeof e.hint?e.hint:void 0,tj(e.notes)])}}),network:tJ(function(e){let t=[],n="string"==typeof e.path?e.path:"";n&&t.push(n);let r=Array.isArray(e.entries)?e.entries:[];if(0===r.length)t.push("No recent HTTP(s) entries found.");else for(let e of r)t.push(...function(e){let t=tF(e)??{},n="string"==typeof t.method?t.method:"HTTP",r="string"==typeof t.url?t.url:"<unknown-url>",o="number"==typeof t.status?` status=${t.status}`:"",i="string"==typeof t.timestamp?`${t.timestamp} `:"",s="number"==typeof t.durationMs?` durationMs=${t.durationMs}`:"",a=[`${i}${n} ${r}${o}${s}`];return tL(a,"headers",t.headers),tL(a,"request",t.requestBody),tL(a,"response",t.responseBody),a}(e));return{data:e,text:t.join("\n"),stderr:tH([tO(e,["active","state","backend","include","scannedLines","matchedLines"]),tj(e.notes)])}}),record:tJ(function(e){let t,n="string"==typeof e.outPath?e.outPath:"",r=Array.isArray(t=e.chunks)?t.flatMap(e=>e&&"object"==typeof e?"number"!=typeof e.index||"string"!=typeof e.path?[]:[{index:e.index,path:e.path}]:[]):[];if(r.length<=1){var o,i;let t;return{data:e,text:(o=e,t=[],(i=n)&&t.push(i),"string"==typeof o.sessionStateDir&&t.push(`Session state: ${o.sessionStateDir}`),"string"==typeof o.warning&&t.push(`Warning: ${o.warning}`),"string"==typeof o.overlayWarning&&t.push(`Overlay warning: ${o.overlayWarning}`),t.join("\n"))}}let s=["Recording chunks:"];for(let e of r)s.push(` ${e.index}: ${e.path}`);return"string"==typeof e.telemetryPath&&s.push(`Telemetry: ${e.telemetryPath}`),"string"==typeof e.warning&&s.push(`Warning: ${e.warning}`),"string"==typeof e.overlayWarning&&s.push(`Overlay warning: ${e.overlayWarning}`),{data:e,text:s.join("\n")}}),metro:({input:e,result:t})=>{var n;return{data:(n={result:t,action:e.action}).result,text:"reload"===n.action?`Reloaded React Native apps via ${n.result.reloadUrl}`:JSON.stringify(n.result,null,2)}}},tZ={...F,...G,...q,...M,...L,...K,...j,...H,metro:function(e,t){let n=(e[0]??"").toLowerCase();if("prepare"!==n&&"reload"!==n)throw new p("INVALID_ARGS","metro requires a subcommand: prepare or reload");if("reload"===n)return{action:n,metroHost:t.metroHost,metroPort:t.metroPort,bundleUrl:t.bundleUrl,timeoutMs:t.metroProbeTimeoutMs};if(!t.metroPublicBaseUrl&&!t.metroProxyBaseUrl)throw new p("INVALID_ARGS","metro prepare requires --public-base-url <url> or --proxy-base-url <url>.");return{action:n,projectRoot:t.metroProjectRoot,kind:t.metroKind,port:t.metroPreparePort,listenHost:t.metroListenHost,statusHost:t.metroStatusHost,publicBaseUrl:t.metroPublicBaseUrl,proxyBaseUrl:t.metroProxyBaseUrl,bearerToken:t.metroBearerToken,bridgeScope:t.tenant&&t.runId&&t.leaseId?{tenantId:t.tenant,runId:t.runId,leaseId:t.leaseId}:void 0,startupTimeoutMs:t.metroStartupTimeoutMs,probeTimeoutMs:t.metroProbeTimeoutMs,reuseExisting:!t.metroNoReuseExisting&&void 0,installDependenciesIfNeeded:!t.metroNoInstallDeps&&void 0,runtimeFilePath:t.metroRuntimeFile}},batch:(e,t)=>({...V(t),steps:t.batchSteps??[],onError:t.batchOnError,maxSteps:t.batchMaxSteps,out:t.out})};async function tY(e){return(await tX(e)).result}async function tX(e){var t,n,r,o;let i=(t=e.command,n=e.positionals,r=e.flags,tZ[t](n,r)),s=await J(e.client,e.command,i);return{result:s,cliOutput:(o={name:e.command,input:i,result:s},tW[o.name]?.({input:o.input??{},result:o.result}))}}let tQ={connect:tC,disconnect:tx,connection:tb,auth:tU,screenshot:async({positionals:e,flags:t,client:n})=>{let r=await tY({client:n,command:"screenshot",positionals:e,flags:t});return tS(t,{path:r.path,...r.overlayRefs?{overlayRefs:r.overlayRefs}:{}},()=>r.overlayRefs?`Annotated ${r.overlayRefs.length} refs onto ${r.path}`:r.path),!0},diff:async({positionals:e,flags:n,client:r})=>{var o;if("snapshot"===e[0]){let o=await tY({client:r,command:"diff",positionals:e,flags:n});return tS(n,o,()=>(function(e){var n;let r=!0===e.baselineInitialized,o=e.summary??{},i=eT(o.additions),s=eT(o.removals),a=eT(o.unchanged),l=eB(),c=eL(e),d=c.length>0?`${c.join("\n")}
|
|
33
33
|
`:"";if(r)return`${d}Baseline initialized (${a} lines).
|
|
34
34
|
`;let u=(function(e){if(0===e.length)return e;let t=e.map((e,t)=>({index:t,kind:e.kind})).filter(e=>"added"===e.kind||"removed"===e.kind).map(e=>e.index);if(0===t.length)return e;let n=Array(e.length).fill(!1);for(let r of t){let t=Math.max(0,r-1),o=Math.min(e.length-1,r+1);for(let e=t;e<=o;e+=1)n[e]=!0}return e.filter((e,t)=>n[t])})(Array.isArray(e.lines)?e.lines:[]).map(e=>{let n="string"==typeof e.text?e.text:"";if("added"===e.kind){let e=n.startsWith(" ")?`+${n}`:`+ ${n}`;return l?t("green",e):e}if("removed"===e.kind){let e=n.startsWith(" ")?`-${n}`:`- ${n}`;return l?t("red",e):e}return l?t("dim",n):n}),f=u.length>0?`${u.join("\n")}
|
|
35
35
|
`:"";if(!l)return`${d}${f}${i} additions, ${s} removals, ${a} unchanged
|
|
36
36
|
`;let p=`${(n=String(i),t("green",n))} additions, ${t("red",String(s))} removals, ${t("dim",String(a))} unchanged`;return`${d}${f}${p}
|
|
37
37
|
`})(o)),!0}if("screenshot"!==e[0])return!1;let i=n.baseline;if(!i||"string"!=typeof i)throw new p("INVALID_ARGS","diff screenshot requires --baseline <path>");let s=z(i),a="string"==typeof n.out?z(n.out):void 0,d=e[1];if(e.length>2)throw new p("INVALID_ARGS","diff screenshot accepts at most one current screenshot path");let u=c({backend:(o=r,{platform:function(e){switch(e.platform){case"android":case"linux":case"macos":return e.platform;default:return"ios"}}(n),captureScreenshot:async(e,t,n)=>{let r=await o.capture.screenshot({path:t,session:e.session,overlayRefs:n?.overlayRefs,fullscreen:n?.fullscreen,stabilize:n?.stabilize,surface:n?.surface});return{path:r.path,...r.overlayRefs?{overlayRefs:r.overlayRefs}:{}}}}),artifacts:Z(),sessions:{get:e=>({name:e}),set:()=>{}},policy:l()}),f=await u.capture.diffScreenshot({session:n.session,baseline:{kind:"path",path:s},current:d?{kind:"path",path:z(d)}:{kind:"live"},...a?{out:{kind:"path",path:a}}:{},threshold:function(e){if(null!=e&&""!==e)return Number(e)}(n.threshold),overlayRefs:n.overlayRefs,surface:n.surface});return tS(n,f,()=>{var e,n,r,o;let i,s,a,l,c,d,u,p;return i=eB(),s=!0===f.match,a=f.dimensionMismatch,(l=[]).push(...function(e,n){if(!0===e.match){let e=n?t("green","✓"):"✓";return[`${e} Screenshots match.`]}let r=e.dimensionMismatch,o=n?t("red","✗"):"✗";if(r){let e=r.expected,t=r.actual;return[`${o} Screenshots have different dimensions: expected ${e?.width}x${e?.height}, got ${t?.width}x${t?.height}`]}let i=eT(e.differentPixels),s=eT(e.mismatchPercentage),a=0===s&&i>0?"<0.01":String(s),l=`${a}% pixels differ`;return[`${o} ${n?t("red",l):l}`]}(f,i)),l.push(...function(e,n,r){if(n)return[];let o=[];if(e.diffPath){let n=eE(e.diffPath),i=r?t("dim","Diff image:"):"Diff image:",s=r?t("green",n):n;o.push(` ${i} ${s}`)}if(e.currentOverlayPath){let n=eE(e.currentOverlayPath),i=r?t("dim","Current overlay:"):"Current overlay:",s=r?t("green",n):n,a=eT(e.currentOverlayRefCount),l=a>0?` (${a} refs)`:"";o.push(` ${i} ${s}${l}`)}return o}(f,s,i)),s||a||(l.push(...(e=f,n=i,c=eT(e.differentPixels),d=eT(e.totalPixels),u=n?t("red",String(c)):String(c),[` ${u} different / ${d} total pixels`])),l.push(...(r=f,o=i,0===(p=function(e){let t=[];for(let n of(e.ocr?.movementClusters??[]).slice(0,2))t.push(`text movement cluster: ${function(e){let t=e.slice(0,4).map(e=>JSON.stringify(e)),n=e.length>t.length?` +${e.length-t.length} more`:"";return`${t.join(", ")}${n}`}(n.texts)} dx=${eU(n.xRange)}px dy=${eU(n.yRange)}px`);let n=(e.nonTextDeltas??[]).filter(e=>["icon","toggle","chevron"].includes(e.likelyKind)).slice(0,3);n.length>0&&t.push(`non-text controls: ${n.map(eR).join("; ")}`);let r=(e.nonTextDeltas??[]).filter(e=>"separator"===e.likelyKind).slice(0,2);return r.length>0&&t.push(`non-text boundaries: ${r.map(eR).join("; ")}`),t.slice(0,6)}(r)).length?[]:[` ${eM("Hints:",o)}`,...p.map(e=>` - ${e}`)])),l.push(...function(e,t){let n=Array.isArray(e.regions)?e.regions:[];if(0===n.length)return[];let r=[` ${eM("Changed regions:",t)}`];for(let e of n.slice(0,5))r.push(...function(e){let t=0===e.shareOfDiffPercentage&&e.differentPixels>0?"<0.01":String(e.shareOfDiffPercentage),n=e.rect,r=[` ${e.index}. ${e.location} x=${n.x} y=${n.y} ${n.width}x${n.height}, ${t}% of diff, change=${e.dominantChange}`],o=function(e){let t=[e.size?`size=${e.size}`:null,e.shape?`shape=${e.shape}`:null,"number"==typeof e.densityPercentage?`density=${e.densityPercentage}%`:null,e.averageBaselineColorHex&&e.averageCurrentColorHex?`avgColor=${e.averageBaselineColorHex}->${e.averageCurrentColorHex}`:null,"number"==typeof e.baselineLuminance&&"number"==typeof e.currentLuminance?`luminance=${e.baselineLuminance}->${e.currentLuminance}`:null].filter(e=>null!==e);return t.length>0?t.join(" "):null}(e);o&&r.push(` ${o}`);let i=e.currentOverlayMatches?.[0];if(i){let e=i.label?` "${i.label}"`:"";r.push(` overlaps @${i.ref}${e}, ${i.regionCoveragePercentage}% of region`)}return r}(e));return r}(f,i)),l.push(...function(e,t){let n=e.ocr?.matches??[];if(0===n.length)return[];let r=n.slice(0,8),o=[` ${eM(`OCR text deltas (${e.ocr?.provider}; baselineBlocks=${e.ocr?.baselineBlocks} currentBlocks=${e.ocr?.currentBlocks}; showing ${r.length}/${n.length}; px):`,t)}`,` ${eM("item | text | movePx | sizeDeltaPx | bboxBaseline | bboxCurrent | confidence | issueHint",t)}`];for(let[e,t]of r.entries()){let n=t.delta;o.push(` ${e+1} | ${JSON.stringify(t.text)} | ${ek(n.x)},${ek(n.y)} | ${ek(n.width)},${ek(n.height)} | ${eP(t.baselineRect)} | ${eP(t.currentRect)} | ${t.confidence} | ${t.possibleTextMetricMismatch?"ocr-bbox-size-change":"-"}`)}return o}(f,i)),l.push(...function(e,t){let n=e.nonTextDeltas??[];if(0===n.length)return[];let r=n.slice(0,8),o=[` ${eM(`Non-text visual deltas (showing ${r.length}/${n.length}; px):`,t)}`,` ${eM("item | region | slot | kind | bboxCurrent | nearestText",t)}`];for(let e of r)o.push(` ${e.index} | ${e.regionIndex?`r${e.regionIndex}`:"-"} | ${e.slot} | ${e.likelyKind} | ${eP(e.rect)} | ${e.nearestText?JSON.stringify(e.nearestText):"-"}`);return o}(f,i))),`${l.join("\n")}
|
|
38
|
-
`}),!0}};async function t0(e){let t={...e.flags},n=tQ[e.command];return n?await n({...e,flags:t}):!!Y(e.command)&&await t1({...e,command:e.command,flags:t})}async function t1(e){let{runGenericClientBackedCommand:t}=await import("./generic.js");return await t(e)}function t2(e,t,n){return n||(e.push(t),"")}async function t3(e,t,n){let{flags:r}=t,o=function(e){var t;if(!e?.metroProxyBaseUrl||"android-instance"!==(t=e.leaseBackend)&&"ios-instance"!==t)return null;let n=[],r={serverBaseUrl:t2(n,"metroProxyBaseUrl",e.metroProxyBaseUrl),bearerToken:t2(n,"metroBearerToken",e.metroBearerToken),tenantId:t2(n,"tenant",e.tenant),runId:t2(n,"runId",e.runId),leaseId:t2(n,"leaseId",e.leaseId)};if(n.length>0)throw new p("INVALID_ARGS",`react-devtools remote bridge requires ${n.join(", ")}.`,{missing:n});return r}(r);if(!o)return n();let i=t.stateDir??process.cwd(),s=t.session??r?.session??"default",a=r?.remoteConfig??`${o.tenantId}:${o.runId}:${o.leaseId}`;if("stop"===e[0])try{return await n()}finally{await
|
|
38
|
+
`}),!0}};async function t0(e){let t={...e.flags},n=tQ[e.command];return n?await n({...e,flags:t}):!!Y(e.command)&&await t1({...e,command:e.command,flags:t})}async function t1(e){let{runGenericClientBackedCommand:t}=await import("./generic.js");return await t(e)}function t2(e,t,n){return n||(e.push(t),"")}async function t3(e,t,n){let{flags:r}=t,o=function(e){var t;if(!e?.metroProxyBaseUrl||"android-instance"!==(t=e.leaseBackend)&&"ios-instance"!==t)return null;let n=[],r={serverBaseUrl:t2(n,"metroProxyBaseUrl",e.metroProxyBaseUrl),bearerToken:t2(n,"metroBearerToken",e.metroBearerToken),tenantId:t2(n,"tenant",e.tenant),runId:t2(n,"runId",e.runId),leaseId:t2(n,"leaseId",e.leaseId)};if(n.length>0)throw new p("INVALID_ARGS",`react-devtools remote bridge requires ${n.join(", ")}.`,{missing:n});return r}(r);if(!o)return n();let i=t.stateDir??process.cwd(),s=t.session??r?.session??"default",a=r?.remoteConfig??`${o.tenantId}:${o.runId}:${o.leaseId}`;if("stop"===e[0])try{return await n()}finally{await eK({projectRoot:t.cwd??process.cwd(),stateDir:i,profileKey:a,consumerKey:s})}return await eH({projectRoot:t.cwd??process.cwd(),stateDir:i,serverBaseUrl:o.serverBaseUrl,bearerToken:o.bearerToken,bridgeScope:{tenantId:o.tenantId,runId:o.runId,leaseId:o.leaseId},session:s,profileKey:a,consumerKey:s,env:t.env??process.env}),await n()}async function t8(e,t={}){let n=t.cwd??process.cwd(),r=t.env??process.env,o=await t3(e,t,async()=>(await _("npm",["exec","--yes","--package","agent-react-devtools@0.4.0","--","agent-react-devtools",...e],{cwd:n,env:r,allowFailure:!0,onStdoutChunk:e=>{process.stdout.write(e)},onStderrChunk:e=>{process.stderr.write(e)}})).exitCode);var i,s=t.flags;return 0!==o&&"wait"===(i=e)[0]&&i.includes("--connected")&&"ios-instance"===s?.leaseBackend&&process.stderr.write("Hint: Remote iOS React DevTools connects during JavaScript startup.\nIf the app was already open before `agent-device react-devtools start`, relaunch it with `agent-device open <bundle-id> --platform ios --relaunch`, then retry `agent-device react-devtools wait --connected`.\n"),o}function t5(e,t={}){let n=t9(t),r={...e};return n.defaultPlatform&&void 0===r.platform&&(r.platform=n.defaultPlatform),r}function t9(e){var t,n,r,o;let i,s=e.env??process.env,a=e.inheritedPlatform??e.configuredPlatform??function(e){if(void 0===e)return;let t=e.trim().toLowerCase();if(t){if("ios"===t||"android"===t||"apple"===t)return t;throw new p("INVALID_ARGS",`Invalid AGENT_DEVICE_PLATFORM: ${e}. Use ios, android, or apple.`)}}(s.AGENT_DEVICE_PLATFORM),l="string"==typeof(t=e.configuredSession??s.AGENT_DEVICE_SESSION)&&t.trim().length>0;return{defaultPlatform:a,lockPolicy:(n=e.policyOverrides,r=s,o=l,(i=n?.sessionLock??n?.sessionLockConflicts??function(e){if(void 0===e)return;let t=e.trim().toLowerCase();if(t){if("reject"===t||"strip"===t)return t;throw new p("INVALID_ARGS",`Invalid session lock mode: ${e}. Use reject or strip.`)}}(r.AGENT_DEVICE_SESSION_LOCK))||(n?.sessionLocked===!0||o?"reject":void 0))}}let t6={sendToDaemon:ec},t4=new Set(["launchUrl","metroBearerToken","metroKind","metroListenHost","metroNoInstallDeps","metroNoReuseExisting","metroPreparePort","metroProbeTimeoutMs","metroProjectRoot","metroProxyBaseUrl","metroPublicBaseUrl","metroRuntimeFile","metroStartupTimeoutMs","metroStatusHost"]),t7=new Set(["connect","connection","close","disconnect","metro","session"]);async function ne(t,n=t6){let o=I(),i=ea(),s=function(e){try{let t=eo(e);return nt(t.command??"",t.providedFlags)}catch{return e.includes("--debug")||e.includes("-v")||e.includes("--verbose")}}(t),a=t.includes("--json"),l=function(e){for(let t=0;t<e.length;t+=1){let n=e[t];if(n.startsWith("--session=")){let e=n.slice(10).trim();return e.length>0?e:null}if("--session"===n){let n=e[t+1]?.trim();if(n&&!n.startsWith("-"))return n;break}}return null}(t)??process.env.AGENT_DEVICE_SESSION??"default";await $({session:l,requestId:o,command:t[0],debug:s},async()=>{var l,c,d,m,h,g,v,I,$,b,_,D,N,P,k,R,U;let E,T,B,M,L,j,H;try{let n,o,i,s,a,u,f,y;l={cwd:process.cwd(),env:process.env},n=eo(t),o=l?.env??process.env,i=l?.cwd??process.cwd(),m=n.command,s=null!==m&&(c={remoteConfig:n.flags.remoteConfig,cwd:i,env:o}).remoteConfig?{...e1(w({configPath:c.remoteConfig,cwd:c.cwd,env:c.env}).profile),remoteConfig:c.remoteConfig}:{},f=Q((a=(d={command:n.command,cwd:i,cliFlags:n.flags,env:o}).env??process.env,u=Q({},function(e){let t={};for(let n of e)Q(t,function(e,t){let n,o;if(!r.existsSync(e)){if(t)throw new p("INVALID_ARGS",`Config file not found: ${e}`);return{}}try{n=r.readFileSync(e,"utf8")}catch(t){throw new p("INVALID_ARGS",`Failed to read config file: ${e}`,{cause:t instanceof Error?t.message:String(t)})}try{o=JSON.parse(n)}catch(t){throw new p("INVALID_ARGS",`Invalid JSON in config file: ${e}`,{cause:t instanceof Error?t.message:String(t)})}if(!o||"object"!=typeof o||Array.isArray(o))throw new p("INVALID_ARGS",`Config file must contain a JSON object: ${e}`);return function(e,t){let n={};for(let[r,o]of Object.entries(e)){if("installSource"===r){n.installSource=O(o,t);continue}let e=en(r);if(!e)throw new p("INVALID_ARGS",`Unknown config key "${r}" in ${t}.`);if(!e.config.enabled)throw new p("INVALID_ARGS",`Unsupported config key "${r}" in ${t}.`);n[r]=ee(e,o,t,r)}return n}(o,`config file ${e}`)}(n.path,n.required));return t}((h=d.cwd,g=d.cliFlags.config,v=a,(y=g??v.AGENT_DEVICE_CONFIG)?[{path:(I=y,$=h,b=v,z(I,{cwd:$,env:b})),required:!0}]:[{path:(_=v,e.join(W("~",{env:_}),".agent-device","config.json")),required:!1},{path:e.resolve(h,"agent-device.json"),required:!1}]))),Q(u,function(e,t){let n={};for(let r of et(t)){if("installSource"===r.key)continue;let t=r.env.names.map(t=>({name:t,value:e[t]})).find(e=>"string"==typeof e.value&&e.value.trim().length>0);t&&(n[r.key]=ee(r,t.value,`environment variable ${t.name}`,t.name))}return n}(a,d.command))),s),E={...es(n,{strictFlags:l?.strictFlags,defaultFlags:f}),providedFlags:n.providedFlags}}catch(t){C({level:"error",phase:"cli_parse_failed",data:{error:t instanceof Error?t.message:String(t)}});let e=f(t,{diagnosticId:A().diagnosticId,logPath:S({force:!0})??void 0});a?e_({success:!1,error:e}):eD(e,{showDetails:s}),process.exit(1);return}for(let e of E.warnings)process.stderr.write(`Warning: ${e}
|
|
39
39
|
`);E.flags.version&&(process.stdout.write(`${i}
|
|
40
|
-
`),process.exit(0));let
|
|
40
|
+
`),process.exit(0));let K="help"===E.command,F=E.flags.help;if(K||F){K&&E.positionals.length>1&&(eD(new p("INVALID_ARGS","help accepts at most one command.")),process.exit(1));let e=K?E.positionals[0]:E.command;e||(process.stdout.write(`${er()}
|
|
41
41
|
`),process.exit(0));let t=ei(e);t&&(process.stdout.write(t),process.exit(0)),eD(new p("INVALID_ARGS",`Unknown command: ${e}`)),process.stdout.write(`${er()}
|
|
42
42
|
`),process.exit(1)}E.command||(process.stdout.write(`${er()}
|
|
43
|
-
`),process.exit(1));let{command:G,positionals:V}=E,q=nt(G,E.providedFlags),J=new Set(E.providedFlags.map(e=>e.key));try{B=(T=t9({policyOverrides:E.flags,configuredPlatform:E.flags.platform,configuredSession:E.flags.session})).lockPolicy?{...E.flags}:t5(E.flags,{policyOverrides:E.flags,configuredPlatform:E.flags.platform,configuredSession:E.flags.session}),M=x(B.stateDir),L=B.session??"default",D={command:G,explicitFlagKeys:J,stateDir:M.baseDir,session:L,remoteConfig:B.remoteConfig,hasResolvedSession:void 0!==B.session},
|
|
43
|
+
`),process.exit(1));let{command:G,positionals:V}=E,q=nt(G,E.providedFlags),J=new Set(E.providedFlags.map(e=>e.key));try{B=(T=t9({policyOverrides:E.flags,configuredPlatform:E.flags.platform,configuredSession:E.flags.session})).lockPolicy?{...E.flags}:t5(E.flags,{policyOverrides:E.flags,configuredPlatform:E.flags.platform,configuredSession:E.flags.session}),M=x(B.stateDir),L=B.session??"default",D={command:G,explicitFlagKeys:J,stateDir:M.baseDir,session:L,remoteConfig:B.remoteConfig,hasResolvedSession:void 0!==B.session},H=(j="connect"===D.command||"connection"===D.command?null:function(e){let t=e.validateRemoteConfigHash??!0,n=e.remoteConfig?y({configPath:e.remoteConfig,cwd:e.cwd,env:e.env}):void 0,r=eF(e)??(e.allowActiveFallback?eZ({stateDir:e.stateDir}):null);if(!r||n&&r.remoteConfigPath!==n)return null;if(t&&eJ(r.remoteConfigPath)!==r.remoteConfigHash)throw new p("INVALID_ARGS","Active remote connection config changed. Run agent-device connect --force to refresh it.",{remoteConfig:r.remoteConfigPath});let o=function(e,t){try{return w({configPath:e.remoteConfigPath,cwd:t.cwd,env:t.env}).profile}catch(e){if(!1===t.validateRemoteConfigHash)return{};throw e}}(r,e);return{runtime:r.runtime,flags:{...o,remoteConfig:r.remoteConfigPath,daemonBaseUrl:r.daemon?.baseUrl??o.daemonBaseUrl,daemonTransport:r.daemon?.transport??o.daemonTransport,daemonServerMode:r.daemon?.serverMode??o.daemonServerMode,tenant:r.tenant,sessionIsolation:"tenant",runId:r.runId,leaseId:r.leaseId,leaseBackend:r.leaseBackend,session:r.session,platform:r.platform??o.platform,target:r.target??o.target}}}({stateDir:D.stateDir,session:D.session,remoteConfig:D.remoteConfig,cwd:process.cwd(),env:process.env,allowActiveFallback:!D.explicitFlagKeys.has("session")&&(!D.remoteConfig||"disconnect"===D.command||!D.hasResolvedSession),validateRemoteConfigHash:"disconnect"!==D.command}))?function(e,t,n){let r={...e};for(let[e,o]of Object.entries(t))void 0!==o&&(n.has(e)||(r[e]=o));return r}(B,j.flags,J):B}catch(t){let e=f(u(t),{diagnosticId:A().diagnosticId,logPath:S({force:!0})??void 0});E.flags.json?e_({success:!1,error:e}):eD(e,{showDetails:q}),process.exit(1);return}let Z=null;try{let e;if("react-devtools"===G){let e=await t8(V,{flags:H,stateDir:M.baseDir,session:H.session??L,cwd:process.cwd(),env:process.env});process.exit(e);return}ed({command:G,currentVersion:i,stateDir:M.baseDir,flags:H});let t=j?.runtime,s=(e,t)=>({session:e.session,requestId:o,stateDir:e.stateDir,daemonBaseUrl:e.daemonBaseUrl,daemonAuthToken:e.daemonAuthToken,daemonTransport:e.daemonTransport,daemonServerMode:e.daemonServerMode,tenant:e.tenant,sessionIsolation:e.sessionIsolation,runId:e.runId,leaseId:e.leaseId,leaseBackend:e.leaseBackend,runtime:t,lockPolicy:T.lockPolicy,lockPlatform:T.defaultPlatform,cwd:process.cwd(),debug:q});if("batch"===G){if(V.length>0)throw new p("INVALID_ARGS","batch does not accept positional arguments.");e=function(e){let t,n,o,i="";if(e.steps)i=e.steps;else if(e.stepsFile)try{i=r.readFileSync(e.stepsFile,"utf8")}catch(n){let t=n instanceof Error?n.message:String(n);throw new p("INVALID_ARGS",`Failed to read --steps-file ${e.stepsFile}: ${t}`)}var s,a=i;try{o=JSON.parse(a)}catch{throw new p("INVALID_ARGS","Batch steps must be valid JSON.")}if(!Array.isArray(o)||0===o.length)throw new p("INVALID_ARGS","Batch steps must be a non-empty JSON array.");return s=o,t=!1,n=s.map((e,n)=>{var r,o,i,s,a,l;let c;if(r=e,null!==r&&"object"==typeof r&&!Array.isArray(r)&&"input"in r&&!("positionals"in r)&&!("flags"in r))return e;let d=function(e,t){if(!e||"object"!=typeof e||Array.isArray(e))throw new p("INVALID_ARGS",`Invalid batch step ${t}.`);var n=e,r=t;let o=Object.keys(n).filter(e=>!["command","positionals","flags","runtime"].includes(e));if(o.length>0)throw new p("INVALID_ARGS",`Batch step ${r} has unknown legacy field(s): ${o.join(", ")}.`);let i=function(e,t){let n="string"==typeof e?e.trim().toLowerCase():"";if(!n)throw new p("INVALID_ARGS",`Batch step ${t} requires command.`);if(X(n))return n;throw new p("INVALID_ARGS",`Batch step ${t} command is not available through command batch: ${String(e)}`)}(e.command,t),s=function(e,t){if(void 0!==e){if(!Array.isArray(e)||e.some(e=>"string"!=typeof e))throw new p("INVALID_ARGS",`Batch step ${t} positionals must contain only strings.`);return e}}(e.positionals,t),a=function(e,t){if(void 0!==e){if(!e||"object"!=typeof e||Array.isArray(e))throw new p("INVALID_ARGS",`Batch step ${t} flags must be an object.`);return e}}(e.flags,t);return{command:i,...void 0===s?{}:{positionals:s},...void 0===a?{}:{flags:a},...void 0===e.runtime?{}:{runtime:e.runtime}}}(e,n+1);return t=!0,c=(i=(o=d).command,s=o.positionals??[],l=o.flags,a={json:!1,help:!1,version:!1,...l},tZ[i](s,a)),{command:o.command,input:c,...void 0===o.runtime?{}:{runtime:o.runtime}}}),t&&process.stderr.write('Warning: batch steps using positionals/flags are deprecated and will be removed in the next major version. Use {"command":"...","input":{...}} steps instead.\n'),n}(B)}if(N=G,"auth"!==N&&"connection"!==N&&(H=(await to({command:G,flags:H,stateDir:M.baseDir,env:process.env})).flags),H.remoteConfig&&(P=G,!t7.has(P))){let r=el(s(H,t),{transport:n.sendToDaemon}),o=await e8({command:G,flags:H,client:r,runtime:t,batchSteps:e,forceRuntimePrepare:function(e){for(let t of t4)if(e.has(t))return!0;return!1}(J)});H=o.flags,t=o.runtime}k={command:G,flags:H,runtime:t,explicitFlagKeys:J,hadConnectionDefaults:!!j},!("open"===k.command&&!k.runtime&&!k.flags.bundleUrl&&!k.flags.metroHost&&!k.flags.metroPort&&!k.flags.remoteConfig&&!k.hadConnectionDefaults&&((R=k.explicitFlagKeys).has("daemonBaseUrl")||R.has("daemonTransport")||R.has("tenant")||R.has("sessionIsolation")||R.has("runId")||R.has("leaseId")||R.has("leaseBackend")))||process.stderr.write("Warning: open is using explicit remote daemon or tenant flags without saved Metro runtime hints. React Native apps may launch without bundle/runtime hints; prefer connect --remote-config <path> first or pass --remote-config <path> on this command.\n");let a=H.daemonBaseUrl;Z=!q||H.json||a?null:function(e){try{let t=r.existsSync(e)?r.statSync(e).size:0,n=!1,o=setInterval(()=>{if(!n&&r.existsSync(e))try{let n=r.statSync(e);if(n.size<t&&(t=0),n.size<=t)return;let o=r.openSync(e,"r");try{let e=Buffer.alloc(n.size-t);r.readSync(o,e,0,e.length,t),t=n.size,e.length>0&&process.stdout.write(e.toString("utf8"))}finally{r.closeSync(o)}}catch{}},200);return()=>{n=!0,clearInterval(o)}}catch{return null}}(M.logPath);let l=el(s(H,t),{transport:function(e){let{command:t,flags:n,transport:r}=e;return"test"!==t||n.json?r:async e=>await r({...e,meta:{...e.meta,requestProgress:"replay-test"}})}({command:G,flags:H,transport:n.sendToDaemon})});if("batch"===G){if(!e)throw new p("INVALID_ARGS","batch requires --steps or --steps-file.");let t=e.map((e,t)=>({...e,input:T.lockPolicy&&void 0===B.platform?{...e.input}:t5(e.input,{policyOverrides:H,configuredPlatform:H.platform,configuredSession:H.session,inheritedPlatform:H.platform})}));if(await t0({command:G,positionals:V,flags:{...H,batchSteps:t},client:l}))return}else if("runtime"===G)throw new p("INVALID_ARGS","runtime command was removed. Use connect --remote-config <path> for remote runs, or metro prepare --remote-config <path> for inspection.");else if(await t0({command:G,positionals:V,flags:H,client:l}))return;throw new p("INVALID_ARGS",`Unknown command: ${G}`)}catch(n){let e=u(n),t=f(e,{diagnosticId:A().diagnosticId,logPath:S({force:!0})??void 0});if("close"===G&&"COMMAND_FAILED"===(U=e).code&&(U.details?.kind==="daemon_startup_failed"||U.message.toLowerCase().includes("failed to start daemon")&&("string"==typeof U.details?.infoPath||"string"==typeof U.details?.lockPath))){H.json&&e_({success:!0,data:{closed:"session",source:"no-daemon"}});return}if(H.json)e_({success:!1,error:t});else if(eD(t,{showDetails:q}),q)try{let e=M.logPath;if(r.existsSync(e)){let t=r.readFileSync(e,"utf8").split("\n"),n=t.slice(Math.max(0,t.length-200)).join("\n");n.trim().length>0&&process.stderr.write(`
|
|
44
44
|
[daemon log]
|
|
45
45
|
${n}
|
|
46
46
|
`)}}catch{}Z&&Z(),process.exit(1)}finally{Z&&Z()}})}function nt(e,t){return t.some(t=>"verbose"===t.key&&("--debug"===t.token||"-v"===t.token||"test"!==e))}n(process.argv[1]??"").href===import.meta.url&&ne(process.argv.slice(2)).catch(e=>{eD(f(u(e)),{showDetails:!0}),process.exit(1)});export{e_ as printJson,ne as runCli,tX as runCliCommandWithOutput,tS as writeCommandOutput};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{listMcpExposedCommandNames as t,BATCH_COMMAND_NAMES as e}from"./5792.js";import{readInputRecord as a,selectorSnapshotFields as r,elementTargetField as i,stringSchema as o,stringArrayField as n,jsonSchemaField as s,booleanSchema as p,integerSchema as c,integerField as d,customField as u,assertAllowedKeys as l,booleanField as m,enumField as h,requiredEnum as f,looseObjectField as g,readPoint as y,requiredField as b,pointField as w,readFieldInput as M,stringField as v,interactionTargetField as x,fieldsInputSchema as S,requiredNumber as P,readCommonInput as k,repeatedFields as
|
|
1
|
+
import{listMcpExposedCommandNames as t,BATCH_COMMAND_NAMES as e}from"./5792.js";import{readInputRecord as a,selectorSnapshotFields as r,elementTargetField as i,stringSchema as o,stringArrayField as n,jsonSchemaField as s,booleanSchema as p,integerSchema as c,integerField as d,customField as u,assertAllowedKeys as l,booleanField as m,enumField as h,requiredEnum as f,looseObjectField as g,readPoint as y,requiredField as b,pointField as w,readFieldInput as M,stringField as v,interactionTargetField as x,fieldsInputSchema as S,requiredNumber as P,readCommonInput as k,repeatedFields as _,looseObjectSchema as C,numberField as A,optionalInteger as E}from"./9404.js";import{PERF_AREA_VALUES as j,PERF_ACTION_VALUES as I}from"./8020.js";import{requireCommandDescription as R}from"./2805.js";function U(t,e){return{...t,run:e,invoke:async(a,r)=>await e(a,t.readInput(r))}}function O(t=e){var a;let r={steps:b(u({type:"array",description:"Structured batch steps. Each step uses a command name and the same input object as that command tool.",items:{type:"object",properties:{command:{type:"string",enum:a=t,description:"Command name to run with structured input."},input:{type:"object",additionalProperties:!0,description:"Structured command input for the nested command. Use the matching MCP tool schema for this object."},runtime:{type:"object",additionalProperties:!0,description:"Optional per-step runtime payload."}},required:["command","input"],additionalProperties:!1}},(t,e)=>(function(t,e){if(!Array.isArray(t))throw Error("Expected steps to be an array.");return t.map((t,a)=>{var r,i,o;let n;return r=t,i=a+1,o=e,l(n=function(t,e){if(!t||"object"!=typeof t||Array.isArray(t))throw Error(`Invalid batch step ${e}.`);return t}(r,i),["command","input","runtime"],`Batch step ${i}`),{command:f(n,"command",o),input:function(t,e){let a=t.input;if(!a||"object"!=typeof a||Array.isArray(a))throw Error(`Batch step ${e} input must be an object.`);return a}(n,i),...function(t,e){let a=t.runtime;if(void 0!==a&&(!a||"object"!=typeof a||Array.isArray(a)))throw Error(`Batch step ${e} runtime must be an object.`);return void 0===a?{}:{runtime:a}}(n,i)}})})(t[e],a))),onError:h(["stop"],"Batch failure policy."),maxSteps:d("Maximum number of steps accepted for this batch.",{min:1,max:1e3}),out:v("Optional output path for command artifacts.")};return{name:"batch",description:"Run multiple structured command steps in one daemon request.",inputSchema:S(r),readInput:t=>(function(t,e){let a=M(t,e),r=a.maxSteps??100;if(!Number.isInteger(r)||r<1||r>1e3)throw Error(`Invalid batch maxSteps: ${String(a.maxSteps)}`);if(a.steps.length>r)throw Error(`batch has ${a.steps.length} steps; max allowed is ${r}.`);return{...a}})(t,r)}}function B(t,e,a){return{name:t,description:e,inputSchema:S(a),readInput:t=>M(t,a)}}let K=["app","frontmost-app","desktop","menubar"],N=["start","stop"],$=[F("devices",{}),F("boot",{headless:m("Boot without showing simulator UI when supported.")}),F("prepare",{action:b(h(["ios-runner"])),timeoutMs:d("Maximum wall-clock time for the prepare command.")}),F("apps",{appsFilter:h(["user-installed","all"])}),F("session",{action:h(["list"])}),F("open",{app:v("App name, bundle id, package, or URL."),url:v("Optional URL passed with an app shell."),surface:h(K),activity:v("Android activity name."),launchConsole:v("Launch console mode."),launchArgs:n("Launch arguments forwarded verbatim to the platform launch command."),relaunch:m("Force relaunch."),saveScript:s({oneOf:[p(),o()]}),noRecord:m("Do not record this action.")}),F("close",{app:v("Optional app to close."),shutdown:m("Shutdown the session/device where supported."),saveScript:s({oneOf:[p(),o()]})}),F("install",{app:b(v()),appPath:b(v("Path to app binary."))}),F("reinstall",{app:b(v()),appPath:b(v("Path to app binary."))}),F("install-from-source",{source:b(s(C("Install source object."))),retainPaths:m(),retentionMs:d()}),F("push",{app:b(v()),payload:b(s({oneOf:[o(),C()]}))}),F("trigger-app-event",{event:b(v()),payload:g()}),F("snapshot",{interactiveOnly:m(),compact:m(),depth:d(),scope:v(),raw:m(),forceFull:m(),timeoutMs:d("Maximum wall-clock time for the snapshot command.")}),F("screenshot",{path:v("Output path."),overlayRefs:m(),fullscreen:m(),maxSize:d(),stabilize:m(),surface:h(K)}),F("diff",{kind:b(s({type:"string",const:"snapshot"})),out:v(),interactiveOnly:m(),compact:m(),depth:d(),scope:v(),raw:m()}),F("wait",{kind:h(["duration","text","ref","selector"]),durationMs:d(),text:v(),ref:v(),selector:v(),timeoutMs:d(),depth:d(),scope:v(),raw:m()}),F("alert",{action:h(["get","accept","dismiss","wait"]),timeoutMs:d()}),F("appstate",{}),F("back",{mode:h(["in-app","system"])}),F("home",{}),F("rotate",{orientation:b(h(["portrait","portrait-upside-down","landscape-left","landscape-right"]))}),F("app-switcher",{}),F("keyboard",{action:h(["status","dismiss"])}),F("clipboard",{action:b(h(["read","write"])),text:v()}),F("react-native",{action:b(h(["dismiss-overlay"]))}),F("replay",{path:b(v()),update:m(),backend:v(),maestro:m(),env:n()}),F("test",{paths:b(n()),update:m(),backend:v(),maestro:m(),env:n(),failFast:m(),timeoutMs:d(),retries:d(),artifactsDir:v(),reportJunit:v(),shardAll:d(),shardSplit:d()}),F("perf",{area:h(j),action:h(I)}),F("logs",{action:h(["path","start","stop","doctor","mark","clear"]),message:v(),restart:m()}),F("network",{action:h(["dump","log"]),limit:d(),include:h(["summary","headers","body","all"])}),F("record",{action:b(h(N)),path:v(),fps:d(),quality:s(c()),hideTouches:m()}),F("trace",{action:b(h(N)),path:v()}),F("settings",{setting:b(v()),state:b(v()),app:v(),latitude:A(),longitude:A(),permission:v(),mode:h(["full","limited"])}),F("metro",{action:b(h(["prepare","reload"])),projectRoot:v(),kind:s(o()),publicBaseUrl:v(),proxyBaseUrl:v(),bearerToken:v(),bridgeScope:s({type:"object",additionalProperties:!0}),launchUrl:v(),port:d(),listenHost:v(),statusHost:v(),startupTimeoutMs:d(),probeTimeoutMs:d(),reuseExisting:m(),installDependenciesIfNeeded:m(),runtimeFilePath:v(),logPath:v(),metroHost:v(),metroPort:d(),bundleUrl:v(),timeoutMs:d()})];function F(t,e){return B(t,R(t),e)}let H=["pan","fling","swipe","pinch","rotate","transform"],T=["up","down","left","right"],D=["left","right","left-edge","right-edge"],L={target:b(x()),button:h(["primary","secondary","middle"],"Pointer button for platforms that support mouse buttons."),...r(),..._()},q={target:b(x()),...r(),..._()},G={target:b(x()),text:b(v("Text to enter into the target.")),delayMs:d("Delay between typed characters.",{min:0}),...r()},z={target:b(x()),durationMs:d("Long press duration in milliseconds.",{min:0}),...r()},J={from:b(w("Swipe start point.")),to:b(w("Swipe end point.")),durationMs:d("Swipe duration in milliseconds.",{min:0}),count:d("Number of swipe repetitions.",{min:1}),pauseMs:d("Pause between repeated swipes.",{min:0}),pattern:h(["one-way","ping-pong"])},X={x:b(A("X coordinate.")),y:b(A("Y coordinate."))},Y={text:b(v("Text to type.")),delayMs:d("Delay between typed characters.",{min:0})},Q={direction:b(h(["up","down","left","right","top","bottom"])),amount:A("Platform scroll amount."),pixels:d("Pixel scroll amount.",{min:0})},V={format:b(h(["text","attrs"])),target:b(i()),...r()},W={predicate:b(h(["visible","hidden","exists","editable","selected","text"])),selector:b(v()),value:v(),...r()},Z={locator:h(["any","text","label","value","role","id"]),query:b(v()),action:h(["click","focus","exists","getText","getAttrs","wait","fill","type"]),value:v(),timeoutMs:d(),first:m(),last:m(),depth:d(),raw:m()},tt={kind:b(h(H,"Gesture variant.")),direction:h(T,"Fling direction."),preset:h(D,"Swipe preset."),origin:w("Gesture origin point."),delta:w("Movement delta for pan or transform gestures."),distance:d("Fling distance.",{min:0}),scale:A("Pinch or transform scale."),degrees:A("Rotation in degrees."),velocity:d("Rotate gesture velocity.",{min:0}),durationMs:d("Gesture duration in milliseconds.",{min:0})},te=[{name:"click",description:R("click"),inputSchema:S(L),readInput:t=>M(t,L)},{name:"press",description:R("press"),inputSchema:S(q),readInput:t=>M(t,q)},{name:"fill",description:R("fill"),inputSchema:S(G),readInput:t=>M(t,G)},ta("longpress",z),ta("swipe",J),ta("focus",X),ta("type",Y),ta("scroll",Q),ta("get",V),ta("is",W),ta("find",Z),{name:"gesture",description:R("gesture"),inputSchema:S(tt),readInput:function(t){let e=a(t),r=k(e),i=f(e,"kind",H);return"pan"===i?{...r,kind:i,origin:y(e,"origin"),delta:y(e,"delta"),durationMs:E(e,"durationMs",{min:0})}:"fling"===i?{...r,kind:i,direction:f(e,"direction",T),origin:y(e,"origin"),distance:E(e,"distance",{min:0}),durationMs:E(e,"durationMs",{min:0})}:"swipe"===i?{...r,kind:i,preset:f(e,"preset",D),durationMs:E(e,"durationMs",{min:0})}:"pinch"===i?{...r,kind:i,scale:P(e,"scale"),origin:tr(e,"origin")}:"rotate"===i?{...r,kind:i,degrees:P(e,"degrees"),origin:tr(e,"origin"),velocity:E(e,"velocity",{min:0})}:{...r,kind:i,origin:y(e,"origin"),delta:y(e,"delta"),scale:P(e,"scale"),degrees:P(e,"degrees"),durationMs:E(e,"durationMs",{min:0})}}}];function ta(t,e){return B(t,R(t),e)}function tr(t,e){return void 0===t[e]?void 0:y(t,e)}let ti=new Map([...te,...$,O(e)].map(t=>[t.name,t]));function to(){return t().map(t=>{var e;if(!tn(t))throw Error(`Missing command metadata for MCP-exposed command: ${t}`);return e=t,ti.get(e)})}function tn(t){return ti.has(t)}export{$ as clientCommandMetadata,O as createBatchCommandMetadata,U as defineExecutableCommand,te as interactionCommandMetadata,tn as isCommandName,to as listMcpCommandMetadata};
|