agent-device 0.21.22 → 0.21.24
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/README.md +6 -6
- package/android/ime-helper/dist/{agent-device-android-ime-helper-0.21.22.apk → agent-device-android-ime-helper-0.21.24.apk} +0 -0
- package/android/ime-helper/dist/agent-device-android-ime-helper-0.21.24.apk.sha256 +1 -0
- package/android/ime-helper/dist/{agent-device-android-ime-helper-0.21.22.manifest.json → agent-device-android-ime-helper-0.21.24.manifest.json} +4 -4
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.24.apk +0 -0
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.24.apk.sha256 +1 -0
- package/android/snapshot-helper/dist/{agent-device-android-snapshot-helper-0.21.22.manifest.json → agent-device-android-snapshot-helper-0.21.24.manifest.json} +6 -6
- package/apple/macos-helper/Sources/AgentDeviceMacOSHelper/SnapshotTraversal.swift +12 -6
- package/apple/macos-helper/Tests/AgentDeviceMacOSHelperTests/RectResponseTests.swift +21 -0
- package/apple/snapshot-bridge/README.md +9 -7
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandDispatch.swift +56 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +14 -5
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Lifecycle.swift +8 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift +12 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotCaptureTarget.swift +1 -1
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotExecution.swift +29 -5
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntry.swift +34 -10
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntryFocus.swift +19 -5
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextTyping.swift +3 -3
- package/dist/src/adapter.js +1 -1
- package/dist/src/adb.js +1 -1
- package/dist/src/agent-browser-lifecycle.js +1 -1
- package/dist/src/agent-browser-process-record.js +1 -1
- package/dist/src/agent-browser-provider.js +1 -1
- package/dist/src/agent-device-client.js +2 -2
- package/dist/src/alert-runtime.js +1 -1
- package/dist/src/alert.js +1 -1
- package/dist/src/android-adb.d.ts +3 -2
- package/dist/src/android-input-ownership.js +1 -1
- package/dist/src/app-backend.js +1 -1
- package/dist/src/app-inventory.d.ts +4 -0
- package/dist/src/app-launch.js +1 -1
- package/dist/src/app-lifecycle.js +1 -1
- package/dist/src/app-log-reconnect.js +1 -1
- package/dist/src/app-log-runtime2.js +3 -3
- package/dist/src/app-resolution.js +2 -2
- package/dist/src/app-state-runtime.d.ts +15 -0
- package/dist/src/apple-runner-platform.js +1 -1
- package/dist/src/application-lifecycle-interaction.js +1 -1
- package/dist/src/aws-device-farm-connection.js +1 -0
- package/dist/src/back-mode.js +1 -1
- package/dist/src/backend-snapshot-options.js +1 -1
- package/dist/src/browserstack-connection.js +1 -0
- package/dist/src/browserstack-device-features.js +1 -0
- package/dist/src/browserstack.js +1 -0
- package/dist/src/cache.js +1 -1
- package/dist/src/cli-config.js +1 -1
- package/dist/src/cli-help.js +35 -19
- package/dist/src/cli-runner.js +1 -1
- package/dist/src/cli.js +3 -4
- package/dist/src/client-companion-tunnel.js +1 -0
- package/dist/src/client-metro-companion.js +1 -1
- package/dist/src/client-metro.js +1 -1
- package/dist/src/client-options.js +3 -3
- package/dist/src/client-types.d.ts +7 -5
- package/dist/src/cloud-artifacts.d.ts +9 -2
- package/dist/src/code-signature-cache.js +1 -1
- package/dist/src/command-metadata.js +1 -1
- package/dist/src/command-schema.js +1 -1
- package/dist/src/command-tools.js +2 -2
- package/dist/src/connection-runtime.js +1 -1
- package/dist/src/connection-verification.js +1 -0
- package/dist/src/connection.js +5 -5
- package/dist/src/contracts.d.ts +1 -1
- package/dist/src/daemon-client-lease-beat.js +1 -1
- package/dist/src/daemon-client-lifecycle.js +1 -1
- package/dist/src/daemon-client-transport.js +1 -1
- package/dist/src/daemon-http.js +1 -1
- package/dist/src/daemon-policy-file.js +1 -1
- package/dist/src/daemon-registration-owner.js +1 -1
- package/dist/src/device-claim-inspection.js +1 -1
- package/dist/src/device-input-state.d.ts +2 -15
- package/dist/src/device-readiness-runtime.js +1 -1
- package/dist/src/device-selection-resolver.js +1 -1
- package/dist/src/device-session.js +3 -1
- package/dist/src/device.js +1 -1
- package/dist/src/device2.js +1 -1
- package/dist/src/device3.js +1 -1
- package/dist/src/dispatch-resolve.js +3 -3
- package/dist/src/doctor-facade.js +1 -1
- package/dist/src/durable-capture-resource.js +1 -1
- package/dist/src/durable-resource.js +1 -1
- package/dist/src/exec.js +1 -1
- package/dist/src/file.js +1 -1
- package/dist/src/find.js +1 -1
- package/dist/src/finders.js +1 -1
- package/dist/src/format.js +2 -1
- package/dist/src/gesture-admission.js +1 -1
- package/dist/src/gesture-plan-types.d.ts +2 -5
- package/dist/src/gesture-runtime.js +1 -1
- package/dist/src/helper.js +2 -2
- package/dist/src/human-control.js +1 -1
- package/dist/src/ime-rebind.js +1 -0
- package/dist/src/ime-settings-record.js +1 -0
- package/dist/src/ime-state.js +1 -0
- package/dist/src/index.d.ts +3 -3
- package/dist/src/input-actions.js +1 -1
- package/dist/src/input-actions2.js +1 -1
- package/dist/src/install-source2.js +1 -1
- package/dist/src/instance-client.js +1 -1
- package/dist/src/interaction-positionals.js +1 -1
- package/dist/src/interaction-ref-policy.js +1 -1
- package/dist/src/interaction.js +1 -1
- package/dist/src/interaction2.js +1 -1
- package/dist/src/interactor.js +5 -5
- package/dist/src/interactors.js +1 -1
- package/dist/src/internal/bin.js +1 -1
- package/dist/src/internal/daemon.js +1 -1
- package/dist/src/inventory2.js +1 -1
- package/dist/src/ios-client.js +4 -4
- package/dist/src/ios-snapshot-acquisition.js +1 -1
- package/dist/src/ios-snapshot-engine.js +1 -1
- package/dist/src/ios-snapshot-runtime.js +1 -1
- package/dist/src/launch-confirmation.js +1 -1
- package/dist/src/lease-scope.js +1 -1
- package/dist/src/lease.js +1 -1
- package/dist/src/limrun.d.ts +4 -555
- package/dist/src/load.js +1 -1
- package/dist/src/local-interactor-operation-set.js +1 -1
- package/dist/src/log-stream.js +33 -0
- package/dist/src/managed-device-scope.js +1 -1
- package/dist/src/manifest.js +1 -0
- package/dist/src/mechanics.js +16 -16
- package/dist/src/mobile-snapshot-semantics.js +1 -1
- package/dist/src/node-http.js +1 -0
- package/dist/src/observation.js +1 -2
- package/dist/src/overlay.js +3 -3
- package/dist/src/owner-identity.js +3 -3
- package/dist/src/perf-facade.js +1 -1
- package/dist/src/perf-runtime-plan.js +1 -1
- package/dist/src/perf-target.js +1 -1
- package/dist/src/physical-device-control.js +1 -1
- package/dist/src/platform-request-scope.js +1 -1
- package/dist/src/platform-runtime-app-log-process.js +1 -1
- package/dist/src/platform-runtime-open-target.js +1 -1
- package/dist/src/platform-runtime-operation-host.js +4 -4
- package/dist/src/platform-runtime-runtime-hints.js +1 -1
- package/dist/src/platform-runtime-screen-recording-finalizer-host.js +1 -1
- package/dist/src/platform-runtime-screen-recording-process-host.js +1 -1
- package/dist/src/platform-runtime-unavailable.js +1 -1
- package/dist/src/platform-runtime.js +1 -1
- package/dist/src/platform-runtime2.js +1 -1
- package/dist/src/plugin.js +1 -0
- package/dist/src/plugins/webdriver.d.ts +111 -0
- package/dist/src/plugins/webdriver.js +1 -0
- package/dist/src/plugins.d.ts +2 -1
- package/dist/src/plugins2.js +1 -1
- package/dist/src/process-exit.js +1 -1
- package/dist/src/process.js +1 -1
- package/dist/src/provider-credential-fingerprint.js +1 -1
- package/dist/src/provider-device-admission.js +1 -1
- package/dist/src/provider-device-runtime.d.ts +556 -0
- package/dist/src/provider-policy.js +1 -0
- package/dist/src/provider-profile-fields.js +1 -1
- package/dist/src/provider-webdriver.js +1 -2
- package/dist/src/providers.js +1 -1
- package/dist/src/proxy.js +2 -2
- package/dist/src/react-devtools.js +2 -0
- package/dist/src/react-native.js +1 -1
- package/dist/src/record-runtime.js +1 -1
- package/dist/src/record-trace.js +1 -1
- package/dist/src/recording.js +1 -1
- package/dist/src/registry.js +24 -24
- package/dist/src/remote-bridge.js +1 -0
- package/dist/src/remote-config-core.js +1 -0
- package/dist/src/remote-config.js +1 -1
- package/dist/src/remote-config2.js +1 -1
- package/dist/src/remote-connection-state.js +1 -0
- package/dist/src/replay.js +2 -2
- package/dist/src/request-admission.js +1 -1
- package/dist/src/request-runtime-binding.js +1 -1
- package/dist/src/result-serialization.js +1 -1
- package/dist/src/retry.js +1 -1
- package/dist/src/retry2.js +1 -0
- package/dist/src/runner-artifact-manifest.js +1 -1
- package/dist/src/runner-cache-metadata.js +2 -3
- package/dist/src/runner-cache-retention.js +1 -0
- package/dist/src/runner-cache-trim.js +1 -0
- package/dist/src/runner-client.js +1 -1
- package/dist/src/runner-dev-tools-security.js +1 -1
- package/dist/src/runner-device-readiness.js +1 -1
- package/dist/src/runner-device-set.js +1 -0
- package/dist/src/runner-disposal.js +1 -1
- package/dist/src/runner-error-classification.js +1 -1
- package/dist/src/runner-exchange.js +1 -1
- package/dist/src/runner-lease.js +1 -0
- package/dist/src/runner-operations-facade.js +1 -1
- package/dist/src/runner-session-types.js +1 -1
- package/dist/src/runner-start-budget.js +1 -1
- package/dist/src/runner-toolchain-probe.js +2 -0
- package/dist/src/runner.js +1 -1
- package/dist/src/runtime-deployment.js +1 -0
- package/dist/src/runtime.js +1 -1
- package/dist/src/runtime10.js +1 -2
- package/dist/src/runtime11.js +2 -0
- package/dist/src/runtime2.js +2 -5
- package/dist/src/runtime3.js +5 -1
- package/dist/src/runtime4.js +1 -5
- package/dist/src/runtime5.js +5 -1
- package/dist/src/runtime6.js +1 -1
- package/dist/src/runtime7.js +1 -1
- package/dist/src/runtime8.js +1 -1
- package/dist/src/runtime9.js +1 -1
- package/dist/src/screen-recording-transport.js +1 -1
- package/dist/src/screenshot-density.js +1 -1
- package/dist/src/screenshot-overlay-draw.js +1 -1
- package/dist/src/screenshot3.js +2 -2
- package/dist/src/script.js +1 -1
- package/dist/src/scroll-gesture.js +1 -1
- package/dist/src/sdk-batch.js +2 -2
- package/dist/src/sdk-contracts.d.ts +25 -33
- package/dist/src/sdk-contracts.js +2 -2
- package/dist/src/sdk-device.js +1 -1
- package/dist/src/sdk-finders.d.ts +1 -1
- package/dist/src/sdk-finders.js +1 -1
- package/dist/src/sdk-remote-config.d.ts +4 -0
- package/dist/src/sdk-remote-config.js +1 -1
- package/dist/src/sdk-selectors.d.ts +1 -1
- package/dist/src/sdk-selectors.js +1 -1
- package/dist/src/selection.js +0 -0
- package/dist/src/selector-pipeline-policy.js +1 -1
- package/dist/src/selector-runtime.js +1 -1
- package/dist/src/selectors.js +1 -1
- package/dist/src/server.js +2 -2
- package/dist/src/session-snapshot.js +1 -1
- package/dist/src/session2.js +5 -5
- package/dist/src/simctl.js +1 -1
- package/dist/src/simulator-boot.js +1 -1
- package/dist/src/simulator-state.js +1 -1
- package/dist/src/simulator.js +1 -1
- package/dist/src/snapshot-capture-annotations.js +1 -1
- package/dist/src/snapshot-desktop-projection.js +1 -1
- package/dist/src/snapshot-private-evidence.js +1 -0
- package/dist/src/snapshot-runtime-binding.js +1 -1
- package/dist/src/snapshot-runtime.js +1 -1
- package/dist/src/snapshot-state.js +1 -1
- package/dist/src/snapshot4.js +1 -1
- package/dist/src/src2.js +1 -1
- package/dist/src/src3.js +1 -1
- package/dist/src/src4.js +1 -1
- package/dist/src/src5.js +1 -1
- package/dist/src/src6.js +1 -1
- package/dist/src/src7.js +1 -1
- package/dist/src/src8.js +20 -20
- package/dist/src/store.js +1 -1
- package/dist/src/target-evidence.js +1 -1
- package/dist/src/text-entry-focus.js +1 -1
- package/dist/src/tool-provider2.js +1 -1
- package/dist/src/touch-runtime2.js +1 -1
- package/dist/src/tree.js +1 -1
- package/dist/src/type-text-runtime.js +1 -1
- package/dist/src/video.js +1 -1
- package/package.json +24 -16
- package/server.json +2 -2
- package/android/ime-helper/dist/agent-device-android-ime-helper-0.21.22.apk.sha256 +0 -1
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.22.apk +0 -0
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.22.apk.sha256 +0 -1
- package/dist/src/capabilities.js +0 -1
- package/dist/src/compatibility-policy.js +0 -1
- package/dist/src/daemon-artifacts.js +0 -1
- package/dist/src/device-claim-rule.js +0 -1
- package/dist/src/human-control-contract.js +0 -1
- package/dist/src/prepare-kind.js +0 -1
- package/dist/src/provider-device-runtimes.js +0 -1
- package/dist/src/screen-recording-admission-ledger.js +0 -1
- package/dist/src/screenshot-runtime.js +0 -1
- package/dist/src/session-routing.js +0 -1
- package/dist/src/session-runtime-admission.js +0 -1
- package/dist/src/session-stream.js +0 -27
- package/dist/src/timeouts.js +0 -1
- package/dist/src/touch-reference-frame.js +0 -1
- package/dist/src/vars.js +0 -2
- package/dist/src/viewport.js +0 -1
package/dist/src/cli-help.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import{r as e}from"./rolldown-runtime.js";import{
|
|
2
|
-
`)}function h(e){let t=e.endsWith(`?`),n=t?e.slice(0,-1):e;return t?`[${n}]`:`<${n}>`}function g(e){return
|
|
1
|
+
import{r as e}from"./rolldown-runtime.js";import{F as t,T as n,c as r,w as i}from"./registry.js";import{yr as a}from"./sdk-batch.js";import{i as o}from"./catalog.js";import{r as s}from"./back-mode.js";import{a as c}from"./version.js";import{n as l,r as u}from"./command-schema.js";import{n as d}from"./cli-command-aliases.js";const f=[`Flows: launchApp (with clearState, permissions, and Apple-only launch arguments; permissions apply after state clearing but before launch, and a launchApp without permissions touches nothing — there is no silent all: allow default); setPermissions (mid-flow permission grants, denials, and resets; all resolves in the backend — one simctl call on iOS, the declared permissions on Android — with specific entries overriding after it); runFlow file/inline; runFlow.when and repeat.while conditions (platform, visible, notVisible, and true, all re-evaluated before every repeat iteration); onFlowStart/onFlowComplete; repeat with times, while, or both; and retry.`,`Interactions: tapOn, doubleTapOn, longPressOn, inputText on the focused element, eraseText, openLink, hideKeyboard, basic pressKey, and back; selector targets poll until available and support recursive index, childOf, above, below, leftOf, rightOf, containsChild, containsDescendants, points, and optional; outer command labels are metadata, not target selectors.`,'Assertions and navigation: assertVisible, assertNotVisible, assertTrue (literal values and ${VAR} lookups only; "", "false", "0", "null", and "undefined" are falsy, everything else is truthy), extendedWaitUntil, scroll, scrollUntilVisible, absolute/percentage/target swipe, takeScreenshot, waitForAnimationToEnd, clearState, and stopApp.',`Scripts: ordered runScript file/env scripts with http.post, json, and output variables; evalScript inline expressions run flow-scoped JavaScript and write output.* leaves for later steps.`],p=[`Permissions: every entry is one settings permission call, applied in order with all first; the step stops at the first entry the selected platform refuses, earlier entries stay applied, and the error names what landed. Android’s only allow level is while-in-use, so location: inuse and location: never mean allow and deny there, while location: always and photos: limited are Apple-only and fail. On iOS, which service a runtime changes is simctl privacy’s own verdict: current runtimes refuse a targeted notifications change and leave notifications untouched under all.`,`Runtime: iOS and Android only; launchApp.clearState and standalone clearState support Android and iOS simulators, launch arguments are Apple-only, and other standalone device utility/state commands are unsupported.`,"Expressions: evalScript and condition true: fields (runFlow.when and repeat.while share one evaluator) are evaluated as JavaScript (flow env and prior output leaves are string-typed); a true: field that is a boolean, a maestro.platform comparison, or plain literal text after ${VAR} lookups is decided without JavaScript, with the assertTrue falsy table for literal text. Other fields stay literal or ${VAR} lookup-only — assertTrue supports literals and bare lookups, and other expression-shaped payloads fail loud.",`Environment: flow env is the default, AD_VAR_* overrides it, and CLI -e KEY=VALUE wins over both.`,`Failure diagnostics: resolved targets and runFlow paths are rendered, while inputText payloads remain hidden; do not place secrets in diagnostic identifiers.`,`Trust: runScript, evalScript, and JavaScript condition true: fields execute flow scripts in-process via node:vm, which is not a security sandbox; runScript may make http.post network requests and its output keys cannot contain a dot. evalScript and true: fields that need JavaScript are refused outright for a flow accepted over the daemon’s remote HTTP surface, since that context can escape to the host.`,`Errors and tracking: unsupported commands and fields fail with source context when available; open a focused issue only when implementation work is planned.`];function m(){return[`Supported subset:`,...f.map(e=>` - ${e}`),``,`Boundaries:`,...p.map(e=>` - ${e}`)].join(`
|
|
2
|
+
`)}function h(e){let t=e.endsWith(`?`),n=t?e.slice(0,-1):e;return t?`[${n}]`:`<${n}>`}function g(e){return s().filter(t=>t.key===e)}function _(e){if(!e.usageHidden)return e.usageLabel??e.names[0]}function v(e){return(e??[]).flatMap(e=>g(e).map(_).filter(e=>e!==void 0).map(e=>`[${e}]`))}function y(e,t){return[t.usageOverride??[e,...(t.positionalArgs??[]).map(h)].join(` `),...v(t.usageFlags??t.allowedFlags)].join(` `)}const b=`Wait failure contract:
|
|
3
3
|
Read --json error.details.reason.
|
|
4
4
|
wait_target_absent: readable capture, no match.
|
|
5
5
|
wait_target_present: absence timeout; details.matches/firstMatch.
|
|
@@ -271,7 +271,7 @@ Report:
|
|
|
271
271
|
If live validation is blocked, state the blocker, device/session, and exact next command needed.`}};function w(){return`agent-device <command> [args] [--json]
|
|
272
272
|
|
|
273
273
|
Automates iOS, Android, macOS, TV, and web apps for AI agents.
|
|
274
|
-
All ${
|
|
274
|
+
All ${o().length} commands: agent-device help commands
|
|
275
275
|
|
|
276
276
|
Start:
|
|
277
277
|
When starting a task with a known app, first run:
|
|
@@ -294,7 +294,7 @@ Loop:
|
|
|
294
294
|
Targets:
|
|
295
295
|
Copy refs exactly: @e12, @e12~s4. Keep @ and any ~sN pin; refs go stale
|
|
296
296
|
after mutations. A literal @handle is label="@handle", not a bare ref.
|
|
297
|
-
Prefer refs, then id/label/role selectors. Selector keys: ${
|
|
297
|
+
Prefer refs, then id/label/role selectors. Selector keys: ${a.join(` `)}.
|
|
298
298
|
Coordinates are last resort: after snapshot -i shows no semantic target, or a
|
|
299
299
|
sparse/AX-unavailable warning says its refs and selectors are invalid.
|
|
300
300
|
Then screenshot, press <x> <y>, and re-snapshot on the changed screen.
|
|
@@ -352,7 +352,7 @@ Snapshots and refs:
|
|
|
352
352
|
|
|
353
353
|
Selectors:
|
|
354
354
|
id="field-email", label="Allow", role=button label="Search" -- not bare role keys (button="Search"); no CSS selectors/--selector/--text/raw x-y when refs/selectors exist.
|
|
355
|
-
Mutating selector ambiguity: press/click/fill/longpress collapse duplicate accessibility wrappers only when every match is one ancestor-descendant chain resolving to the same actionable node. Matches in distinct subtrees fail with AMBIGUOUS_MATCH and a bounded candidate list; geometry never chooses a winner. Retry one printed candidate ref (pinned to refsGeneration) or narrow the selector with role/id/longer text.
|
|
355
|
+
Mutating selector ambiguity: press/click/fill/longpress collapse duplicate accessibility wrappers only when every match is one ancestor-descendant chain resolving to the same actionable node. Matches in distinct subtrees fail with AMBIGUOUS_MATCH and a bounded candidate list; geometry never chooses a winner. Retry one printed candidate ref (pinned to refsGeneration) or narrow the selector with role/id/longer text. Uniqueness-based reads (is except exists/absent, get attrs) share that failure shape.
|
|
356
356
|
hittable: false on a resolved element does not block dispatch (iOS AX flags are unreliable on deep RN trees); press/fill/click return targetHittable: false plus a hint -- verify or re-target, not a failure.
|
|
357
357
|
|
|
358
358
|
Text entry:
|
|
@@ -778,7 +778,7 @@ Rules:
|
|
|
778
778
|
Do not hard-code Edit/Done/Add Widget or other SpringBoard label text into a plan as a fixed assumption; take them from the latest snapshot -i so the plan survives iOS version/locale differences.
|
|
779
779
|
A real system permission alert can appear mid-flow; it composes with this workflow normally, so handle it with alert wait/accept/dismiss or by pressing the visible label like any other step.
|
|
780
780
|
Prefer refs/selectors from the fresh snapshot for every step except the two documented coordinate fallbacks (empty-space long-press to enter edit mode, and the gallery search-result tap).
|
|
781
|
-
This topic covers what already works by opening SpringBoard as the session app. It does not yet cover keeping an app session open while alternating individual commands against SpringBoard, or Live Activity/Dynamic Island semantics; those land separately.`},foldable:
|
|
781
|
+
This topic covers what already works by opening SpringBoard as the session app. It does not yet cover keeping an app session open while alternating individual commands against SpringBoard, or Live Activity/Dynamic Island semantics; those land separately.`},foldable:r,remote:{summary:`Direct proxy, cloud profiles, and remote config`,body:`agent-device help remote
|
|
782
782
|
|
|
783
783
|
Remote connection providers use the same lifecycle:
|
|
784
784
|
connect -> install/open -> commands -> close -> disconnect
|
|
@@ -789,17 +789,18 @@ Providers:
|
|
|
789
789
|
Direct proxy: agent-device connect proxy --daemon-base-url <proxy-agent-device-url> stores the shared proxy profile and client identity.
|
|
790
790
|
BrowserStack: agent-device connect browserstack verifies credentials, the exact device, and a bs:// app reference, then stores a local provider profile. It does not create an App Automate session.
|
|
791
791
|
AWS Device Farm: agent-device connect aws-device-farm verifies credentials and the exact project, device, and optional app upload, then stores a local provider profile. It does not create a remote access session.
|
|
792
|
+
TestMu AI: agent-device connect testmu verifies credentials and the exact virtual device (emulator or simulator) or, with --provider-device-type real, real device and OS version, then stores a local provider profile. --provider-app takes an lt:// app reference, an https URL, or a local path: connect looks an lt:// id up among your uploads for that device pool, while URL and local sources are uploaded and validated when open creates the session. It does not create a hub session.
|
|
792
793
|
Limrun: agent-device connect limrun verifies access to the selected iOS or Android instance service, then stores a local provider profile. It does not create an instance.
|
|
793
794
|
|
|
794
795
|
After direct-provider connect:
|
|
795
796
|
Read the printed Device, App, Next, and workflow-note lines. They are also available as verification/device/app/liveSession/nextSteps/notes in --json output.
|
|
796
|
-
BrowserStack
|
|
797
|
+
BrowserStack, AWS Device Farm, and TestMu AI create the hosted session on open. open needs the installed package or bundle identifier, not the app artifact name, ARN, or lt:// id.
|
|
797
798
|
Before provider allocation, apps lists compatible uploaded app assets without creating an instance when the selected provider exposes a catalog. open <exact-asset-name> creates the instance with that asset, resolves its installed app id, and launches it. install remains available when the app comes from a fresh local path or URL.
|
|
798
799
|
AWS Device Farm cannot install after allocation. If connect reports no attached app, run its printed reconnect command, which includes --session <name> --force, before open.
|
|
799
800
|
Do not run devices as a pre-open catalog probe for direct providers; it can allocate the deferred provider session. Limrun is the exception for apps: before allocation it lists uploaded assets for the selected platform.
|
|
800
801
|
|
|
801
802
|
Device cloud interfaces:
|
|
802
|
-
CLI is the canonical bootstrap path: connect limrun/browserstack/aws-device-farm, then use normal open/snapshot/click/close/artifacts/disconnect commands.
|
|
803
|
+
CLI is the canonical bootstrap path: connect limrun/browserstack/aws-device-farm/testmu, then use normal open/snapshot/click/close/artifacts/disconnect commands.
|
|
803
804
|
JavaScript can skip persisted connect state by passing leaseProvider plus provider fields to createAgentDeviceClient or per-command options.
|
|
804
805
|
MCP exposes operational tools such as open, snapshot, click, close, and artifacts. It does not expose connect/disconnect; run CLI connect first in the same state dir before relying on MCP tools.
|
|
805
806
|
|
|
@@ -829,6 +830,20 @@ Cloud profile flow:
|
|
|
829
830
|
agent-device snapshot
|
|
830
831
|
agent-device disconnect
|
|
831
832
|
|
|
833
|
+
TestMu AI virtual-device flow (emulators and simulators):
|
|
834
|
+
agent-device plugins add @agent-device/testmu
|
|
835
|
+
export LT_USERNAME=... LT_ACCESS_KEY=...
|
|
836
|
+
agent-device connect testmu --platform ios --device "iPhone 16" --provider-os-version 18.0 --provider-app lt://APP-id
|
|
837
|
+
agent-device open com.example.app
|
|
838
|
+
agent-device snapshot -i
|
|
839
|
+
agent-device close
|
|
840
|
+
agent-device artifacts --json
|
|
841
|
+
agent-device disconnect
|
|
842
|
+
|
|
843
|
+
TestMu AI real-device flow:
|
|
844
|
+
agent-device connect testmu --provider-device-type real --platform ios --device "iPhone 16" --provider-os-version 18 --provider-app ./MyApp.ipa
|
|
845
|
+
Real iOS devices are listed by major OS version (18, not 18.0) and install a signed .ipa. Real and virtual devices have separate upload APIs, so pass an lt:// id uploaded for the pool you connect to.
|
|
846
|
+
|
|
832
847
|
BrowserStack hosted-device flow:
|
|
833
848
|
BROWSERSTACK_USERNAME=... BROWSERSTACK_ACCESS_KEY=...
|
|
834
849
|
agent-device connect browserstack --platform android --device "Google Pixel 8" --provider-os-version 14.0 --provider-app bs://app-id
|
|
@@ -877,13 +892,13 @@ Rules:
|
|
|
877
892
|
Use connect without --remote-config when the cloud control plane owns the connection profile.
|
|
878
893
|
Prefer connect --remote-config over --daemon-base-url, --tenant, --run-id, and --lease-id when using a local profile.
|
|
879
894
|
Use agent-device proxy for direct tunnel access to a Mac you control. Expose the printed proxy URL through cloudflared/ngrok, then run agent-device connect proxy with the tunnel URL and printed token before normal commands.
|
|
880
|
-
Use Limrun, BrowserStack,
|
|
881
|
-
Device cloud credentials must be available before the command starts. Limrun uses LIMRUN_API_KEY, or the LIM_*_INSTANCE_* variables for an existing instance. BrowserStack uses BROWSERSTACK_USERNAME and BROWSERSTACK_ACCESS_KEY. AWS Device Farm uses the AWS CLI credential chain, including CI-provided AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY/AWS_SESSION_TOKEN, AWS profiles, or web identity role variables.
|
|
882
|
-
A local daemon keeps the Limrun and
|
|
895
|
+
Use Limrun, BrowserStack, AWS Device Farm, and TestMu AI through local provider profiles; they do not accept a remote agent-device daemon URL.
|
|
896
|
+
Device cloud credentials must be available before the command starts. Limrun uses LIMRUN_API_KEY, or the LIM_*_INSTANCE_* variables for an existing instance. BrowserStack uses BROWSERSTACK_USERNAME and BROWSERSTACK_ACCESS_KEY. TestMu AI uses LT_USERNAME and LT_ACCESS_KEY. AWS Device Farm uses the AWS CLI credential chain, including CI-provided AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY/AWS_SESSION_TOKEN, AWS profiles, or web identity role variables.
|
|
897
|
+
A local daemon keeps the Limrun, BrowserStack, and TestMu AI credentials it started with. When the shell holds different ones, the first command that allocates a lease refuses with reason provider-credentials-changed; run agent-device daemon stop with the same --state-dir, then rerun the command. A shell that sets none of them uses the daemon's. A daemon with an HTTP auth hook serves remote callers and does not compare.
|
|
883
898
|
Direct-provider connect performs read-only provider calls and saves active connection state only after verification succeeds. It never creates a device, instance, App Automate session, or AWS remote access session.
|
|
884
899
|
connect without --session always creates a fresh remote session and prints that session in its next-step commands. Concurrent callers must pass the returned --session on every command; the ambient active connection is only a single-workflow convenience.
|
|
885
900
|
To replace an existing connection, pass its returned session explicitly with --session <name> --force. --force without --session creates another fresh session and does not release or overwrite an unrelated active connection.
|
|
886
|
-
Prefer short-lived AWS role credentials in CI. Generated connection profiles store app/device selectors and ARNs, not Limrun API keys or instance tokens, BrowserStack access keys, or AWS credentials.
|
|
901
|
+
Prefer short-lived AWS role credentials in CI. Generated connection profiles store app/device selectors and ARNs, not Limrun API keys or instance tokens, BrowserStack or TestMu AI access keys, or AWS credentials.
|
|
887
902
|
Limrun Android supports direct ADB port reverse for local Metro. Limrun iOS requires a public Metro/React DevTools URL because it cannot reach local host ports directly.
|
|
888
903
|
After closing a device cloud session, run agent-device artifacts --json to retrieve provider video/log/dashboard URLs when the provider has made them available.
|
|
889
904
|
connect proxy stores the connection profile and client identity. Proxy device leases are acquired on open and expire after five minutes without commands; devices may inspect proxy inventory without allocating.
|
|
@@ -928,7 +943,8 @@ Rules:
|
|
|
928
943
|
Context menus are not ambient UI: secondary-click a visible target, then re-snapshot and use the new menu-item refs.
|
|
929
944
|
Do not let iOS simulator-set scoping hide macOS desktop targets.
|
|
930
945
|
Prefer refs/selectors over raw coordinates.
|
|
931
|
-
macOS snapshot rects are window-space; use current refs or overlay refs instead of guessing coordinates
|
|
946
|
+
macOS snapshot rects are window-space; use current refs or overlay refs instead of guessing coordinates.
|
|
947
|
+
On the default XCTest backend a read (snapshot, get, find) of a session app that sits behind other windows is answered from where it sits, without raising the app; interactions and a window-level screenshot of that app still bring it forward.`},web:{summary:`Minimal browser workflow with the managed web backend`,body:`agent-device help web
|
|
932
948
|
|
|
933
949
|
Use --platform web only for the minimal browser command loop exposed through agent-device.
|
|
934
950
|
|
|
@@ -979,25 +995,25 @@ Rules:
|
|
|
979
995
|
|
|
980
996
|
Full command catalog. Use agent-device help <command> for exact flags and behavior.
|
|
981
997
|
|
|
982
|
-
${B(
|
|
998
|
+
${B(o().map(e=>{let t=l(e);return{name:e,schema:t,usage:j(e,t)}}))}
|
|
983
999
|
|
|
984
1000
|
${L(`Device Selection (shared by device commands; help <command> lists each command's flags):`,F(i))}
|
|
985
1001
|
|
|
986
|
-
${L(`Global Flags:`,F(
|
|
1002
|
+
${L(`Global Flags:`,F(n))}
|
|
987
1003
|
|
|
988
1004
|
${z(`Configuration:`,E)}
|
|
989
1005
|
|
|
990
1006
|
${R(`Environment:`,D)}
|
|
991
1007
|
|
|
992
1008
|
${z(`Examples:`,O)}
|
|
993
|
-
`}function P(){return M()}function F(e){return
|
|
1009
|
+
`}function P(){return M()}function F(e){return s().filter(t=>e.has(t.key)&&t.usageLabel!==void 0&&t.usageDescription!==void 0)}function I(e,t){return t?e.map(e=>{let n=t[e.key];return n===void 0?e:{...e,usageDescription:n}}):e}function L(e,t){return R(e,t.map(e=>({label:e.usageLabel??``,description:e.usageDescription??``})))}function R(e,t){if(t.length===0)return`${e}\n (none)`;let n=Math.max(...t.map(e=>Math.min(e.label.length,26)))+2,r=[e];for(let e of t){let t=e.label.length<=26?e.label.padEnd(n):`${e.label} `;r.push(` ${t}${e.description}`)}return r.join(`
|
|
994
1010
|
`)}function z(e,t){return t.length===0?`${e}\n (none)`:[e,...t.map(e=>` ${e}`)].join(`
|
|
995
|
-
`)}function B(e){return R(`Commands:`,e.map(e=>({label:e.usage,description:e.schema.text.summary})))}function V(e){let
|
|
1011
|
+
`)}function B(e){return R(`Commands:`,e.map(e=>({label:e.usage,description:e.schema.text.summary})))}function V(e){let n=W(e);if(n)return n;let r=u(e);if(!r)return null;let i=y(e,r),a=I(F(new Set(r.allowedFlags??[])),r.flagDescriptionOverrides),o=[];a.length>0&&o.push(L(`Command flags:`,a));let s=o.length>0?`\n\n${o.join(`
|
|
996
1012
|
|
|
997
1013
|
`)}`:``;return`Usage:
|
|
998
|
-
agent-device ${
|
|
1014
|
+
agent-device ${i}
|
|
999
1015
|
|
|
1000
|
-
${
|
|
1016
|
+
${t(r.text)}${s}
|
|
1001
1017
|
`}function H(e){return V(d(e))}function U(){return Object.keys(k)}function W(e){let t=k[e];return t?`${G(e,e===`commands`?N():t.body)}
|
|
1002
1018
|
|
|
1003
1019
|
Related:
|
package/dist/src/cli-runner.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{n as e,
|
|
1
|
+
import{n as e,y as t}from"./registry.js";import{t as n}from"./cli-output.js";import{n as r}from"./command-surface.js";const i=e();function a(e,n,r){let a=i[e];if(!a)throw Error(`Missing CLI reader for command: ${e}`);return{...a(n,r),...t(e,r)}}async function o(e){return(await s(e)).result}async function s(e){let t=a(e.command,e.positionals,e.flags),i=await r(e.client,e.command,t);return{result:i,cliOutput:await n({name:e.command,input:t,result:i,progress:e.commandProgress})}}export{s as n,o as t};
|
package/dist/src/cli.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import{F as e,J as t,P as n,nt as r}from"./sdk-contracts.js";import{t as i}from"./capture.js";import{d as a,f as o,s,u as c}from"./sdk-batch-runner.js";import{a as l,i as u,l as d,n as f,o as p,r as m}from"./diagnostics.js";import"./diagnostics2.js";import{n as h,r as g}from"./agent-device-client.js";import{s as ee,t as te,u as ne}from"./sdk-batch.js";import{i as re,r as _,t as v}from"./catalog.js";import{n as y,r as b}from"./back-mode.js";import{L as ie}from"./registry.js";import{p as ae}from"./exec.js";import{n as oe}from"./command-metadata.js";import"./command.js";import{t as se}from"./session-artifact-paths.js";import{a as ce}from"./version.js";import{t as le}from"./daemon-resolution.js";import{r as x,t as ue}from"./command-schema.js";import{i as S,r as C,t as de}from"./cli-config.js";import{t as fe}from"./update-check.js";import{n as pe,r as me,t as he}from"./cli-command-aliases.js";import{exitAfterFlush as w}from"./process-exit.js";import{A as ge,D as _e,M as ve,f as ye,h as be,j as xe,k as Se,r as Ce}from"./connection-runtime.js";import{i as we}from"./auth-session.js";import T from"node:fs";import{pathToFileURL as Te}from"node:url";const E=`open <app> --relaunch`,Ee={start:{command:`open`,example:E},restart:{command:`open`,example:E},touch:{command:`press`,example:`press`},input:{command:`fill`,example:`fill`},settext:{command:`fill`,example:`fill`},entertext:{command:`fill`,example:`fill`},screencap:{command:`screenshot`,example:`screenshot`},capture:{command:`screenshot`,example:`screenshot`},dismiss:{command:`keyboard`,example:`keyboard dismiss`},"get-text":{command:`get`,example:`get text`},gettext:{command:`get`,example:`get text`},get_text:{command:`get`,example:`get text`},"open-url":{command:`open`,example:`open <url>`},"close-session":{command:`close`,example:`close`}};function D(e){if(e.length<=2)return[];let t=re(),n=t.filter(t=>t.startsWith(e));return n.length>0?n.sort(O).slice(0,3):k(e,t)}function O(e,t){return e.length-t.length||e.localeCompare(t)}function k(e,t){let n=t.map(t=>({name:t,distance:Oe(e,t)})).filter(t=>t.distance<=De(e));if(n.length===0)return[];let r=Math.min(...n.map(e=>e.distance));return n.filter(e=>e.distance===r).sort((e,t)=>e.name.localeCompare(t.name)).slice(0,3).map(e=>e.name)}function De(e){return e.length<4?1:e.length<=6?2:3}function Oe(e,t){return e===t?0:e.startsWith(t)||t.startsWith(e)?Math.abs(e.length-t.length):ke(e,t)}function ke(e,t){let n=e.length+1,r=t.length+1,i=Array.from({length:n},()=>Array(r).fill(0));for(let e=0;e<n;e+=1)i[e][0]=e;for(let e=0;e<r;e+=1)i[0][e]=e;for(let a=1;a<n;a+=1)for(let n=1;n<r;n+=1){let r=e[a-1]===t[n-1]?0:1;i[a][n]=Math.min(i[a-1][n]+1,i[a][n-1]+1,i[a-1][n-1]+r)}return i[n-1][r-1]}function A(e){let t=e.toLowerCase(),n=Ee[t]?.example;if(n)return n;let r=D(t);if(r.length!==0)return r.length===1?r[0]:`one of: ${r.join(`, `)}`}const Ae=new Set([`--bundle-id`,`--bundleid`,`--bundle`,`--package`,`--package-name`,`--packagename`,`--app-id`,`--appid`,`--pkg`]),je=new Set([`--session-locked`,`--session-lock-conflicts`]),Me={"--output":`--out`,"--path":`--out`};function Ne(e,t){let n=e.toLowerCase(),r=Me[n];if(r&&Pe(r,t))return r;let i=Fe(n,t);if(i.length!==0)return i.length===1?i[0]:`one of: ${i.join(`, `)}`}function Pe(e,t){let n=b().find(t=>t.names.includes(e));return n?S(n.key,t):!1}function Fe(e,t){let n=j(e);if(n.length<=2)return[];let r=Ie(t),i=r.filter(e=>j(e).startsWith(n));return i.length>0?i.sort(O).slice(0,3):k(n,r.map(e=>j(e))).map(e=>`--${e}`)}function Ie(e){let t=new Set;for(let n of b()){if(!S(n.key,e))continue;let r=n.names[0];r&&t.add(r)}return[...t]}function j(e){return e.replace(/^--?/,``)}function Le(e,t){let n=e.toLowerCase();if(Ae.has(n))return`Unknown flag: ${e}. The app or bundle id is a positional argument, e.g. ${E}.`;if(je.has(n))return`Unknown flag: ${e}. Use --session-lock reject|strip instead.`;if(n===i.cliToken)return`Unknown flag: ${e}. ${i.migration.screenshot}. ${i.migration.record}.`;let r=Ne(e,t);return r?`Unknown flag: ${e}. Did you mean ${r}?`:`Unknown flag: ${e}`}function M(e){let t={json:!1,help:!1,version:!1},r=null,i=null,a=[],o=[],s=[],c=!0;for(let o=0;o<e.length;o+=1){let l=e[o];if(c&&l===`--`){c=!1;continue}if(!c){r?a.push(l):(i=l,r=L(l));continue}if(Ve(r)){a.push(l);continue}let u=l.startsWith(`--`),d=l.startsWith(`-`)&&l.length>1;if(!u&&!d){r?a.push(l):(i=l,r=L(l));continue}let[f,p]=u?N(l):[l,void 0];if(ze(r,f))continue;let m=He(f,r);if(Be(r,m)){a.push(l);continue}if(!m){if(qe(r,a,l)){r?a.push(l):r=l;continue}throw new n(`INVALID_ARGS`,Le(f,r))}let h=Ge(m,f,p,e[o+1]);h.consumeNext&&(o+=1);let g=t[m.key];if(m.multiple){let e=Array.isArray(g)?[...g,h.value]:g===void 0?[h.value]:[g,h.value];t[m.key]=e}else t[m.key]=h.value;s.push({key:m.key,token:f})}return Re(i,t),{command:r,positionals:a,flags:t,warnings:o,providedFlags:s}}function Re(e,t){if(e)for(let n of he(e)?.impliedFlags??[])t[n]=!0}function ze(e,t){return t===`-c`&&(e===`snapshot`||e===`diff`)}function Be(e,t){return e===`react-devtools`?!t||!S(t.key,e):!1}function Ve(e){return e===`cdp`}function He(e,t){let n=b().filter(t=>t.names.includes(e));if(n.length<=1)return n[0]??y(e);if(t){let e=n.find(e=>S(e.key,t));if(e)return e}return y(e)}function Ue(e,t){let r=t?.strictFlags??!0,i=[...e.warnings],a=C({json:!1,help:!1,version:!1},t?.defaultFlags??{});if(C(a,e.flags),e.command&&!_(e.command)&&!a.help){let t=A(e.command),r=t?`Unknown command: ${e.command}. Did you mean ${t}?`:`Unknown command: ${e.command}`;throw new n(`INVALID_ARGS`,r)}let o=e.providedFlags.filter(t=>!S(t.key,e.command));if(o.length>0){let t=o.map(e=>e.token),s=$e(e.command,t);if(r)throw new n(`INVALID_ARGS`,s);i.push(s);for(let e of o)delete a[e.key]}let s=Ze(e);if(s.length>0){let t=Qe(e.command,e.positionals[0],s);if(r)throw new n(`INVALID_ARGS`,t);i.push(t);for(let e of s)delete a[e.key]}for(let t of Object.keys(a))a[t]!==void 0&&(S(t,e.command)||delete a[t]);Xe(e,a),We(e),ne(e.command,a);let c=Ye({command:e.command,positionals:e.positionals,flags:a,warnings:i});if(ue(c.command,c.positionals),c.command===`batch`&&+!!a.steps+ +!!a.stepsFile!=1)throw new n(`INVALID_ARGS`,`batch requires exactly one step source: --steps or --steps-file.`);return c}function We(e){if(e.command!==`back`)return;let t=e.providedFlags.filter(e=>e.key===`backMode`);if(!(new Set(t.map(e=>e.token)).size<=1))throw new n(`INVALID_ARGS`,`back accepts only one explicit mode flag: use either --in-app or --system.`)}function N(e){let t=e.indexOf(`=`);return t===-1?[e,void 0]:[e.slice(0,t),e.slice(t+1)]}function Ge(e,t,r,i){if(e.setValue!==void 0){if(r!==void 0)throw new n(`INVALID_ARGS`,`Flag ${t} does not take a value.`);return{value:e.setValue,consumeNext:!1}}if(e.type===`boolean`){if(r!==void 0)throw new n(`INVALID_ARGS`,`Flag ${t} does not take a value.`);return{value:!0,consumeNext:!1}}if(e.type===`booleanOrString`){if(r!==void 0){if(r.trim().length===0)throw new n(`INVALID_ARGS`,`Flag ${t} requires a non-empty value when provided.`);return{value:r,consumeNext:!1}}return i===void 0||F(i)?{value:!0,consumeNext:!1}:Ke(i)?{value:i,consumeNext:!0}:{value:!0,consumeNext:!1}}let a=r??i;if(a===void 0||r===void 0&&F(a))throw new n(`INVALID_ARGS`,`Flag ${t} requires a value.`);if(e.type===`string`)return{value:a,consumeNext:r===void 0};if(e.type===`enum`){if(!e.enumValues?.includes(a))throw new n(`INVALID_ARGS`,`Invalid ${P(t)}: ${a}`);return{value:a,consumeNext:r===void 0}}let o=Number(a);if(!Number.isFinite(o)||typeof e.min==`number`&&o<e.min||typeof e.max==`number`&&o>e.max)throw new n(`INVALID_ARGS`,`Invalid ${P(t)}: ${a}`);return{value:e.type===`int`?Math.floor(o):o,consumeNext:r===void 0}}function P(e){return e.replace(/^-+/,``)}function F(e){if(!e.startsWith(`-`)||e===`-`)return!1;let[t]=e.startsWith(`--`)?N(e):[e,void 0];return y(t)!==void 0}function Ke(e){let t=e.trim();return!t||/^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(t)?!1:!!(t.startsWith(`./`)||t.startsWith(`../`)||t.startsWith(`~/`)||t.startsWith(`/`)||t.includes(`/`)||t.includes(`\\`))}function qe(e,t,n){if(!Je(n)||!e)return!1;let r=x(e);if(!r||r.allowsExtraPositionals)return!0;let i=r.positionalArgs??[];return i.length===0?!1:t.length<i.length||i.some(e=>e.includes(`?`))}function Je(e){return/^-\d+(\.\d+)?$/.test(e)}function Ye(e){if(e.flags.help)return e;if(e.command===`snapshot`&&e.flags.snapshotDiff){let{snapshotDiff:t,...n}=e.flags;return{command:`diff`,positionals:[`snapshot`,...e.positionals],flags:n,warnings:e.warnings}}return e}function Xe(e,t){let n=x(e.command)?.explicitOnlyFlags;if(n===void 0)return;let r=new Set(e.providedFlags.map(e=>e.key));for(let e of n)r.has(e)||delete t[e]}function Ze(e){let t=x(e.command)?.flagsByAction,n=e.positionals[0];if(t===void 0||n===void 0||!Object.hasOwn(t,n))return[];let r=t[n];if(r===void 0)return[];let i=new Set(Object.values(t).flat());return e.providedFlags.filter(e=>i.has(e.key)&&!r.includes(e.key))}function Qe(e,t,n){return`${e} ${t} does not read ${n.map(e=>e.token).join(`, `)}. Run \`${e} ${t} --help\` for the options it reads.`}function $e(e,t){return e?t.length===1?`Flag ${t[0]} is not supported for command ${e}.`:`Flags ${t.join(`, `)} are not supported for command ${e}.`:t.length===1?`Flag ${t[0]} requires a command that supports it.`:`Flags ${t.join(`, `)} require a command that supports them.`}async function I(){let{buildUsageText:e}=await import(`./cli-help.js`).then(e=>e.n);return e()}async function et(e){let{buildCommandUsageText:t}=await import(`./cli-help.js`).then(e=>e.n);return t(L(e))}function L(e){let t=me(e);if(t)throw new n(`INVALID_ARGS`,t);return pe(e)}function tt(){return{renderedToStderr:!1}}function nt(e){return t=>{t.type===`command`&&(e.renderedToStderr=!0,process.stderr.write(`${t.message}\n`))}}function rt(e){return oe(e)}const it={connect:async()=>(await import(`./connection.js`)).connectCommand,disconnect:async()=>(await import(`./connection.js`)).disconnectCommand,connection:async()=>(await import(`./connection.js`)).connectionCommand,auth:async()=>(await import(`./auth.js`)).authCommand,plugins:async()=>(await import(`./plugins2.js`)).pluginsCommand,daemon:async()=>(await import(`./daemon.js`)).daemonCommand,device:async()=>(await import(`./device3.js`)).deviceCommand,proxy:async()=>(await import(`./proxy.js`)).proxyCommand,takeover:async()=>(await import(`./takeover.js`)).takeoverCommand,replay:async()=>(await import(`./replay.js`)).replayCommand,screenshot:async()=>(await import(`./screenshot3.js`)).screenshotCommand,diff:async()=>(await import(`./screenshot3.js`)).diffCommand,record:async()=>(await import(`./recording.js`)).recordingCommand};async function R(e){let t={...e.flags},n=it[e.command];return n&&await(await n())({...e,flags:t})?!0:rt(e.command)?await at({...e,command:e.command,flags:t}):!1}async function at(e){let{runGenericClientBackedCommand:t}=await import(`./generic.js`);return await t(e)}function ot(e){return[`exec`,`--yes`,`--package`,`agent-react-devtools@0.5.0`,`--`,`agent-react-devtools`,...e]}function st(e){return e===`ios-instance`}function ct(e){return e[0]===`wait`&&e.includes(`--connected`)}function lt(e,t,n){n===0||!ct(e)||!st(t?.leaseBackend)||process.stderr.write([`Hint: Remote iOS React DevTools connects during JavaScript startup.`,"If 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`.",``].join(`
|
|
2
|
-
`)
|
|
3
|
-
`)}function q(e){let t=e.effectiveFlags,n=e.connectionMetadata;return{session:t.session,requestId:e.requestId,stateDir:t.stateDir,daemonBaseUrl:t.daemonBaseUrl,daemonAuthToken:t.daemonAuthToken,daemonTransport:t.daemonTransport,daemonServerMode:t.daemonServerMode,tenant:t.tenant,sessionIsolation:t.sessionIsolation,runId:t.runId,leaseId:t.leaseId,leaseBackend:t.leaseBackend,leaseProvider:n?.leaseProvider,clientId:n?.clientId,deviceKey:n?.deviceKey,providerApp:t.providerApp,providerOsVersion:t.providerOsVersion,providerProject:t.providerProject,providerBuild:t.providerBuild,providerSessionName:t.providerSessionName,providerDeviceOrientation:t.providerDeviceOrientation,providerGeoLocation:t.providerGeoLocation,providerTimezone:t.providerTimezone,providerAppiumVersion:t.providerAppiumVersion,providerLanguage:t.providerLanguage,providerLocale:t.providerLocale,providerNetworkProfile:t.providerNetworkProfile,providerCustomNetwork:t.providerCustomNetwork,providerNoResignApp:t.providerNoResignApp,awsProjectArn:t.awsProjectArn,awsDeviceArn:t.awsDeviceArn,awsAppArn:t.awsAppArn,awsRegion:t.awsRegion,awsInteractionMode:t.awsInteractionMode,runtime:e.resolvedRuntime,lockPolicy:e.binding.lockPolicy,lockPlatform:e.binding.defaultPlatform,cwd:process.cwd(),debug:e.debugOutputEnabled,cost:t.cost,responseLevel:t.responseLevel}}function jt(e){let t=e.effectiveFlags.daemonBaseUrl;return e.debugOutputEnabled&&!e.effectiveFlags.json&&!t?Yt(e.daemonPaths.logPath):null}async function Mt(e){if(e.command!==`test`)return;let{createReplayTestReporterRuntime:t}=await import(`./reporting.js`);return t({debug:e.debugOutputEnabled,verbose:e.effectiveFlags.verbose,json:e.effectiveFlags.json,reporter:e.effectiveFlags.reporter,reportJunit:e.effectiveFlags.reportJunit})}async function Nt(e,t,r,i){let{command:a,positionals:o,effectiveFlags:s}=e;if(a===`batch`){if(!e.parsedBatchSteps)throw new n(`INVALID_ARGS`,`batch requires --steps or --steps-file.`);let c=e.parsedBatchSteps.map((t,n)=>({...t,input:e.binding.lockPolicy&&e.flags.platform===void 0?{...t.input}:V(t.input,{policyOverrides:s,configuredPlatform:s.platform,configuredSession:s.session,inheritedPlatform:s.platform})}));if(await R({command:a,positionals:o,flags:{...s,batchSteps:c},client:t,debug:e.debugOutputEnabled,replayTestReporterRuntime:r,commandProgress:i}))return}else if(a===`runtime`)throw new n(`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 R({command:a,positionals:o,flags:s,client:t,debug:e.debugOutputEnabled,replayTestReporterRuntime:r,commandProgress:i}))return;throw new n(`INVALID_ARGS`,Lt(a))}async function Pt(n,r,i){let a=e(n),o=t(a,{diagnosticId:l().diagnosticId,logPath:u({force:!0})?.path});if(r.command===`close`&&zt(a)){r.effectiveFlags.json&&await W({success:!0,data:{closed:`session`,source:`no-daemon`}});return}r.effectiveFlags.json?await W({success:!1,error:o}):(await U(o,{showDetails:r.debugOutputEnabled}),r.debugOutputEnabled&&Ft(r,o)),i&&i(),await w(1)}const J=64e3;function Ft(e,t){if(!e.effectiveFlags.daemonBaseUrl){Y(`daemon log`,e.daemonPaths.logPath);return}let n=t.diagnosticsRecord;n&&Y(`remote diagnostics`,se(e.daemonPaths.baseDir,n))}function Y(e,t){try{if(T.existsSync(t)){let n=T.readFileSync(t,`utf8`).split(`
|
|
1
|
+
import{F as e,J as t,P as n,nt as r}from"./sdk-contracts.js";import{t as i}from"./capture.js";import{d as a,f as o,s,u as c}from"./sdk-batch-runner.js";import{R as l}from"./registry.js";import{a as u,i as d,l as f,n as p,o as m,r as h}from"./diagnostics.js";import"./diagnostics2.js";import{n as g,r as ee}from"./agent-device-client.js";import{s as te,t as ne,u as re}from"./sdk-batch.js";import{i as ie,r as _,t as v}from"./catalog.js";import{n as y,r as b}from"./back-mode.js";import{n as ae}from"./command-metadata.js";import{t as oe}from"./session-artifact-paths.js";import{a as se}from"./version.js";import{t as x}from"./daemon-resolution.js";import{r as S,t as ce}from"./command-schema.js";import{i as C,r as w,t as le}from"./cli-config.js";import{t as ue}from"./update-check.js";import{n as de,r as fe,t as pe}from"./cli-command-aliases.js";import{exitAfterFlush as T}from"./process-exit.js";import{_ as me,m as he,v as ge}from"./remote-connection-state.js";import{i as _e}from"./auth-session.js";import E from"node:fs";import{pathToFileURL as ve}from"node:url";const D=`open <app> --relaunch`,ye={start:{command:`open`,example:D},restart:{command:`open`,example:D},touch:{command:`press`,example:`press`},input:{command:`fill`,example:`fill`},settext:{command:`fill`,example:`fill`},entertext:{command:`fill`,example:`fill`},screencap:{command:`screenshot`,example:`screenshot`},capture:{command:`screenshot`,example:`screenshot`},dismiss:{command:`keyboard`,example:`keyboard dismiss`},"get-text":{command:`get`,example:`get text`},gettext:{command:`get`,example:`get text`},get_text:{command:`get`,example:`get text`},"open-url":{command:`open`,example:`open <url>`},"close-session":{command:`close`,example:`close`}};function be(e){if(e.length<=2)return[];let t=ie(),n=t.filter(t=>t.startsWith(e));return n.length>0?n.sort(O).slice(0,3):k(e,t)}function O(e,t){return e.length-t.length||e.localeCompare(t)}function k(e,t){let n=t.map(t=>({name:t,distance:Se(e,t)})).filter(t=>t.distance<=xe(e));if(n.length===0)return[];let r=Math.min(...n.map(e=>e.distance));return n.filter(e=>e.distance===r).sort((e,t)=>e.name.localeCompare(t.name)).slice(0,3).map(e=>e.name)}function xe(e){return e.length<4?1:e.length<=6?2:3}function Se(e,t){return e===t?0:e.startsWith(t)||t.startsWith(e)?Math.abs(e.length-t.length):A(e,t)}function A(e,t){let n=e.length+1,r=t.length+1,i=Array.from({length:n},()=>Array(r).fill(0));for(let e=0;e<n;e+=1)i[e][0]=e;for(let e=0;e<r;e+=1)i[0][e]=e;for(let a=1;a<n;a+=1)for(let n=1;n<r;n+=1){let r=e[a-1]===t[n-1]?0:1;i[a][n]=Math.min(i[a-1][n]+1,i[a][n-1]+1,i[a-1][n-1]+r)}return i[n-1][r-1]}function j(e){let t=e.toLowerCase(),n=ye[t]?.example;if(n)return n;let r=be(t);if(r.length!==0)return r.length===1?r[0]:`one of: ${r.join(`, `)}`}const Ce=new Set([`--bundle-id`,`--bundleid`,`--bundle`,`--package`,`--package-name`,`--packagename`,`--app-id`,`--appid`,`--pkg`]),we=new Set([`--session-locked`,`--session-lock-conflicts`]),Te={"--output":`--out`,"--path":`--out`};function Ee(e,t){let n=e.toLowerCase(),r=Te[n];if(r&&De(r,t))return r;let i=Oe(n,t);if(i.length!==0)return i.length===1?i[0]:`one of: ${i.join(`, `)}`}function De(e,t){let n=b().find(t=>t.names.includes(e));return n?C(n.key,t):!1}function Oe(e,t){let n=M(e);if(n.length<=2)return[];let r=ke(t),i=r.filter(e=>M(e).startsWith(n));return i.length>0?i.sort(O).slice(0,3):k(n,r.map(e=>M(e))).map(e=>`--${e}`)}function ke(e){let t=new Set;for(let n of b()){if(!C(n.key,e))continue;let r=n.names[0];r&&t.add(r)}return[...t]}function M(e){return e.replace(/^--?/,``)}function Ae(e,t){let n=e.toLowerCase();if(Ce.has(n))return`Unknown flag: ${e}. The app or bundle id is a positional argument, e.g. ${D}.`;if(we.has(n))return`Unknown flag: ${e}. Use --session-lock reject|strip instead.`;if(n===i.cliToken)return`Unknown flag: ${e}. ${i.migration.screenshot}. ${i.migration.record}.`;let r=Ee(e,t);return r?`Unknown flag: ${e}. Did you mean ${r}?`:`Unknown flag: ${e}`}function N(e){let t={json:!1,help:!1,version:!1},r=null,i=null,a=[],o=[],s=[],c=!0;for(let o=0;o<e.length;o+=1){let l=e[o];if(c&&l===`--`){c=!1;continue}if(!c){r?a.push(l):(i=l,r=R(l));continue}if(Pe(r)){a.push(l);continue}let u=l.startsWith(`--`),d=l.startsWith(`-`)&&l.length>1;if(!u&&!d){r?a.push(l):(i=l,r=R(l));continue}let[f,p]=u?P(l):[l,void 0];if(Me(r,f))continue;let m=Fe(f,r);if(Ne(r,m)){a.push(l);continue}if(!m){if(Be(r,a,l)){r?a.push(l):r=l;continue}throw new n(`INVALID_ARGS`,Ae(f,r))}let h=Re(m,f,p,e[o+1]);h.consumeNext&&(o+=1);let g=t[m.key];if(m.multiple){let e=Array.isArray(g)?[...g,h.value]:g===void 0?[h.value]:[g,h.value];t[m.key]=e}else t[m.key]=h.value;s.push({key:m.key,token:f})}return je(i,t),{command:r,positionals:a,flags:t,warnings:o,providedFlags:s}}function je(e,t){if(e)for(let n of pe(e)?.impliedFlags??[])t[n]=!0}function Me(e,t){return t===`-c`&&(e===`snapshot`||e===`diff`)}function Ne(e,t){return e===`react-devtools`?!t||!C(t.key,e):!1}function Pe(e){return e===`cdp`}function Fe(e,t){let n=b().filter(t=>t.names.includes(e));if(n.length<=1)return n[0]??y(e);if(t){let e=n.find(e=>C(e.key,t));if(e)return e}return y(e)}function Ie(e,t){let r=t?.strictFlags??!0,i=[...e.warnings],a=w({json:!1,help:!1,version:!1},t?.defaultFlags??{});if(w(a,e.flags),e.command&&!_(e.command)&&!a.help){let t=j(e.command),r=t?`Unknown command: ${e.command}. Did you mean ${t}?`:`Unknown command: ${e.command}`;throw new n(`INVALID_ARGS`,r)}let o=e.providedFlags.filter(t=>!C(t.key,e.command));if(o.length>0){let t=o.map(e=>e.token),s=Ke(e.command,t);if(r)throw new n(`INVALID_ARGS`,s);i.push(s);for(let e of o)delete a[e.key]}let s=We(e);if(s.length>0){let t=Ge(e.command,e.positionals[0],s);if(r)throw new n(`INVALID_ARGS`,t);i.push(t);for(let e of s)delete a[e.key]}for(let t of Object.keys(a))a[t]!==void 0&&(C(t,e.command)||delete a[t]);Ue(e,a),Le(e),re(e.command,a);let c=He({command:e.command,positionals:e.positionals,flags:a,warnings:i});if(ce(c.command,c.positionals),c.command===`batch`&&+!!a.steps+ +!!a.stepsFile!=1)throw new n(`INVALID_ARGS`,`batch requires exactly one step source: --steps or --steps-file.`);return c}function Le(e){if(e.command!==`back`)return;let t=e.providedFlags.filter(e=>e.key===`backMode`);if(!(new Set(t.map(e=>e.token)).size<=1))throw new n(`INVALID_ARGS`,`back accepts only one explicit mode flag: use either --in-app or --system.`)}function P(e){let t=e.indexOf(`=`);return t===-1?[e,void 0]:[e.slice(0,t),e.slice(t+1)]}function Re(e,t,r,i){if(e.setValue!==void 0){if(r!==void 0)throw new n(`INVALID_ARGS`,`Flag ${t} does not take a value.`);return{value:e.setValue,consumeNext:!1}}if(e.type===`boolean`){if(r!==void 0)throw new n(`INVALID_ARGS`,`Flag ${t} does not take a value.`);return{value:!0,consumeNext:!1}}if(e.type===`booleanOrString`){if(r!==void 0){if(r.trim().length===0)throw new n(`INVALID_ARGS`,`Flag ${t} requires a non-empty value when provided.`);return{value:r,consumeNext:!1}}return i===void 0||I(i)?{value:!0,consumeNext:!1}:ze(i)?{value:i,consumeNext:!0}:{value:!0,consumeNext:!1}}let a=r??i;if(a===void 0||r===void 0&&I(a))throw new n(`INVALID_ARGS`,`Flag ${t} requires a value.`);if(e.type===`string`)return{value:a,consumeNext:r===void 0};if(e.type===`enum`){if(!e.enumValues?.includes(a))throw new n(`INVALID_ARGS`,`Invalid ${F(t)}: ${a}`);return{value:a,consumeNext:r===void 0}}let o=Number(a);if(!Number.isFinite(o)||typeof e.min==`number`&&o<e.min||typeof e.max==`number`&&o>e.max)throw new n(`INVALID_ARGS`,`Invalid ${F(t)}: ${a}`);return{value:e.type===`int`?Math.floor(o):o,consumeNext:r===void 0}}function F(e){return e.replace(/^-+/,``)}function I(e){if(!e.startsWith(`-`)||e===`-`)return!1;let[t]=e.startsWith(`--`)?P(e):[e,void 0];return y(t)!==void 0}function ze(e){let t=e.trim();return!t||/^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(t)?!1:!!(t.startsWith(`./`)||t.startsWith(`../`)||t.startsWith(`~/`)||t.startsWith(`/`)||t.includes(`/`)||t.includes(`\\`))}function Be(e,t,n){if(!Ve(n)||!e)return!1;let r=S(e);if(!r||r.allowsExtraPositionals)return!0;let i=r.positionalArgs??[];return i.length===0?!1:t.length<i.length||i.some(e=>e.includes(`?`))}function Ve(e){return/^-\d+(\.\d+)?$/.test(e)}function He(e){if(e.flags.help)return e;if(e.command===`snapshot`&&e.flags.snapshotDiff){let{snapshotDiff:t,...n}=e.flags;return{command:`diff`,positionals:[`snapshot`,...e.positionals],flags:n,warnings:e.warnings}}return e}function Ue(e,t){let n=S(e.command)?.explicitOnlyFlags;if(n===void 0)return;let r=new Set(e.providedFlags.map(e=>e.key));for(let e of n)r.has(e)||delete t[e]}function We(e){let t=S(e.command)?.flagsByAction,n=e.positionals[0];if(t===void 0||n===void 0||!Object.hasOwn(t,n))return[];let r=t[n];if(r===void 0)return[];let i=new Set(Object.values(t).flat());return e.providedFlags.filter(e=>i.has(e.key)&&!r.includes(e.key))}function Ge(e,t,n){return`${e} ${t} does not read ${n.map(e=>e.token).join(`, `)}. Run \`${e} ${t} --help\` for the options it reads.`}function Ke(e,t){return e?t.length===1?`Flag ${t[0]} is not supported for command ${e}.`:`Flags ${t.join(`, `)} are not supported for command ${e}.`:t.length===1?`Flag ${t[0]} requires a command that supports it.`:`Flags ${t.join(`, `)} require a command that supports them.`}async function L(){let{buildUsageText:e}=await import(`./cli-help.js`).then(e=>e.n);return e()}async function qe(e){let{buildCommandUsageText:t}=await import(`./cli-help.js`).then(e=>e.n);return t(R(e))}function R(e){let t=fe(e);if(t)throw new n(`INVALID_ARGS`,t);return de(e)}function Je(){return{renderedToStderr:!1}}function Ye(e){return t=>{t.type===`command`&&(e.renderedToStderr=!0,process.stderr.write(`${t.message}\n`))}}function Xe(e){return ae(e)}const Ze={connect:async()=>(await import(`./connection.js`)).connectCommand,disconnect:async()=>(await import(`./connection.js`)).disconnectCommand,connection:async()=>(await import(`./connection.js`)).connectionCommand,auth:async()=>(await import(`./auth.js`)).authCommand,plugins:async()=>(await import(`./plugins2.js`)).pluginsCommand,daemon:async()=>(await import(`./daemon.js`)).daemonCommand,device:async()=>(await import(`./device3.js`)).deviceCommand,proxy:async()=>(await import(`./proxy.js`)).proxyCommand,takeover:async()=>(await import(`./takeover.js`)).takeoverCommand,replay:async()=>(await import(`./replay.js`)).replayCommand,screenshot:async()=>(await import(`./screenshot3.js`)).screenshotCommand,diff:async()=>(await import(`./screenshot3.js`)).diffCommand,record:async()=>(await import(`./recording.js`)).recordingCommand};async function z(e){let t={...e.flags},n=Ze[e.command];return n&&await(await n())({...e,flags:t})?!0:Xe(e.command)?await Qe({...e,command:e.command,flags:t}):!1}async function Qe(e){let{runGenericClientBackedCommand:t}=await import(`./generic.js`);return await t(e)}const B=`${s} Run agent-device help batch for the commands batch accepts and for runnable step examples.`,$e=`${ne} Run agent-device help batch for the commands batch accepts and for runnable step examples.`;function et(e){let t;try{t=JSON.parse(e)}catch{throw new n(`INVALID_ARGS`,`Batch steps must be valid JSON.`)}if(!Array.isArray(t)||t.length===0)throw new n(`INVALID_ARGS`,`Batch steps must be a non-empty JSON array.`);return t.map((e,t)=>tt(e,t+1))}function tt(e,t){let r=o(e,t,B),i=[`positionals`,`flags`].filter(e=>e in r);if(i.length>0){let e=i.map(e=>`"${e}"`).join(`, `);throw new n(`INVALID_ARGS`,`Batch step ${t} uses removed field(s): ${e}. Use {"command":"...","input":{...}}. Example: {"command":"open","input":{"app":"settings","platform":"ios"}}.`,{hint:B})}l(r,[`command`,`input`,`runtime`],`Batch step ${t}`,B);let s=c(r.runtime,t);return{command:te(r.command,t,$e),input:a(r,t,B),...s===void 0?{}:{runtime:s}}}function V(e,t={}){let n=H(t),r={...e};return n.defaultPlatform&&r.platform===void 0&&(r.platform=n.defaultPlatform),r}function H(e){let t=e.env??process.env,n=e.inheritedPlatform??e.configuredPlatform??rt(t.AGENT_DEVICE_PLATFORM),r=at(e.configuredSession??t.AGENT_DEVICE_SESSION);return{defaultPlatform:n,lockPolicy:nt(e.policyOverrides,t,r)}}function nt(e,t,n){let r=e?.sessionLock??it(t.AGENT_DEVICE_SESSION_LOCK);if(r)return r;if(n)return`reject`}function rt(e){if(e===void 0)return;let t=e.trim().toLowerCase();if(t){if(t===`ios`||t===`android`||t===`apple`)return t;throw new n(`INVALID_ARGS`,`Invalid AGENT_DEVICE_PLATFORM: ${e}. Use ios, android, or apple.`)}}function it(e){if(e===void 0)return;let t=e.trim().toLowerCase();if(t){if(t===`reject`||t===`strip`)return t;throw new n(`INVALID_ARGS`,`Invalid session lock mode: ${e}. Use reject or strip.`)}}function at(e){return typeof e==`string`&&e.trim().length>0}function ot(e,t){let n=N(e),r=t?.env??process.env,i=t?.cwd??process.cwd(),a=st(n.command)?me({remoteConfig:n.flags.remoteConfig,cwd:i,env:r}):{},o=w(le({command:n.command,cwd:i,cliFlags:n.flags,env:r}),a);return{...Ie(n,{strictFlags:t?.strictFlags,defaultFlags:o}),providedFlags:n.providedFlags}}function st(e){return e!==null}v.runtime;async function ct(e){let{command:t,request:n,transport:r,transportOptions:i}=e;return await r({...n,command:t},i)}const U=(e,t={})=>import(`./error.js`).then(e=>e.t).then(({printHumanError:n})=>n(e,t)),W=e=>import(`./json.js`).then(({printJson:t})=>t(e)),lt={sendToDaemon:ee},ut=new Set([`launchUrl`,`kind`,`metroBearerToken`,`metroKind`,`metroListenHost`,`metroNoInstallDeps`,`metroNoReuseExisting`,`metroPreparePort`,`metroProbeTimeoutMs`,`metroProjectRoot`,`metroProxyBaseUrl`,`metroPublicBaseUrl`,`metroRuntimeFile`,`metroStartupTimeoutMs`,`metroStatusHost`]),dt=new Set([`connect`,`connection`,`close`,`daemon`,`plugins`,`device`,`disconnect`,`metro`,`proxy`,`session`,`takeover`]);async function G(e,t=lt){let n=p(),r=se(),i=xt(e),a=e.includes(`--json`),o=Nt(e)??process.env.AGENT_DEVICE_SESSION??`default`;await f({session:o,requestId:n,command:e[0],debug:i},async()=>{let{parsed:o,command:s,positionals:c}=await ft(e,{version:r,jsonRequested:a,debugEnabled:i}),l=Z(s,o.providedFlags),u=await pt(o,{command:s,positionals:c,requestId:n,debugOutputEnabled:l});K(u.effectiveFlags);let d=null;try{if(s===`react-devtools`){await T(await mt(u,t));return}if(s===`web`){let{runWebCommand:e}=await import(`./web.js`);await T(await e(c,{flags:u.effectiveFlags,stateDir:u.daemonPaths.baseDir}));return}if(ue({command:s,currentVersion:r,stateDir:u.daemonPaths.baseDir,flags:u.effectiveFlags}),await ht(u,t),K(u.effectiveFlags),s===`cdp`){await T(await ge(c,{flags:u.effectiveFlags,runtime:u.resolvedRuntime,cwd:process.cwd(),env:process.env}));return}d=gt(u);let e=await _t(u),n=Je();await vt(u,g(q(u),{transport:Mt({command:s,flags:u.effectiveFlags,replayTestReporterRuntime:e,commandProgress:n,transport:t.sendToDaemon})}),e,n)}catch(e){await yt(e,u,d)}finally{d&&d()}})}function K(e){e.daemonAuthToken&&m(e.daemonAuthToken)}async function ft(e,r){let i;try{i=ot(e,{cwd:process.cwd(),env:process.env})}catch(e){h({level:`error`,phase:`cli_parse_failed`,data:{error:e instanceof Error?e.message:String(e)}});let n=t(e,{diagnosticId:u().diagnosticId,logPath:d({force:!0})?.path});return r.jsonRequested?await W({success:!1,error:n}):await U(n,{showDetails:r.debugEnabled}),T(1)}for(let e of i.warnings)process.stderr.write(`Warning: ${e}\n`);if(i.flags.version)return process.stdout.write(`${r.version}\n`),T(0);let a=i.command===`help`,o=i.flags.help;if(a||o){if(a&&i.positionals.length>1)return await U(new n(`INVALID_ARGS`,`help accepts at most one command.`)),T(1);let e=a?i.positionals[0]:i.command;if(!e)return process.stdout.write(`${await L()}\n`),T(0);let t=await qe(e);return t?(process.stdout.write(t),T(0)):(await U(new n(`INVALID_ARGS`,St(e))),process.stdout.write(`${await L()}\n`),T(1))}return i.command?{parsed:i,command:i.command,positionals:i.positionals}:(process.stdout.write(`${await L()}\n`),T(1))}async function pt(n,r){let i=new Set(n.providedFlags.map(e=>e.key));try{let e=H({policyOverrides:n.flags,configuredPlatform:n.flags.platform,configuredSession:n.flags.session}),t=e.lockPolicy?{...n.flags}:V(n.flags,{policyOverrides:n.flags,configuredPlatform:n.flags.platform,configuredSession:n.flags.session}),a=x(t.stateDir),o=t.session??`default`,s=Tt({command:r.command,explicitFlagKeys:i,stateDir:a.baseDir,session:o,remoteConfig:t.remoteConfig,hasResolvedSession:t.session!==void 0}),c=s?At(t,s.flags,i):t;return{...r,binding:e,flags:t,daemonPaths:a,sessionName:o,connectionDefaults:s,explicitFlagKeys:i,effectiveFlags:c,resolvedRuntime:s?.runtime,connectionMetadata:s?.connection,parsedBatchSteps:void 0}}catch(i){let a=e(i),o=t(a,{diagnosticId:u().diagnosticId,logPath:d({force:!0})?.path});return n.flags.json?await W({success:!1,error:o}):await U(o,{showDetails:r.debugOutputEnabled}),T(1)}}async function mt(e,t){let{runReactDevtoolsCommand:n}=await import(`./react-devtools.js`),{daemonAuthToken:i,...a}=e.effectiveFlags;return await n(e.positionals,{flags:{...a,leaseProvider:e.connectionDefaults?.connection?.leaseProvider},stateDir:e.daemonPaths.baseDir,session:e.effectiveFlags.session??e.sessionName,cwd:process.cwd(),env:process.env,configureDirectPortReverse:async()=>{let n=await ct({route:`react-devtools`,command:v.runtime,request:{positionals:[`port-reverse`],flags:{...a,leaseProvider:e.connectionDefaults?.connection?.leaseProvider,devicePort:8097,hostPort:8097,portReverseName:`react-devtools`},session:e.effectiveFlags.session??e.sessionName},transport:t.sendToDaemon,transportOptions:{authToken:i}});n.ok||r(n.error)}})}async function ht(e,t){if(e.command===`batch`){if(e.positionals.length>0)throw new n(`INVALID_ARGS`,`batch does not accept positional arguments.`);e.parsedBatchSteps=Ct(e.flags)}if(Dt(e.command)&&(e.effectiveFlags=(await _e({command:e.command,flags:e.effectiveFlags,stateDir:e.daemonPaths.baseDir,env:process.env})).flags),e.effectiveFlags.remoteConfig&&Et(e.command)){let n=g(q(e),{transport:Q(t.sendToDaemon)}),{materializeRemoteConnectionForCommand:r}=await import(`./connection-runtime.js`),i=await r({command:e.command,flags:e.effectiveFlags,client:n,runtime:e.resolvedRuntime,positionals:e.positionals,batchSteps:e.parsedBatchSteps,forceRuntimePrepare:jt(e.explicitFlagKeys)});e.effectiveFlags=i.flags,e.resolvedRuntime=i.runtime,e.connectionMetadata=i.connection}Ot({command:e.command,flags:e.effectiveFlags,runtime:e.resolvedRuntime,explicitFlagKeys:e.explicitFlagKeys,hadConnectionDefaults:!!e.connectionDefaults})&&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.
|
|
2
|
+
`)}function q(e){let t=e.effectiveFlags,n=e.connectionMetadata;return{session:t.session,requestId:e.requestId,stateDir:t.stateDir,daemonBaseUrl:t.daemonBaseUrl,daemonAuthToken:t.daemonAuthToken,daemonTransport:t.daemonTransport,daemonServerMode:t.daemonServerMode,tenant:t.tenant,sessionIsolation:t.sessionIsolation,runId:t.runId,leaseId:t.leaseId,leaseBackend:t.leaseBackend,leaseProvider:n?.leaseProvider,clientId:n?.clientId,deviceKey:n?.deviceKey,providerApp:t.providerApp,providerOsVersion:t.providerOsVersion,providerDeviceType:t.providerDeviceType,providerProject:t.providerProject,providerBuild:t.providerBuild,providerSessionName:t.providerSessionName,providerDeviceOrientation:t.providerDeviceOrientation,providerGeoLocation:t.providerGeoLocation,providerTimezone:t.providerTimezone,providerAppiumVersion:t.providerAppiumVersion,providerLanguage:t.providerLanguage,providerLocale:t.providerLocale,providerNetworkProfile:t.providerNetworkProfile,providerCustomNetwork:t.providerCustomNetwork,providerNoResignApp:t.providerNoResignApp,awsProjectArn:t.awsProjectArn,awsDeviceArn:t.awsDeviceArn,awsAppArn:t.awsAppArn,awsRegion:t.awsRegion,awsInteractionMode:t.awsInteractionMode,runtime:e.resolvedRuntime,lockPolicy:e.binding.lockPolicy,lockPlatform:e.binding.defaultPlatform,cwd:process.cwd(),debug:e.debugOutputEnabled,cost:t.cost,responseLevel:t.responseLevel}}function gt(e){let t=e.effectiveFlags.daemonBaseUrl;return e.debugOutputEnabled&&!e.effectiveFlags.json&&!t?Pt(e.daemonPaths.logPath):null}async function _t(e){if(e.command!==`test`)return;let{createReplayTestReporterRuntime:t}=await import(`./reporting.js`);return t({debug:e.debugOutputEnabled,verbose:e.effectiveFlags.verbose,json:e.effectiveFlags.json,reporter:e.effectiveFlags.reporter,reportJunit:e.effectiveFlags.reportJunit})}async function vt(e,t,r,i){let{command:a,positionals:o,effectiveFlags:s}=e;if(a===`batch`){if(!e.parsedBatchSteps)throw new n(`INVALID_ARGS`,`batch requires --steps or --steps-file.`);let c=e.parsedBatchSteps.map((t,n)=>({...t,input:e.binding.lockPolicy&&e.flags.platform===void 0?{...t.input}:V(t.input,{policyOverrides:s,configuredPlatform:s.platform,configuredSession:s.session,inheritedPlatform:s.platform})}));if(await z({command:a,positionals:o,flags:{...s,batchSteps:c},client:t,debug:e.debugOutputEnabled,replayTestReporterRuntime:r,commandProgress:i}))return}else if(a===`runtime`)throw new n(`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 z({command:a,positionals:o,flags:s,client:t,debug:e.debugOutputEnabled,replayTestReporterRuntime:r,commandProgress:i}))return;throw new n(`INVALID_ARGS`,X(a))}async function yt(n,r,i){let a=e(n),o=t(a,{diagnosticId:u().diagnosticId,logPath:d({force:!0})?.path});if(r.command===`close`&&wt(a)){r.effectiveFlags.json&&await W({success:!0,data:{closed:`session`,source:`no-daemon`}});return}r.effectiveFlags.json?await W({success:!1,error:o}):(await U(o,{showDetails:r.debugOutputEnabled}),r.debugOutputEnabled&&bt(r,o)),i&&i(),await T(1)}const J=64e3;function bt(e,t){if(!e.effectiveFlags.daemonBaseUrl){Y(`daemon log`,e.daemonPaths.logPath);return}let n=t.diagnosticsRecord;n&&Y(`remote diagnostics`,oe(e.daemonPaths.baseDir,n))}function Y(e,t){try{if(E.existsSync(t)){let n=E.readFileSync(t,`utf8`).split(`
|
|
4
3
|
`),r=n.slice(Math.max(0,n.length-200)).join(`
|
|
5
|
-
`);r.length>J&&(r=r.slice(r.length-J)),r.trim().length>0&&process.stderr.write(`\n[${e}]\n${r}\n`)}}catch{}}function
|
|
4
|
+
`);r.length>J&&(r=r.slice(r.length-J)),r.trim().length>0&&process.stderr.write(`\n[${e}]\n${r}\n`)}}catch{}}function xt(e){try{let t=N(e);return Z(t.command??``,t.providedFlags)}catch{return e.includes(`--debug`)||e.includes(`-v`)||e.includes(`--verbose`)}}function St(e){let t=j(e);return t?`Unknown command: ${e}. Did you mean ${t}?`:`Unknown command: ${e}`}function X(e){return _(e)?(h({level:`error`,phase:`cli_known_command_unhandled`,data:{command:e}}),`Command is registered but no CLI handler accepted it: ${e}`):`Unknown command: ${e}`}function Z(e,t){return t.some(t=>t.key===`verbose`&&(t.token===`--debug`||t.token===`-v`||e!==`test`))}function Ct(e){let t=``;if(e.steps)t=e.steps;else if(e.stepsFile)try{t=E.readFileSync(e.stepsFile,`utf8`)}catch(t){let r=t instanceof Error?t.message:String(t);throw new n(`INVALID_ARGS`,`Failed to read --steps-file ${e.stepsFile}: ${r}`)}return et(t)}function wt(e){return e.code===`COMMAND_FAILED`?e.details?.kind===`daemon_startup_failed`?!0:e.message.toLowerCase().includes(`failed to start daemon`)?typeof e.details?.infoPath==`string`||typeof e.details?.lockPath==`string`:!1:!1}function Tt(e){return e.command===`connect`||e.command===`connection`||e.command===`daemon`||e.command===`plugins`||e.command===`proxy`?null:he({stateDir:e.stateDir,session:e.session,remoteConfig:e.remoteConfig,cwd:process.cwd(),env:process.env,allowActiveFallback:!e.explicitFlagKeys.has(`session`)&&(!e.remoteConfig||e.command===`disconnect`||!e.hasResolvedSession),validateRemoteConfigHash:e.command!==`disconnect`})}function Et(e){return!dt.has(e)}function Dt(e){return e!==`auth`&&e!==`connection`&&e!==`daemon`&&e!==`plugins`&&e!==`device`&&e!==`proxy`}function Ot(e){return e.command!==`open`||e.runtime||e.flags.bundleUrl||e.flags.metroHost||e.flags.metroPort||e.flags.remoteConfig||e.hadConnectionDefaults?!1:kt(e.explicitFlagKeys)}function kt(e){return e.has(`daemonBaseUrl`)||e.has(`daemonTransport`)||e.has(`tenant`)||e.has(`sessionIsolation`)||e.has(`runId`)||e.has(`leaseId`)||e.has(`leaseBackend`)}function At(e,t,n){let r={...e};for(let[e,i]of Object.entries(t))i!==void 0&&(n.has(e)||(r[e]=i));return r}function jt(e){for(let t of ut)if(e.has(t))return!0;return!1}function Mt(e){let{command:t,flags:n,replayTestReporterRuntime:r,transport:i}=e;if(n.json)return Q(i);let a=t===`test`&&r?r.onProgress:Ye(e.commandProgress);return async(e,n)=>{let r={...n,onProgress:a};return await $(i,{...e,meta:{...e.meta,requestProgress:t===`test`?`replay-test`:`command`}},r)}}function Q(e){return async(t,n)=>await $(e,t,n)}async function $(e,t,n){return await e(t,n)}function Nt(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(n===`--session`){let n=e[t+1]?.trim();return n&&!n.startsWith(`-`)?n:null}}return null}ve(process.argv[1]??``).href===import.meta.url&&G(process.argv.slice(2)).catch(async n=>{let r=e(n);await U(t(r),{showDetails:!0}),await T(1)});function Pt(e){try{let t=E.existsSync(e)?E.statSync(e).size:0,n=!1,r=setInterval(()=>{if(!n&&E.existsSync(e))try{let n=E.statSync(e);if(n.size<t&&(t=0),n.size<=t)return;let r=E.openSync(e,`r`);try{let e=Buffer.alloc(n.size-t);E.readSync(r,e,0,e.length,t),t=n.size,e.length>0&&process.stdout.write(e.toString(`utf8`))}finally{E.closeSync(r)}}catch{}},200);return()=>{n=!0,clearInterval(r)}}catch{return null}}export{G as runCli};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{O as e,S as t,m as n,w as r}from"./owner-identity.js";import{d as i}from"./exec.js";import"./command.js";import"./process.js";import{a,c as o,d as s,f as c,i as l,l as u,m as d,o as f,p,r as m,s as h,t as g,u as _}from"./base-url.js";import{createHash as v}from"node:crypto";import y from"node:fs";import b from"node:path";import{fileURLToPath as x}from"node:url";const S=`companion-tunnel`;function C(e){return v(`sha256`).update(e).digest(`hex`)}function w(e){return typeof e==`string`&&e.trim()?e.trim():void 0}function T(e){if(!e||typeof e!=`object`||Array.isArray(e))return;let t=e;if(typeof t.tenantId==`string`&&typeof t.runId==`string`&&typeof t.leaseId==`string`)return{tenantId:t.tenantId,runId:t.runId,leaseId:t.leaseId}}function E(e,t){return e.tenantId===t.tenantId&&e.runId===t.runId&&e.leaseId===t.leaseId}function D(e,t,n,r){let i=r??b.join(e,`.agent-device`);if(!n)return{statePath:b.join(i,`${t.slug}.json`),logPath:b.join(i,`${t.slug}.log`)};let a=C(n).slice(0,12),o=b.join(i,t.slug);return{statePath:b.join(o,`${t.slug}-${a}.json`),logPath:b.join(o,`${t.slug}-${a}.log`)}}function O(e){try{let t=JSON.parse(y.readFileSync(e,`utf8`));if(!Number.isInteger(t.pid)||Number(t.pid)<=0||typeof t.serverBaseUrl!=`string`||typeof t.localBaseUrl!=`string`||typeof t.tokenHash!=`string`||t.tokenHash.length===0)return null;let n=Array.isArray(t.consumers)?t.consumers.filter(e=>typeof e==`string`&&e.length>0):[];return{pid:Number(t.pid),startTime:typeof t.startTime==`string`?t.startTime:void 0,command:typeof t.command==`string`?t.command:void 0,serverBaseUrl:t.serverBaseUrl,localBaseUrl:t.localBaseUrl,launchUrl:w(t.launchUrl),registerPath:w(t.registerPath),unregisterPath:w(t.unregisterPath),devicePort:Number.isInteger(t.devicePort)?Number(t.devicePort):void 0,session:w(t.session),bridgeScope:T(t.bridgeScope),tokenHash:t.tokenHash,consumers:n}}catch{return null}}function k(e,t){y.mkdirSync(b.dirname(e),{recursive:!0}),y.writeFileSync(e,`${JSON.stringify(t,null,2)}\n`,`utf8`)}function A(e){y.mkdirSync(b.dirname(e),{recursive:!0}),y.closeSync(y.openSync(e,`a`))}function j(e){try{y.unlinkSync(e)}catch{}}function M(e){try{y.readdirSync(e).length===0&&y.rmdirSync(e)}catch{}}function N(e,t){let n=b.dirname(e.statePath),r=b.dirname(e.logPath);j(e.statePath),j(e.logPath),M(n),r!==n&&M(r),b.basename(n)===t.slug&&M(b.dirname(n))}function P(e,t){return e.includes(t.runArg)}function F(e,i){if(!n(e.pid))return!1;if(e.startTime){let t=r(e.pid);if(!t||t!==e.startTime)return!1}let a=t(e.pid);return!a||!P(a,i.definition)||!e.bridgeScope?!1:e.serverBaseUrl===g(i.serverBaseUrl)&&e.localBaseUrl===g(i.localBaseUrl)&&e.launchUrl===w(i.launchUrl)&&e.registerPath===w(i.registerPath)&&e.unregisterPath===w(i.unregisterPath)&&e.devicePort===i.devicePort&&e.session===w(i.session)&&E(e.bridgeScope,i.bridgeScope)&&e.tokenHash===C(i.bearerToken)}function I(e){return w(e.consumerKey)??w(e.profileKey)??null}function L(e,t){return!t||e.consumers.includes(t)?e:{...e,consumers:[...e.consumers,t]}}function R(e,t){return t?{...e,consumers:e.consumers.filter(e=>e!==t)}:{...e,consumers:[]}}async function z(r,i){if(!n(r.pid))return;let a=t(r.pid);if(!(!a||!P(a,i))){try{process.kill(r.pid,`SIGTERM`)}catch(e){let t=e.code;if(t===`ESRCH`||t===`EPERM`)return;throw e}if(!await e(r.pid,1e3)){try{process.kill(r.pid,`SIGKILL`)}catch(e){let t=e.code;if(t===`ESRCH`||t===`EPERM`)return;throw e}await e(r.pid,1e3)}}}function B(e,t,n){n===void 0?delete e[t]:e[t]=n}function V(e,t){let n={...t};return n[s]=g(e.serverBaseUrl),n[m]=e.bearerToken,n[f]=g(e.localBaseUrl),n[p]=D(e.projectRoot,e.definition,e.profileKey,e.stateDir).statePath,n[_]=e.bridgeScope.tenantId,n[u]=e.bridgeScope.runId,n[o]=e.bridgeScope.leaseId,B(n,a,w(e.launchUrl)),B(n,h,w(e.registerPath)),B(n,d,w(e.unregisterPath)),B(n,l,e.devicePort===void 0?void 0:String(e.devicePort)),B(n,c,w(e.session)),n}function H(e){let t=x(import.meta.url),n=b.extname(t)||`.js`,r=[b.join(b.dirname(t),`${S}${n}`),b.join(b.dirname(t),`internal`,`${S}${n}`)].find(e=>y.existsSync(e));if(!r)throw Error(`${e.displayName} entrypoint not found. Rebuild the package to include the companion worker entry.`);return r}function U(e,n){let a=H(e.definition),o=a.endsWith(`.ts`)?[`--experimental-strip-types`]:[];y.mkdirSync(b.dirname(n),{recursive:!0});let s=y.openSync(n,`a`),c=0;try{c=i(process.execPath,[...o,a,e.definition.runArg],{env:V(e,e.env??process.env),stdio:[`ignore`,s,s]})}finally{y.closeSync(s)}if(!Number.isInteger(c)||c<=0)throw Error(`Failed to start ${e.definition.displayName} process.`);return{pid:c,startTime:r(c)??void 0,command:t(c)??void 0,serverBaseUrl:g(e.serverBaseUrl),localBaseUrl:g(e.localBaseUrl),launchUrl:w(e.launchUrl),registerPath:w(e.registerPath),unregisterPath:w(e.unregisterPath),devicePort:e.devicePort,session:w(e.session),bridgeScope:e.bridgeScope,tokenHash:C(e.bearerToken),consumers:[]}}async function W(e){let t=I(e),n=D(e.projectRoot,e.definition,e.profileKey,e.stateDir),r=O(n.statePath);if(r&&F(r,e)){let e=L(r,t);return e!==r&&k(n.statePath,e),{pid:r.pid,spawned:!1,statePath:n.statePath,logPath:n.logPath}}r&&(await z(r,e.definition),N(n,e.definition)),A(n.statePath);let i;try{i=U(e,n.logPath),k(n.statePath,L(i,t))}catch(t){throw i&&await z(i,e.definition).catch(()=>{}),N(n,e.definition),t}return{pid:i.pid,spawned:!0,statePath:n.statePath,logPath:n.logPath}}async function G(e){let t=I(e),n=D(e.projectRoot,e.definition,e.profileKey,e.stateDir),r=O(n.statePath);if(!r)return N(n,e.definition),{stopped:!1,statePath:n.statePath};let i=R(r,t);return i.consumers.length>0?(k(n.statePath,i),{stopped:!1,statePath:n.statePath}):(await z(r,e.definition),N(n,e.definition),{stopped:!0,statePath:n.statePath})}export{G as n,W as t};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{h as e}from"./base-url.js";import{n as t,t as n}from"./client-companion-tunnel.js";const r={slug:`metro-companion`,runArg:e,displayName:`Metro companion`};async function i(e){return await n({...e,definition:r,registerPath:e.registerPath??`/api/metro/companion/register`})}async function a(e){return await t({...e,definition:r})}export{a as n,i as t};
|
package/dist/src/client-metro.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{F as e,P as t}from"./sdk-contracts.js";import{D as n}from"./owner-identity.js";import{n as r}from"./path-resolution.js";import{d as i,m as a}from"./exec.js";import{t as o}from"./timeouts.js";import"./file.js";import"./command.js";import"./process.js";import"./retry.js";import{t as s}from"./base-url.js";import{t as c}from"./client-metro-companion.js";import{n as l,r as u}from"./project-runtime.js";import{t as d}from"./runtime-transport-hints.js";import f from"node:fs";import p from"node:path";function m(e,t,n=`index.bundle`){let r=new URL(`${s(e)}/${n}`);return r.searchParams.set(`platform`,t),r.searchParams.set(`dev`,`true`),r.searchParams.set(`minify`,`false`),r.toString()}const h=8081,g=`.expo/.virtual-metro-entry.bundle`;function _(e,n){if(e==null||e===``)return n;let r=Number.parseInt(String(e),10);if(!Number.isInteger(r)||r<1||r>65535)throw new t(`INVALID_ARGS`,`Invalid Metro port: ${String(e)}. Use 1-65535.`);return r}function v(e){let n=S(e.bundleUrl),r=n??e.runtime?.bundleUrl,i=!!n,a=!!S(r),o=d({metroHost:y(e,i,a),metroPort:b(e,i,a),bundleUrl:r});if(!o)throw new t(`INVALID_ARGS`,`Unable to resolve Metro host and port for reload.`);let s=ee(r);return{reloadUrl:x(o,o.scheme,`${s}/reload`),messageSocketUrl:x(o,o.scheme===`https`?`wss`:`ws`,`${s}/message`)}}function y(e,t,n){return S(e.metroHost)??(t?void 0:S(e.runtime?.metroHost))??(n?void 0:`localhost`)}function b(e,t,n){if(e.metroPort!==void 0)return _(e.metroPort,h);if(!t)return e.runtime?.metroPort??(n?void 0:h)}function ee(e){let t=S(e);if(!t)return``;let n;try{n=new URL(t)}catch{return``}let r=n.pathname.replace(/\/+$/,``),i=`/${g}`;if(r.endsWith(i))return r.slice(0,-i.length);let a=r.lastIndexOf(`/`);return(a>=0?r.slice(a+1):r).endsWith(`.bundle`)&&a>0?r.slice(0,a):``}function x(e,t,n){let r=new URL(`${t}://localhost`);return r.hostname=e.host,r.port=String(e.port),r.pathname=n,r.toString()}function S(e){return typeof e==`string`&&e.trim()?e.trim():void 0}function C(e){return typeof e==`string`&&e.trim()?s(e.trim()):``}function w(e){return typeof e==`string`&&e.trim()?e.trim():void 0}function T(e,t,n){return r(e,{env:t,cwd:n})}function E(e){try{return f.accessSync(e,f.constants.F_OK),!0}catch{return!1}}function D(e){try{return f.statSync(e).isDirectory()}catch{return!1}}function O(e){let n=p.join(e,`package.json`),r=u(e);if(!r)throw new t(`INVALID_ARGS`,`package.json not found at ${n}`);return r}const k=[{file:`pnpm-lock.yaml`,command:`pnpm`},{file:`yarn.lock`,command:`yarn`},{file:`bun.lock`,command:`bun`},{file:`bun.lockb`,command:`bun`},{file:`package-lock.json`,command:`npm`}];function te(e){let t=e;for(;;){for(let{file:e,command:n}of k)if(E(p.join(t,e)))return{command:n,installArgs:[`install`]};if(E(p.join(t,`.git`)))return null;let e=p.dirname(t);if(e===t)return null;t=e}}function A(e){return te(e)??{command:`npm`,installArgs:[`install`]}}function j(e,t){if(t!==`auto`)return t;let n=l(e);return n===`expo`||n===`repack`?n:`react-native`}function M(e,t){return typeof{...e.dependencies??{},...e.devDependencies??{}}[t]==`string`}function N(e,t){return[`js`,`mjs`,`cjs`,`ts`,`mts`,`cts`].some(n=>E(p.join(e,`${t}.config.${n}`)))}function P(e,t){return N(e,`rspack`)?`rspack`:N(e,`webpack`)?`webpack`:M(t,`@rspack/core`)?`rspack`:M(t,`webpack`)?`webpack`:`rspack`}function F(e,t,n){if(e==null||e===``)return t;let r=Number.parseInt(String(e),10);return Number.isInteger(r)?Math.max(r,n):t}function ne(e){return e===`expo`?g:`index.bundle`}function I(e,t,n){return{platform:t,bundleUrl:m(e,t,ne(n))}}function L(e,t){return{platform:t,metroHost:w(e?.metro_host),metroPort:e?.metro_port,bundleUrl:w(e?.metro_bundle_url),launchUrl:w(e?.launch_url)}}function R(e,t){if(D(p.join(e,`node_modules`)))return{installed:!1};let n=A(e);try{a(n.command,n.installArgs,{cwd:e,env:t})}catch(e){throw z(e,n)}return{installed:!0,packageManager:n.command}}function z(n,r){let i=e(n),a=`Dependency install failed using detected package manager "${r.command}". If dependencies are already installed (for example via a monorepo root install), pass --no-install-deps to skip this step, or install manually with "${r.command} ${r.installArgs.join(` `)}" from the project root.`;return new t(i.code,i.message,{...i.details??{},hint:a,packageManager:r.command},i)}async function B(e){await o(e)}async function V(e,n,r={}){try{let t=await fetch(e,{headers:r,signal:AbortSignal.timeout(n)});return{ok:t.ok,status:t.status,body:await t.text()}}catch(r){throw r instanceof Error&&r.name===`TimeoutError`?new t(`COMMAND_FAILED`,`Timed out fetching ${e} after ${n}ms`):r}}async function H(e,t){try{let n=await V(e,t);return n.ok&&n.body.includes(`packager-status:running`)}catch{return!1}}function U(e,t,n,r){return e===`expo`?{command:`npx`,installArgs:[`expo`,`start`,`--host`,`lan`,`--port`,String(n)]}:e===`repack`?{command:`npx`,installArgs:[`react-native`,t===`webpack`?`webpack-start`:`rspack-start`,`--host`,r,`--port`,String(n)]}:{command:`npx`,installArgs:[`react-native`,`start`,`--host`,r,`--port`,String(n)]}}function W(e,n,r,a,o,s,c){let l=U(n,r,a,o);f.mkdirSync(p.dirname(s),{recursive:!0});let u=f.openSync(s,`a`),d=0;try{d=i(l.command,l.installArgs,{cwd:e,env:c,stdio:[`ignore`,u,u]})}finally{f.closeSync(u)}if(!Number.isInteger(d)||d<=0)throw new t(`COMMAND_FAILED`,`Failed to start React Native dev server. Expected a detached child PID.`);return{pid:d}}async function G(e){if(!(!Number.isInteger(e)||e<=0)){try{process.kill(e,`SIGTERM`)}catch(e){let t=e.code;if(t===`ESRCH`||t===`EPERM`)return;throw e}if(!await n(e,1e3)){try{process.kill(e,`SIGKILL`)}catch(e){let t=e.code;if(t===`ESRCH`||t===`EPERM`)return;throw e}await n(e,1e3)}}}function K(e,t){return{Authorization:`Bearer ${t}`,"Content-Type":`application/json`,...e.includes(`ngrok`)?{"ngrok-skip-browser-warning":`1`}:{}}}function q(e,n){let r=new t(`COMMAND_FAILED`,e);return r.retryable=n,r}function J(e,t){return!!(e>=500||e===408||e===425||e===429||JSON.stringify(t).includes(`Metro companion is not connected`))}function Y(e){return!!(e&&typeof e==`object`&&`retryable`in e&&e.retryable===!0)}async function X(e){let t;try{t=await fetch(`${e.baseUrl}/api/metro/bridge`,{method:`POST`,headers:K(e.baseUrl,e.bearerToken),body:JSON.stringify({...e.scope,...e.runtime?{ios_runtime:e.runtime}:{},timeout_ms:e.timeoutMs}),signal:AbortSignal.timeout(e.timeoutMs)})}catch(t){throw t instanceof Error&&t.name===`TimeoutError`?q(`/api/metro/bridge timed out after ${e.timeoutMs}ms calling ${e.baseUrl}/api/metro/bridge`,!0):q(t instanceof Error?t.message:String(t),!0)}let n=Z(await t.text(),t.status,e.baseUrl);if(!t.ok)throw q(`/api/metro/bridge failed (${t.status}): ${JSON.stringify(n)}`,J(t.status,n));return ie(n)}function Z(e,t,n){if(!e)return{};try{let t=JSON.parse(e);if(!t||typeof t!=`object`||Array.isArray(t))throw Error(`Expected a JSON object`);return t}catch(r){let i=e.slice(0,200);throw q(`/api/metro/bridge returned invalid JSON (${t}) from ${n}: ${r instanceof Error?r.message:String(r)}. body=${JSON.stringify(i)}`,J(t,e))}}function re(e){return{enabled:e.enabled,baseUrl:e.base_url,statusUrl:e.status_url??``,bundleUrl:e.bundle_url??``,iosRuntime:L(e.ios_runtime,`ios`),androidRuntime:L(e.android_runtime,`android`),upstream:{bundleUrl:e.upstream.bundle_url??``,host:e.upstream.host??``,port:e.upstream.port??0,statusUrl:e.upstream.status_url??``},probe:{reachable:e.probe.reachable,statusCode:e.probe.status_code,latencyMs:e.probe.latency_ms,detail:e.probe.detail}}}function ie(e){let t=e.data??e;if(!t||typeof t!=`object`||Array.isArray(t))throw q(`/api/metro/bridge returned malformed descriptor: Expected a JSON object.`,!1);try{return re(t)}catch(e){throw q(`/api/metro/bridge returned malformed descriptor: ${e instanceof Error?e.message:String(e)}`,!1)}}function Q(e,t,n,r,i){let a=[`Metro bridge is required for this run but could not be configured via ${e}/api/metro/bridge.`];return t&&a.push(`bridgeError=${t}`),n?.probe.reachable===!1&&a.push(`bridgeProbe=${n.probe.detail||`unreachable (status ${n.probe.statusCode||0})`}`),r&&r!==t&&a.push(`initialBridgeError=${r}`),i&&a.push(`metroCompanionLog=${i}`),a.join(` `)}function ae(e,n){if(!n?.iosRuntime.bundleUrl)throw new t(`COMMAND_FAILED`,Q(e,`bridge descriptor is missing ios_runtime.metro_bundle_url`,n))}function oe(e,n,r){let i=n||w(r.AGENT_DEVICE_METRO_BEARER_TOKEN)||``,a=i||e&&w(r.AGENT_DEVICE_DAEMON_AUTH_TOKEN)||``;if(e&&!a)throw new t(`INVALID_ARGS`,`metro prepare requires proxy auth when --proxy-base-url is provided. Pass --bearer-token or set AGENT_DEVICE_METRO_BEARER_TOKEN or AGENT_DEVICE_DAEMON_AUTH_TOKEN.`);if(!e&&i)throw new t(`INVALID_ARGS`,`metro prepare requires --proxy-base-url when proxy auth is provided.`);return{proxyEnabled:!!(e&&a),proxyBaseUrl:e,proxyBearerToken:a}}function se(e){if(!e?.tenantId||!e.runId||!e.leaseId)throw new t(`INVALID_ARGS`,`metro prepare with proxy requires tenantId, runId, and leaseId bridge scope.`);return e}function ce(e,n){if(!(e||n))throw new t(`INVALID_ARGS`,`metro prepare requires --public-base-url <url> or --proxy-base-url <url>.`)}function le(e,t,n){return e.runtimeFilePath?T(e.runtimeFilePath,t,n):null}function ue(e,t,n,r){return T(e.logPath??p.join(r,`.agent-device`,`metro.log`),t,n)}function $(e){let t=e.env??process.env,n=process.cwd(),r=T(e.projectRoot??n,t,n),i=e.kind??`auto`,a=null,o;i===`auto`?(a=O(r),o=j(a,i)):o=i;let s=null;o===`repack`&&(a??=O(r),s=P(r,a));let c=C(e.publicBaseUrl),l=C(e.proxyBaseUrl);ce(c,l);let{proxyEnabled:u,proxyBaseUrl:d,proxyBearerToken:f}=oe(l,w(e.proxyBearerToken)??``,t);return{env:t,projectRoot:r,kind:o,repackBundler:s,metroPort:_(e.metroPort??8081,8081),listenHost:w(e.listenHost)??`0.0.0.0`,statusHost:w(e.statusHost)??`127.0.0.1`,publicBaseUrl:c,proxyBaseUrl:d,proxyBearerToken:f,bridgeScope:u?se(e.bridgeScope):null,startupTimeoutMs:F(e.startupTimeoutMs,18e4,3e4),probeTimeoutMs:F(e.probeTimeoutMs,1e4,1e3),reuseExisting:e.reuseExisting??!0,installProjectDeps:e.installDependenciesIfNeeded??!0,runtimeFilePath:le(e,t,n),logPath:ue(e,t,n,r)}}async function de(e,t,n){let r=Date.now()+t;for(;Date.now()<r;){let t=r-Date.now();if(await H(e,Math.min(n,Math.max(t,1))))return!0;let i=Math.min(500,Math.max(r-Date.now(),0));i>0&&await B(i)}return!1}async function fe(e){let n=Date.now()+e.startupTimeoutMs,r=null,i=null;for(;Date.now()<n;){try{let t=await X({baseUrl:e.baseUrl,bearerToken:e.bearerToken,scope:e.scope,runtime:e.runtime,timeoutMs:e.probeTimeoutMs});if(t.probe.reachable!==!1)return t;r=t,i=null}catch(n){if(i=n instanceof Error?n.message:String(n),!Y(n))throw new t(`COMMAND_FAILED`,Q(e.baseUrl,i,r,e.initialBridgeError,e.companionLogPath),void 0,n)}let a=Math.min(1e3,Math.max(n-Date.now(),0));a>0&&await B(a)}throw new t(`COMMAND_FAILED`,Q(e.baseUrl,i,r,e.initialBridgeError,e.companionLogPath))}async function pe(e){let n=`http://${e.statusHost}:${e.metroPort}/status`;if(e.reuseExisting&&await H(n,e.probeTimeoutMs))return{started:!1,reused:!0,pid:0,statusUrl:n};let r=W(e.projectRoot,e.kind,e.repackBundler,e.metroPort,e.listenHost,e.logPath,e.env);if(await de(n,e.startupTimeoutMs,e.probeTimeoutMs))return{started:!0,reused:!1,pid:r.pid,statusUrl:n};throw await G(r.pid).catch(()=>{}),new t(`COMMAND_FAILED`,`React Native dev server did not become ready at ${n} within ${e.startupTimeoutMs}ms. Check ${e.logPath}.`,{logPath:e.logPath})}async function me(e,t){let n=t.bridgeScope;if(!n)return null;let r=null,i=null;try{r=await X({baseUrl:t.proxyBaseUrl,bearerToken:t.proxyBearerToken,scope:n,timeoutMs:t.probeTimeoutMs})}catch(e){if(!Y(e))throw e;i=e instanceof Error?e.message:String(e)}return(!r||r.probe.reachable===!1)&&(r=await he(e,t,n,r,i)),ae(t.proxyBaseUrl,r),r}async function he(e,n,r,i,a){let o;try{o=(await c({projectRoot:n.projectRoot,serverBaseUrl:n.proxyBaseUrl,bearerToken:n.proxyBearerToken,bridgeScope:r,localBaseUrl:`http://${n.statusHost}:${n.metroPort}`,launchUrl:w(e.launchUrl),profileKey:w(e.companionProfileKey),consumerKey:w(e.companionConsumerKey),env:n.env})).logPath}catch(e){throw new t(`COMMAND_FAILED`,Q(n.proxyBaseUrl,e instanceof Error?e.message:String(e),i,a),void 0,e)}try{return await fe({baseUrl:n.proxyBaseUrl,bearerToken:n.proxyBearerToken,scope:r,probeTimeoutMs:n.probeTimeoutMs,startupTimeoutMs:n.startupTimeoutMs,initialBridgeError:a,companionLogPath:o})}catch(e){throw e instanceof Error?e:Error(String(e))}}function ge(e,t){return{baseIosRuntime:e?I(e,`ios`,t):{platform:`ios`},baseAndroidRuntime:e?I(e,`android`,t):{platform:`android`}}}function _e(e,t){e&&(f.mkdirSync(p.dirname(e),{recursive:!0}),f.writeFileSync(e,JSON.stringify(t,null,2)))}async function ve(e={}){let t=$(e),n=t.installProjectDeps?R(t.projectRoot,t.env):{installed:!1},r=await pe(t),{baseIosRuntime:i,baseAndroidRuntime:a}=ge(t.publicBaseUrl,t.kind),o=await me(e,t),s=o?.iosRuntime??i,c=o?.androidRuntime??a,l={projectRoot:t.projectRoot,kind:t.kind,dependenciesInstalled:n.installed,packageManager:n.packageManager??null,started:r.started,reused:r.reused,pid:r.pid,logPath:t.logPath,statusUrl:r.statusUrl,runtimeFilePath:t.runtimeFilePath,iosRuntime:s,androidRuntime:c,bridge:o};return _e(t.runtimeFilePath,l),l}function ye(e){let t=e.trimStart().slice(0,15).toLowerCase();return t.startsWith(`<!doctype`)||t.startsWith(`<html`)}async function be(e,n){await new Promise((r,i)=>{let a=new WebSocket(e),o=e=>{clearTimeout(s);try{a.close()}catch{}i(new t(`COMMAND_FAILED`,e))},s=setTimeout(()=>{o(`Timed out broadcasting reload to ${e} after ${n}ms`)},n);a.addEventListener(`open`,()=>{a.send(JSON.stringify({version:2,method:`reload`}));let e=()=>{if(a.bufferedAmount===0){clearTimeout(s),a.close(),r();return}setTimeout(e,20)};e()}),a.addEventListener(`error`,()=>{o(`Failed to reach the dev server message socket at ${e}`)})})}async function xe(e={}){let n=F(e.timeoutMs,1e4,1e3),{reloadUrl:r,messageSocketUrl:i}=v(e),a=await V(r,n);if(a.ok&&!ye(a.body))return{reloaded:!0,reloadUrl:r,status:a.status,body:a.body,transport:`http`};try{await be(i,n)}catch(e){throw new t(`COMMAND_FAILED`,`React Native dev server reload failed (${a.status}).`,{reloadUrl:r,status:a.status,body:a.body.slice(0,500),messageSocketUrl:i,hint:`Verify Metro or Re.Pack is running and the target React Native app is connected to this dev server instance.`},e instanceof Error?e:void 0)}return{reloaded:!0,reloadUrl:i,status:a.status,body:``,transport:`message-socket`}}export{xe as n,m as r,ve as t};
|
|
1
|
+
import{F as e,P as t}from"./sdk-contracts.js";import{O as n}from"./owner-identity.js";import{n as r}from"./path-resolution.js";import{d as i,m as a}from"./exec.js";import{i as o}from"./retry.js";import"./file.js";import"./command.js";import"./process.js";import"./retry2.js";import{t as s}from"./base-url.js";import{t as c}from"./client-metro-companion.js";import{n as l,r as u}from"./project-runtime.js";import{t as d}from"./runtime-transport-hints.js";import f from"node:fs";import p from"node:path";function m(e,t,n=`index.bundle`){let r=new URL(`${s(e)}/${n}`);return r.searchParams.set(`platform`,t),r.searchParams.set(`dev`,`true`),r.searchParams.set(`minify`,`false`),r.toString()}const h=8081,g=`.expo/.virtual-metro-entry.bundle`;function _(e,n){if(e==null||e===``)return n;let r=Number.parseInt(String(e),10);if(!Number.isInteger(r)||r<1||r>65535)throw new t(`INVALID_ARGS`,`Invalid Metro port: ${String(e)}. Use 1-65535.`);return r}function v(e){let n=S(e.bundleUrl),r=n??e.runtime?.bundleUrl,i=!!n,a=!!S(r),o=d({metroHost:y(e,i,a),metroPort:b(e,i,a),bundleUrl:r});if(!o)throw new t(`INVALID_ARGS`,`Unable to resolve Metro host and port for reload.`);let s=ee(r);return{reloadUrl:x(o,o.scheme,`${s}/reload`),messageSocketUrl:x(o,o.scheme===`https`?`wss`:`ws`,`${s}/message`)}}function y(e,t,n){return S(e.metroHost)??(t?void 0:S(e.runtime?.metroHost))??(n?void 0:`localhost`)}function b(e,t,n){if(e.metroPort!==void 0)return _(e.metroPort,h);if(!t)return e.runtime?.metroPort??(n?void 0:h)}function ee(e){let t=S(e);if(!t)return``;let n;try{n=new URL(t)}catch{return``}let r=n.pathname.replace(/\/+$/,``),i=`/${g}`;if(r.endsWith(i))return r.slice(0,-i.length);let a=r.lastIndexOf(`/`);return(a>=0?r.slice(a+1):r).endsWith(`.bundle`)&&a>0?r.slice(0,a):``}function x(e,t,n){let r=new URL(`${t}://localhost`);return r.hostname=e.host,r.port=String(e.port),r.pathname=n,r.toString()}function S(e){return typeof e==`string`&&e.trim()?e.trim():void 0}function C(e){return typeof e==`string`&&e.trim()?s(e.trim()):``}function w(e){return typeof e==`string`&&e.trim()?e.trim():void 0}function T(e,t,n){return r(e,{env:t,cwd:n})}function E(e){try{return f.accessSync(e,f.constants.F_OK),!0}catch{return!1}}function D(e){try{return f.statSync(e).isDirectory()}catch{return!1}}function O(e){let n=p.join(e,`package.json`),r=u(e);if(!r)throw new t(`INVALID_ARGS`,`package.json not found at ${n}`);return r}const k=[{file:`pnpm-lock.yaml`,command:`pnpm`},{file:`yarn.lock`,command:`yarn`},{file:`bun.lock`,command:`bun`},{file:`bun.lockb`,command:`bun`},{file:`package-lock.json`,command:`npm`}];function te(e){let t=e;for(;;){for(let{file:e,command:n}of k)if(E(p.join(t,e)))return{command:n,installArgs:[`install`]};if(E(p.join(t,`.git`)))return null;let e=p.dirname(t);if(e===t)return null;t=e}}function A(e){return te(e)??{command:`npm`,installArgs:[`install`]}}function j(e,t){if(t!==`auto`)return t;let n=l(e);return n===`expo`||n===`repack`?n:`react-native`}function M(e,t){return typeof{...e.dependencies??{},...e.devDependencies??{}}[t]==`string`}function N(e,t){return[`js`,`mjs`,`cjs`,`ts`,`mts`,`cts`].some(n=>E(p.join(e,`${t}.config.${n}`)))}function P(e,t){return N(e,`rspack`)?`rspack`:N(e,`webpack`)?`webpack`:M(t,`@rspack/core`)?`rspack`:M(t,`webpack`)?`webpack`:`rspack`}function F(e,t,n){if(e==null||e===``)return t;let r=Number.parseInt(String(e),10);return Number.isInteger(r)?Math.max(r,n):t}function ne(e){return e===`expo`?g:`index.bundle`}function I(e,t,n){return{platform:t,bundleUrl:m(e,t,ne(n))}}function L(e,t){return{platform:t,metroHost:w(e?.metro_host),metroPort:e?.metro_port,bundleUrl:w(e?.metro_bundle_url),launchUrl:w(e?.launch_url)}}function R(e,t){if(D(p.join(e,`node_modules`)))return{installed:!1};let n=A(e);try{a(n.command,n.installArgs,{cwd:e,env:t})}catch(e){throw z(e,n)}return{installed:!0,packageManager:n.command}}function z(n,r){let i=e(n),a=`Dependency install failed using detected package manager "${r.command}". If dependencies are already installed (for example via a monorepo root install), pass --no-install-deps to skip this step, or install manually with "${r.command} ${r.installArgs.join(` `)}" from the project root.`;return new t(i.code,i.message,{...i.details??{},hint:a,packageManager:r.command},i)}async function B(e){await o(e)}async function V(e,n,r={}){try{let t=await fetch(e,{headers:r,signal:AbortSignal.timeout(n)});return{ok:t.ok,status:t.status,body:await t.text()}}catch(r){throw r instanceof Error&&r.name===`TimeoutError`?new t(`COMMAND_FAILED`,`Timed out fetching ${e} after ${n}ms`):r}}async function H(e,t){try{let n=await V(e,t);return n.ok&&n.body.includes(`packager-status:running`)}catch{return!1}}function U(e,t,n,r){return e===`expo`?{command:`npx`,installArgs:[`expo`,`start`,`--host`,`lan`,`--port`,String(n)]}:e===`repack`?{command:`npx`,installArgs:[`react-native`,t===`webpack`?`webpack-start`:`rspack-start`,`--host`,r,`--port`,String(n)]}:{command:`npx`,installArgs:[`react-native`,`start`,`--host`,r,`--port`,String(n)]}}function W(e,n,r,a,o,s,c){let l=U(n,r,a,o);f.mkdirSync(p.dirname(s),{recursive:!0});let u=f.openSync(s,`a`),d=0;try{d=i(l.command,l.installArgs,{cwd:e,env:c,stdio:[`ignore`,u,u]})}finally{f.closeSync(u)}if(!Number.isInteger(d)||d<=0)throw new t(`COMMAND_FAILED`,`Failed to start React Native dev server. Expected a detached child PID.`);return{pid:d}}async function G(e){if(!(!Number.isInteger(e)||e<=0)){try{process.kill(e,`SIGTERM`)}catch(e){let t=e.code;if(t===`ESRCH`||t===`EPERM`)return;throw e}if(!await n(e,1e3)){try{process.kill(e,`SIGKILL`)}catch(e){let t=e.code;if(t===`ESRCH`||t===`EPERM`)return;throw e}await n(e,1e3)}}}function K(e,t){return{Authorization:`Bearer ${t}`,"Content-Type":`application/json`,...e.includes(`ngrok`)?{"ngrok-skip-browser-warning":`1`}:{}}}function q(e,n){let r=new t(`COMMAND_FAILED`,e);return r.retryable=n,r}function J(e,t){return!!(e>=500||e===408||e===425||e===429||JSON.stringify(t).includes(`Metro companion is not connected`))}function Y(e){return!!(e&&typeof e==`object`&&`retryable`in e&&e.retryable===!0)}async function X(e){let t;try{t=await fetch(`${e.baseUrl}/api/metro/bridge`,{method:`POST`,headers:K(e.baseUrl,e.bearerToken),body:JSON.stringify({...e.scope,...e.runtime?{ios_runtime:e.runtime}:{},timeout_ms:e.timeoutMs}),signal:AbortSignal.timeout(e.timeoutMs)})}catch(t){throw t instanceof Error&&t.name===`TimeoutError`?q(`/api/metro/bridge timed out after ${e.timeoutMs}ms calling ${e.baseUrl}/api/metro/bridge`,!0):q(t instanceof Error?t.message:String(t),!0)}let n=Z(await t.text(),t.status,e.baseUrl);if(!t.ok)throw q(`/api/metro/bridge failed (${t.status}): ${JSON.stringify(n)}`,J(t.status,n));return ie(n)}function Z(e,t,n){if(!e)return{};try{let t=JSON.parse(e);if(!t||typeof t!=`object`||Array.isArray(t))throw Error(`Expected a JSON object`);return t}catch(r){let i=e.slice(0,200);throw q(`/api/metro/bridge returned invalid JSON (${t}) from ${n}: ${r instanceof Error?r.message:String(r)}. body=${JSON.stringify(i)}`,J(t,e))}}function re(e){return{enabled:e.enabled,baseUrl:e.base_url,statusUrl:e.status_url??``,bundleUrl:e.bundle_url??``,iosRuntime:L(e.ios_runtime,`ios`),androidRuntime:L(e.android_runtime,`android`),upstream:{bundleUrl:e.upstream.bundle_url??``,host:e.upstream.host??``,port:e.upstream.port??0,statusUrl:e.upstream.status_url??``},probe:{reachable:e.probe.reachable,statusCode:e.probe.status_code,latencyMs:e.probe.latency_ms,detail:e.probe.detail}}}function ie(e){let t=e.data??e;if(!t||typeof t!=`object`||Array.isArray(t))throw q(`/api/metro/bridge returned malformed descriptor: Expected a JSON object.`,!1);try{return re(t)}catch(e){throw q(`/api/metro/bridge returned malformed descriptor: ${e instanceof Error?e.message:String(e)}`,!1)}}function Q(e,t,n,r,i){let a=[`Metro bridge is required for this run but could not be configured via ${e}/api/metro/bridge.`];return t&&a.push(`bridgeError=${t}`),n?.probe.reachable===!1&&a.push(`bridgeProbe=${n.probe.detail||`unreachable (status ${n.probe.statusCode||0})`}`),r&&r!==t&&a.push(`initialBridgeError=${r}`),i&&a.push(`metroCompanionLog=${i}`),a.join(` `)}function ae(e,n){if(!n?.iosRuntime.bundleUrl)throw new t(`COMMAND_FAILED`,Q(e,`bridge descriptor is missing ios_runtime.metro_bundle_url`,n))}function oe(e,n,r){let i=n||w(r.AGENT_DEVICE_METRO_BEARER_TOKEN)||``,a=i||e&&w(r.AGENT_DEVICE_DAEMON_AUTH_TOKEN)||``;if(e&&!a)throw new t(`INVALID_ARGS`,`metro prepare requires proxy auth when --proxy-base-url is provided. Pass --bearer-token or set AGENT_DEVICE_METRO_BEARER_TOKEN or AGENT_DEVICE_DAEMON_AUTH_TOKEN.`);if(!e&&i)throw new t(`INVALID_ARGS`,`metro prepare requires --proxy-base-url when proxy auth is provided.`);return{proxyEnabled:!!(e&&a),proxyBaseUrl:e,proxyBearerToken:a}}function se(e){if(!e?.tenantId||!e.runId||!e.leaseId)throw new t(`INVALID_ARGS`,`metro prepare with proxy requires tenantId, runId, and leaseId bridge scope.`);return e}function ce(e,n){if(!(e||n))throw new t(`INVALID_ARGS`,`metro prepare requires --public-base-url <url> or --proxy-base-url <url>.`)}function le(e,t,n){return e.runtimeFilePath?T(e.runtimeFilePath,t,n):null}function ue(e,t,n,r){return T(e.logPath??p.join(r,`.agent-device`,`metro.log`),t,n)}function $(e){let t=e.env??process.env,n=process.cwd(),r=T(e.projectRoot??n,t,n),i=e.kind??`auto`,a=null,o;i===`auto`?(a=O(r),o=j(a,i)):o=i;let s=null;o===`repack`&&(a??=O(r),s=P(r,a));let c=C(e.publicBaseUrl),l=C(e.proxyBaseUrl);ce(c,l);let{proxyEnabled:u,proxyBaseUrl:d,proxyBearerToken:f}=oe(l,w(e.proxyBearerToken)??``,t);return{env:t,projectRoot:r,kind:o,repackBundler:s,metroPort:_(e.metroPort??8081,8081),listenHost:w(e.listenHost)??`0.0.0.0`,statusHost:w(e.statusHost)??`127.0.0.1`,publicBaseUrl:c,proxyBaseUrl:d,proxyBearerToken:f,bridgeScope:u?se(e.bridgeScope):null,startupTimeoutMs:F(e.startupTimeoutMs,18e4,3e4),probeTimeoutMs:F(e.probeTimeoutMs,1e4,1e3),reuseExisting:e.reuseExisting??!0,installProjectDeps:e.installDependenciesIfNeeded??!0,runtimeFilePath:le(e,t,n),logPath:ue(e,t,n,r)}}async function de(e,t,n){let r=Date.now()+t;for(;Date.now()<r;){let t=r-Date.now();if(await H(e,Math.min(n,Math.max(t,1))))return!0;let i=Math.min(500,Math.max(r-Date.now(),0));i>0&&await B(i)}return!1}async function fe(e){let n=Date.now()+e.startupTimeoutMs,r=null,i=null;for(;Date.now()<n;){try{let t=await X({baseUrl:e.baseUrl,bearerToken:e.bearerToken,scope:e.scope,runtime:e.runtime,timeoutMs:e.probeTimeoutMs});if(t.probe.reachable!==!1)return t;r=t,i=null}catch(n){if(i=n instanceof Error?n.message:String(n),!Y(n))throw new t(`COMMAND_FAILED`,Q(e.baseUrl,i,r,e.initialBridgeError,e.companionLogPath),void 0,n)}let a=Math.min(1e3,Math.max(n-Date.now(),0));a>0&&await B(a)}throw new t(`COMMAND_FAILED`,Q(e.baseUrl,i,r,e.initialBridgeError,e.companionLogPath))}async function pe(e){let n=`http://${e.statusHost}:${e.metroPort}/status`;if(e.reuseExisting&&await H(n,e.probeTimeoutMs))return{started:!1,reused:!0,pid:0,statusUrl:n};let r=W(e.projectRoot,e.kind,e.repackBundler,e.metroPort,e.listenHost,e.logPath,e.env);if(await de(n,e.startupTimeoutMs,e.probeTimeoutMs))return{started:!0,reused:!1,pid:r.pid,statusUrl:n};throw await G(r.pid).catch(()=>{}),new t(`COMMAND_FAILED`,`React Native dev server did not become ready at ${n} within ${e.startupTimeoutMs}ms. Check ${e.logPath}.`,{logPath:e.logPath})}async function me(e,t){let n=t.bridgeScope;if(!n)return null;let r=null,i=null;try{r=await X({baseUrl:t.proxyBaseUrl,bearerToken:t.proxyBearerToken,scope:n,timeoutMs:t.probeTimeoutMs})}catch(e){if(!Y(e))throw e;i=e instanceof Error?e.message:String(e)}return(!r||r.probe.reachable===!1)&&(r=await he(e,t,n,r,i)),ae(t.proxyBaseUrl,r),r}async function he(e,n,r,i,a){let o;try{o=(await c({projectRoot:n.projectRoot,serverBaseUrl:n.proxyBaseUrl,bearerToken:n.proxyBearerToken,bridgeScope:r,localBaseUrl:`http://${n.statusHost}:${n.metroPort}`,launchUrl:w(e.launchUrl),profileKey:w(e.companionProfileKey),consumerKey:w(e.companionConsumerKey),env:n.env})).logPath}catch(e){throw new t(`COMMAND_FAILED`,Q(n.proxyBaseUrl,e instanceof Error?e.message:String(e),i,a),void 0,e)}try{return await fe({baseUrl:n.proxyBaseUrl,bearerToken:n.proxyBearerToken,scope:r,probeTimeoutMs:n.probeTimeoutMs,startupTimeoutMs:n.startupTimeoutMs,initialBridgeError:a,companionLogPath:o})}catch(e){throw e instanceof Error?e:Error(String(e))}}function ge(e,t){return{baseIosRuntime:e?I(e,`ios`,t):{platform:`ios`},baseAndroidRuntime:e?I(e,`android`,t):{platform:`android`}}}function _e(e,t){e&&(f.mkdirSync(p.dirname(e),{recursive:!0}),f.writeFileSync(e,JSON.stringify(t,null,2)))}async function ve(e={}){let t=$(e),n=t.installProjectDeps?R(t.projectRoot,t.env):{installed:!1},r=await pe(t),{baseIosRuntime:i,baseAndroidRuntime:a}=ge(t.publicBaseUrl,t.kind),o=await me(e,t),s=o?.iosRuntime??i,c=o?.androidRuntime??a,l={projectRoot:t.projectRoot,kind:t.kind,dependenciesInstalled:n.installed,packageManager:n.packageManager??null,started:r.started,reused:r.reused,pid:r.pid,logPath:t.logPath,statusUrl:r.statusUrl,runtimeFilePath:t.runtimeFilePath,iosRuntime:s,androidRuntime:c,bridge:o};return _e(t.runtimeFilePath,l),l}function ye(e){let t=e.trimStart().slice(0,15).toLowerCase();return t.startsWith(`<!doctype`)||t.startsWith(`<html`)}async function be(e,n){await new Promise((r,i)=>{let a=new WebSocket(e),o=e=>{clearTimeout(s);try{a.close()}catch{}i(new t(`COMMAND_FAILED`,e))},s=setTimeout(()=>{o(`Timed out broadcasting reload to ${e} after ${n}ms`)},n);a.addEventListener(`open`,()=>{a.send(JSON.stringify({version:2,method:`reload`}));let e=()=>{if(a.bufferedAmount===0){clearTimeout(s),a.close(),r();return}setTimeout(e,20)};e()}),a.addEventListener(`error`,()=>{o(`Failed to reach the dev server message socket at ${e}`)})})}async function xe(e={}){let n=F(e.timeoutMs,1e4,1e3),{reloadUrl:r,messageSocketUrl:i}=v(e),a=await V(r,n);if(a.ok&&!ye(a.body))return{reloaded:!0,reloadUrl:r,status:a.status,body:a.body,transport:`http`};try{await be(i,n)}catch(e){throw new t(`COMMAND_FAILED`,`React Native dev server reload failed (${a.status}).`,{reloadUrl:r,status:a.status,body:a.body.slice(0,500),messageSocketUrl:i,hint:`Verify Metro or Re.Pack is running and the target React Native app is connected to this dev server instance.`},e instanceof Error?e:void 0)}return{reloaded:!0,reloadUrl:i,status:a.status,body:``,transport:`message-socket`}}export{xe as n,m as r,ve as t};
|