agent-device 0.20.8 → 0.20.9
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 +94 -31
- package/android/ime-helper/dist/{agent-device-android-ime-helper-0.20.8.apk → agent-device-android-ime-helper-0.20.9.apk} +0 -0
- package/android/ime-helper/dist/agent-device-android-ime-helper-0.20.9.apk.sha256 +1 -0
- package/android/ime-helper/dist/{agent-device-android-ime-helper-0.20.8.manifest.json → agent-device-android-ime-helper-0.20.9.manifest.json} +4 -4
- package/android/snapshot-helper/dist/{agent-device-android-snapshot-helper-0.20.8.apk → agent-device-android-snapshot-helper-0.20.9.apk} +0 -0
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.20.9.apk.sha256 +1 -0
- package/android/snapshot-helper/dist/{agent-device-android-snapshot-helper-0.20.8.manifest.json → agent-device-android-snapshot-helper-0.20.9.manifest.json} +6 -6
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerAXSnapshotBridge.h +3 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerAXSnapshotBridge.m +13 -7
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+AXSnapshotFallback.swift +4 -112
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+FlatSnapshotFiltering.swift +9 -1
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+PrivateAXPresentation.swift +90 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift +46 -10
- package/dist/src/agent-browser-tool.js +1 -1
- package/dist/src/agent-device-client.js +2 -2
- package/dist/src/android-adb.d.ts +5 -5
- package/dist/src/android-adb.js +1 -1
- package/dist/src/android.js +1 -1
- package/dist/src/app-helpers.js +1 -1
- package/dist/src/app-lifecycle.js +6 -7
- package/dist/src/app-lifecycle2.js +2 -2
- package/dist/src/app-log-reconnect.js +1 -1
- package/dist/src/app-log-runtime.js +3 -3
- package/dist/src/app-resolution.js +2 -2
- package/dist/src/app-state.js +2 -0
- package/dist/src/appearance.js +1 -0
- package/dist/src/apps.js +5 -5
- package/dist/src/artifacts.d.ts +1 -1
- package/dist/src/audio-probe.js +1 -1
- package/dist/src/auth-session.js +1 -1
- package/dist/src/backend-snapshot-options.js +1 -0
- package/dist/src/boot-diagnostics.js +2 -2
- package/dist/src/bounds.js +1 -0
- package/dist/src/byte-limit-stream.js +1 -0
- package/dist/src/cancel.js +1 -0
- package/dist/src/cli-config.js +1 -1
- package/dist/src/cli-help.js +25 -20
- package/dist/src/cli.js +6 -6
- package/dist/src/client-metro.js +1 -1
- package/dist/src/command-catalog.js +1 -0
- package/dist/src/command-metadata.js +1 -1
- package/dist/src/command-schema.js +1 -1
- package/dist/src/command-surface.js +1 -1
- package/dist/src/config.js +1 -0
- package/dist/src/connection-runtime.js +1 -1
- package/dist/src/connection.js +3 -3
- package/dist/src/contracts.js +1 -1
- package/dist/src/debug-symbols.js +3 -3
- package/dist/src/device-claim-inspection.js +1 -1
- package/dist/src/device-input-state.js +1 -1
- package/dist/src/device-ready.js +1 -1
- package/dist/src/device2.js +2 -2
- package/dist/src/dispatch.js +1 -1
- package/dist/src/entities.js +1 -1
- package/dist/src/find.js +1 -1
- package/dist/src/finders.js +1 -1
- package/dist/src/generic-settle.js +1 -1
- package/dist/src/generic.js +1 -1
- package/dist/src/harmonyos.js +1 -1
- package/dist/src/hdc.js +1 -1
- package/dist/src/helper-package-install.js +1 -0
- package/dist/src/helper.js +2 -2
- package/dist/src/host-process.js +1 -1
- package/dist/src/ime-lifecycle.js +2 -9
- package/dist/src/ime-recovery-marker.js +1 -0
- package/dist/src/index.d.ts +24 -15
- package/dist/src/index.js +1 -1
- package/dist/src/input-actions.js +4 -4
- package/dist/src/input-actions2.js +1 -1
- package/dist/src/input-actions3.js +1 -1
- package/dist/src/install-artifact.js +1 -1
- package/dist/src/install-artifact2.js +1 -1
- package/dist/src/install-source2.js +1 -1
- package/dist/src/interaction-common.js +1 -0
- package/dist/src/interaction-runtime.js +1 -1
- package/dist/src/interaction-snapshot.js +1 -1
- package/dist/src/interaction.js +1 -1
- package/dist/src/interaction2.js +1 -0
- package/dist/src/interactor.js +2 -2
- package/dist/src/interactor2.js +1 -1
- package/dist/src/interactors.js +1 -0
- package/dist/src/internal/bin.js +1 -1
- package/dist/src/internal/daemon.js +4 -7
- package/dist/src/internal/png-worker.js +1 -1
- package/dist/src/inventory.js +1 -1
- package/dist/src/keyed-lock.js +1 -0
- package/dist/src/lease-context.js +1 -1
- package/dist/src/lease.js +1 -1
- package/dist/src/limrun-runtime-dependencies.js +1 -1
- package/dist/src/limrun.d.ts +3 -1
- package/dist/src/limrun.js +1 -1
- package/dist/src/linux.js +1 -1
- package/dist/src/location-coordinates.js +1 -0
- package/dist/src/logcat.js +1 -1
- package/dist/src/manifest.js +1 -1
- package/dist/src/observability.js +1 -0
- package/dist/src/owner-identity.js +1 -1
- package/dist/src/perf.js +4 -0
- package/dist/src/physical-device-control.js +1 -1
- package/dist/src/platform-runtime-app-log-process.js +1 -1
- package/dist/src/platform-runtime-host.js +1 -1
- package/dist/src/platform-runtime-network-web-transport.js +1 -1
- package/dist/src/platform-runtime-open-target.js +1 -0
- package/dist/src/platform-runtime-operation-host.js +4 -4
- package/dist/src/platform-runtime-runtime-hints.js +2 -0
- package/dist/src/platform-runtime-screen-recording-apple-runner-host.js +1 -1
- package/dist/src/platform-runtime-screen-recording-apple-runner-transport.js +1 -1
- package/dist/src/platform-runtime-screen-recording-apple-transport.js +1 -1
- package/dist/src/platform-runtime-screen-recording-finalizer-host.js +1 -1
- package/dist/src/platform-runtime-screen-recording-web-host.js +1 -1
- package/dist/src/platform-runtime.js +1 -1
- package/dist/src/platform-runtime2.js +1 -0
- package/dist/src/plist.js +1 -1
- package/dist/src/png-resize.js +1 -0
- package/dist/src/png-worker-contract.js +1 -1
- package/dist/src/prepare-kind.js +13 -13
- package/dist/src/process-lock.js +1 -1
- package/dist/src/project-runtime.js +1 -0
- package/dist/src/provider-webdriver.js +1 -1
- package/dist/src/provider.js +1 -0
- package/dist/src/proxy.js +1 -1
- 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-export-quality.js +1 -0
- package/dist/src/registry.js +29 -26
- package/dist/src/remote-config2.js +1 -1
- package/dist/src/replay.js +1 -1
- package/dist/src/reporting.js +3 -3
- package/dist/src/rolldown-runtime.js +1 -0
- package/dist/src/runner-client.js +1 -0
- package/dist/src/runner-disposal.js +1 -1
- package/dist/src/runner-lease.js +1 -1
- package/dist/src/runner-sequence.js +1 -1
- package/dist/src/runtime-transport.js +1 -1
- package/dist/src/runtime.js +3 -3
- package/dist/src/runtime2.js +4 -3
- package/dist/src/runtime3.js +1 -3
- package/dist/src/runtime4.js +3 -1
- package/dist/src/runtime5.js +1 -1
- package/dist/src/runtime6.js +1 -1
- package/dist/src/runtime7.js +1 -1
- package/dist/src/runtime8.js +1 -0
- package/dist/src/runtime9.js +1 -0
- package/dist/src/scoped-provider.js +1 -0
- package/dist/src/screenshot-density.js +1 -0
- package/dist/src/screenshot-geometry.js +1 -0
- package/dist/src/screenshot-result.js +4 -4
- package/dist/src/screenshot.js +1 -1
- package/dist/src/sdk-android-adb.d.ts +20 -2
- package/dist/src/sdk-android-adb.js +3 -3
- package/dist/src/sdk-batch-runner.js +3 -3
- package/dist/src/sdk-contracts.d.ts +3 -3
- package/dist/src/sdk-contracts.js +2 -2
- package/dist/src/sdk-device.js +1 -1
- package/dist/src/sdk-finders.js +1 -1
- package/dist/src/sdk-io.js +1 -1
- package/dist/src/sdk-remote-config.js +1 -1
- package/dist/src/sdk-selectors.d.ts +19 -19
- package/dist/src/sdk-selectors.js +1 -1
- package/dist/src/sdk.js +1 -0
- package/dist/src/selector-runtime.js +1 -1
- package/dist/src/selectors.d.ts +1 -1
- package/dist/src/selectors.js +1 -1
- package/dist/src/server.js +2 -2
- package/dist/src/session-target-evidence.js +1 -1
- package/dist/src/session.js +1 -30
- package/dist/src/session2.js +28 -0
- package/dist/src/setting-state.js +1 -1
- package/dist/src/shared.js +1 -1
- package/dist/src/simctl.js +1 -0
- package/dist/src/simulator-state.js +1 -0
- package/dist/src/simulator.js +1 -1
- package/dist/src/snapshot-runtime.js +1 -1
- package/dist/src/snapshot-session.js +1 -1
- package/dist/src/snapshot.js +8 -1
- package/dist/src/snapshot2.js +1 -1
- package/dist/src/snapshot3.js +1 -0
- package/dist/src/src.js +1 -1
- package/dist/src/src2.js +1 -2
- package/dist/src/src3.js +2 -1
- package/dist/src/string-enum.js +1 -0
- package/dist/src/tool-provider.js +3 -3
- package/dist/src/tool-provider2.js +1 -1
- package/dist/src/update-check.js +1 -1
- package/dist/src/verdict.js +1 -0
- package/dist/src/verified-file.js +1 -0
- package/dist/src/version.js +1 -1
- package/dist/src/video.js +1 -1
- package/dist/src/web.js +1 -1
- package/package.json +8 -4
- package/server.json +3 -3
- package/android/ime-helper/dist/agent-device-android-ime-helper-0.20.8.apk.sha256 +0 -1
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.20.8.apk.sha256 +0 -1
- package/dist/src/interaction-touch-reference-frame.js +0 -1
- package/dist/src/notifications.js +0 -1
- package/dist/src/platform-runtime-toolchain-host.js +0 -1
- package/dist/src/text-surface.js +0 -1
- package/dist/src/tool-provider3.js +0 -1
package/dist/src/cli-help.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import{
|
|
2
|
-
`)}function d(e){let t=e.endsWith(`?`),n=t?e.slice(0,-1):e;return t?`[${n}]`:`<${n}>`}function f(e){return
|
|
1
|
+
import{Yn as e}from"./sdk-batch-runner.js";import{i as t}from"./command-catalog.js";import{S as n,d as r,m as i}from"./registry.js";import{n as a}from"./version.js";import{i as o,r as s}from"./command-schema.js";const c=[`Flows: launchApp; runFlow file/inline with platform, visibility, and limited boolean conditions; onFlowStart/onFlowComplete; repeat.times and retry.`,`Interactions: tapOn, doubleTapOn, longPressOn, inputText, eraseText, openLink, hideKeyboard, basic pressKey, and back; targets support index, childOf, label, points, and optional.`,`Assertions and navigation: assertVisible, assertNotVisible, extendedWaitUntil, scroll, scrollUntilVisible, absolute/percentage/target swipe, takeScreenshot, waitForAnimationToEnd, and stopApp.`,`Scripts: ordered runScript file/env scripts with http.post, json, and output variables.`],l=[`Runtime: iOS and Android only; launchApp.clearState supports Android and iOS simulators, launch arguments are Apple-only, and standalone device utility/state commands are unsupported.`,`Expressions: when.true supports boolean literals and maestro.platform comparisons; repeat.while, evalScript, and broader JavaScript expressions are unsupported.`,`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 executes trusted scripts, may make http.post network requests, and is not a security sandbox; output keys cannot contain a dot.`,`Errors and tracking: unsupported commands and fields fail with source context when available; open a focused issue only when implementation work is planned.`];function u(){return[`Supported subset:`,...c.map(e=>` - ${e}`),``,`Boundaries:`,...l.map(e=>` - ${e}`)].join(`
|
|
2
|
+
`)}function d(e){let t=e.endsWith(`?`),n=t?e.slice(0,-1):e;return t?`[${n}]`:`<${n}>`}function f(e){return n().filter(t=>t.key===e)}function p(e,t){if(t.usageOverride)return t.usageOverride;let n=(t.positionalArgs??[]).map(d),r=(t.allowedFlags??[]).flatMap(e=>f(e).map(e=>e.usageLabel??e.names[0])).map(e=>`[${e}]`);return[e,...n,...r].join(` `)}function m(){return`agent-device <command> [args] [--json]
|
|
3
3
|
|
|
4
4
|
Automates iOS, Android, macOS, TV, and web apps for AI agents.
|
|
5
|
-
All ${
|
|
5
|
+
All ${t().length} commands: agent-device help commands
|
|
6
6
|
|
|
7
7
|
Start:
|
|
8
8
|
When starting a task with a known app, first run:
|
|
@@ -24,7 +24,7 @@ Loop:
|
|
|
24
24
|
Targets:
|
|
25
25
|
Copy refs exactly: @e12, @e12~s4. Keep @ and any ~sN pin; refs go stale
|
|
26
26
|
after mutations. A literal @handle is label="@handle", not a bare ref.
|
|
27
|
-
Prefer refs, then id/label/role selectors. Selector keys: ${
|
|
27
|
+
Prefer refs, then id/label/role selectors. Selector keys: ${e.join(` `)}.
|
|
28
28
|
Coordinates are last resort: after snapshot -i shows no semantic target, or a
|
|
29
29
|
sparse/AX-unavailable warning says its refs and selectors are invalid.
|
|
30
30
|
Then screenshot, press <x> <y>, and re-snapshot on the changed screen.
|
|
@@ -259,7 +259,7 @@ Vega OS:
|
|
|
259
259
|
vega virtual-device stop
|
|
260
260
|
Use a component ID from the app package or Vega SDK tooling; agent-device app inventory is not yet supported.
|
|
261
261
|
Use --serial VirtualDevice for explicit VVD selection.
|
|
262
|
-
|
|
262
|
+
The VVD is never booted implicitly; start it with vega virtual-device start.
|
|
263
263
|
Snapshot, screenshot, selectors, install, touch/text/gesture, logs, and performance commands remain unsupported until their Vega backends are implemented.
|
|
264
264
|
|
|
265
265
|
Buttons:
|
|
@@ -368,7 +368,7 @@ Diagnostics and traces:
|
|
|
368
368
|
agent-device perf cpu profile report --kind xctrace --out ./artifacts/app-profile.json
|
|
369
369
|
agent-device perf trace start --kind xctrace --template "Animation Hitches" --out ./artifacts/hitches.trace
|
|
370
370
|
agent-device perf trace stop --kind xctrace --out ./artifacts/hitches.trace
|
|
371
|
-
perf xctrace
|
|
371
|
+
perf xctrace keeps the .trace artifact on disk; CPU report returns a bounded weighted top-function summary. Do not dump .trace contents into context.
|
|
372
372
|
For Android native CPU/trace evidence, use perf artifacts instead of raw adb/simpleperf/perfetto output:
|
|
373
373
|
agent-device perf cpu profile start --kind simpleperf --out /tmp/cpu.perf.data
|
|
374
374
|
agent-device perf cpu profile stop --kind simpleperf
|
|
@@ -376,6 +376,10 @@ Diagnostics and traces:
|
|
|
376
376
|
agent-device perf trace start --kind perfetto --out /tmp/app.perfetto-trace
|
|
377
377
|
agent-device perf trace stop --kind perfetto
|
|
378
378
|
Treat native perf output as the agent evidence: for example, state=stopped, outPath=/tmp/app.perfetto-trace, sizeBytes=5392410, method=adb-shell-perfetto. The 5.3 MB raw trace stays in the artifact.
|
|
379
|
+
CPU reports return at most ten top functions in structured data and print five in default CLI output.
|
|
380
|
+
Prefer explicit perf frames, perf memory, perf cpu, or perf trace forms. Bare perf, perf sample, perf metrics, and metrics are deprecated compatibility forms until the next major release.
|
|
381
|
+
On Android, those deprecated aggregate forms retain the released dumpsys cpuinfo point sample for compatibility; new profiling workflows should use perf cpu profile.
|
|
382
|
+
Startup duration belongs to the open command's startup result; read it there instead of using aggregate perf.
|
|
379
383
|
|
|
380
384
|
Memory diagnostics:
|
|
381
385
|
Use perf memory when the symptom is leak/growth/OOM suspicion and you need agent-readable evidence.
|
|
@@ -386,7 +390,7 @@ Memory diagnostics:
|
|
|
386
390
|
{"metrics":{"memory":{"available":true,"totalPssKb":562958,"totalRssKb":570304,"topConsumers":[{"name":"Dalvik Heap","pssKb":213456}]}}}
|
|
387
391
|
Example default snapshot output:
|
|
388
392
|
Memory artifact (android-hprof): /tmp/app.hprof (42MB)
|
|
389
|
-
Prefer perf memory sample over raw dumpsys/leaks output for first-pass agent diagnosis: it keeps arrays bounded
|
|
393
|
+
Prefer perf memory sample over raw dumpsys/leaks output for first-pass agent diagnosis: it keeps arrays bounded and returns only relevant memory evidence.
|
|
390
394
|
Prefer perf memory snapshot over printing heap/memgraph data: snapshots return path, size, kind, method, and support metadata while the large artifact stays on disk for external inspection.
|
|
391
395
|
Unsupported platforms return artifact.available=false with reason/hint; do not pretend a heap or memgraph was captured.
|
|
392
396
|
|
|
@@ -464,7 +468,7 @@ Example:
|
|
|
464
468
|
agent-device react-devtools profile report @c5
|
|
465
469
|
agent-device network dump --include headers
|
|
466
470
|
|
|
467
|
-
Use snapshot, screenshot, logs, network, and perf
|
|
471
|
+
Use snapshot, screenshot, logs, network, perf frames, and perf memory for device/app runtime evidence. Use react-devtools when component internals or React rendering behavior matters.`},cdp:{summary:`React Native CDP targets, JS heap snapshots, and leak triage`,body:`agent-device help cdp
|
|
468
472
|
|
|
469
473
|
Use this when a React Native or Expo app exposes a CDP target through Metro and
|
|
470
474
|
the task needs JavaScript heap growth checks, heap snapshot diffs, allocation
|
|
@@ -570,7 +574,7 @@ Overlays and busy RN UIs:
|
|
|
570
574
|
React DevTools routing:
|
|
571
575
|
Keep the agent-device react-devtools prefix on every React DevTools command.
|
|
572
576
|
Use help react-devtools for status/wait, component trees, props/state/hooks, profile windows, slow renders, rerenders, and remote bridge rules.
|
|
573
|
-
If React DevTools cannot connect, report status and continue with logs, network, perf
|
|
577
|
+
If React DevTools cannot connect, report status and continue with logs, network, perf frames, perf memory, screenshot, and trace evidence instead of blocking the whole flow.
|
|
574
578
|
|
|
575
579
|
CDP memory routing:
|
|
576
580
|
Keep the agent-device cdp prefix on every CDP command.
|
|
@@ -587,7 +591,7 @@ Slow-flow investigation:
|
|
|
587
591
|
If the task says to open the app, include the open command even when it also describes the current screen.
|
|
588
592
|
Use help react-devtools for the narrow React profile window. Profiling plans need both status and wait --connected before profile start.
|
|
589
593
|
Check status before wait/profile. Do not substitute react-devtools start for status; start launches the helper, while status reports connection state.
|
|
590
|
-
Use help debugging for logs clear --restart, logs mark, network dump --include headers, perf
|
|
594
|
+
Use help debugging for logs clear --restart, logs mark, network dump --include headers, perf frames, perf memory, native profiles, traces, and runtime failure evidence.
|
|
591
595
|
For 15-20s async work, use wait with the exact expected text or selector instead of repeated snapshots.
|
|
592
596
|
Report React render offenders separately from network/backend waits and device frame/CPU/memory findings.`},"physical-device":{summary:`Connected phone/tablet setup and iOS signing prerequisites`,body:`agent-device help physical-device
|
|
593
597
|
|
|
@@ -770,6 +774,7 @@ Open and inspect:
|
|
|
770
774
|
agent-device snapshot -i --platform macos
|
|
771
775
|
|
|
772
776
|
Surfaces:
|
|
777
|
+
--surface is an open flag; the session keeps it, so later commands do not repeat it.
|
|
773
778
|
--surface app normal app session
|
|
774
779
|
--surface frontmost-app inspect whichever app is frontmost
|
|
775
780
|
--surface desktop desktop-wide surface
|
|
@@ -777,7 +782,7 @@ Surfaces:
|
|
|
777
782
|
|
|
778
783
|
Menu bar app example:
|
|
779
784
|
agent-device open "Agent Device Tester Menu" --platform macos --surface menubar
|
|
780
|
-
agent-device snapshot -i --platform macos
|
|
785
|
+
agent-device snapshot -i --platform macos
|
|
781
786
|
|
|
782
787
|
Context menu example:
|
|
783
788
|
agent-device click @e66 --button secondary --platform macos
|
|
@@ -793,7 +798,7 @@ Rules:
|
|
|
793
798
|
Use --platform web only for the minimal browser command loop exposed through agent-device.
|
|
794
799
|
|
|
795
800
|
Dependency:
|
|
796
|
-
|
|
801
|
+
Browser mechanics come from a managed, pinned agent-browser backend. agent-device owns command/session/replay integration, selectors/refs at the command surface, and artifact routing; agent-browser owns browser launch, page control, screenshots, and browser-specific behavior.
|
|
797
802
|
Use --platform web when a browser step belongs inside an agent-device session, replay, batch, MCP, or typed-client flow. Use agent-browser directly for standalone web automation.
|
|
798
803
|
Before first use, set up and verify the managed backend:
|
|
799
804
|
agent-device web setup
|
|
@@ -890,7 +895,7 @@ Rules:
|
|
|
890
895
|
scroll takes direction then amount and does not support a selector or --settle: agent-device scroll down 3.
|
|
891
896
|
Keep commands in the report reproducible; use selectors or refs from fresh snapshots, not guessed coordinates.
|
|
892
897
|
Prefer refs for exploration and selectors for deterministic replay.
|
|
893
|
-
Use logs, network, screenshot --overlay-refs, trace, perf
|
|
898
|
+
Use logs, network, screenshot --overlay-refs, trace, perf frames, perf memory, native profiles, or react-devtools only when they add evidence to a specific issue.
|
|
894
899
|
Never delete screenshots, videos, traces, or report artifacts during a session.
|
|
895
900
|
Escalate to help debugging or help react-devtools when runtime symptoms require those tools.`},validate:{summary:`Engineering self-validation with device evidence and cleanup`,body:`agent-device help validate
|
|
896
901
|
|
|
@@ -921,7 +926,7 @@ Evidence:
|
|
|
921
926
|
Visual claim: screenshot, optionally screenshot --overlay-refs when target mapping matters.
|
|
922
927
|
Runtime/logging claim: logs clear --restart, logs mark, reproduce, logs path.
|
|
923
928
|
Network claim: network dump --include headers when headers are relevant.
|
|
924
|
-
Performance claim: perf
|
|
929
|
+
Performance claim: perf frames, perf memory sample, native profile reports, or trace artifacts with bounded output.
|
|
925
930
|
Replay/regression claim: replay or test through the public command path.
|
|
926
931
|
|
|
927
932
|
Report:
|
|
@@ -930,27 +935,27 @@ Report:
|
|
|
930
935
|
|
|
931
936
|
Full command catalog. Use agent-device help <command> for exact flags and behavior.
|
|
932
937
|
|
|
933
|
-
${A(
|
|
938
|
+
${A(t().map(e=>{let t=s(e);return{name:e,schema:t,usage:x(e,t)}}))}
|
|
934
939
|
|
|
935
|
-
${D(`Global Flags:`,T(
|
|
940
|
+
${D(`Global Flags:`,T(r))}
|
|
936
941
|
|
|
937
942
|
${k(`Configuration:`,h)}
|
|
938
943
|
|
|
939
944
|
${O(`Environment:`,g)}
|
|
940
945
|
|
|
941
946
|
${k(`Examples:`,_)}
|
|
942
|
-
`}function w(){return S()}function T(e){return
|
|
947
|
+
`}function w(){return S()}function T(e){return n().filter(t=>e.has(t.key)&&t.usageLabel!==void 0&&t.usageDescription!==void 0)}function E(e,t){return t?e.map(e=>{let n=t[e.key];return n===void 0?e:{...e,usageDescription:n}}):e}function D(e,t){return O(e,t.map(e=>({label:e.usageLabel??``,description:e.usageDescription??``})))}function O(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(`
|
|
943
948
|
`)}function k(e,t){return t.length===0?`${e}\n (none)`:[e,...t.map(e=>` ${e}`)].join(`
|
|
944
|
-
`)}function A(e){return O(`Commands:`,e.map(e=>({label:e.usage,description:e.schema.text.summary})))}function j(e){let t=M(e);if(t)return t;let n=o(e);if(!n)return null;let r=p(e,n),
|
|
949
|
+
`)}function A(e){return O(`Commands:`,e.map(e=>({label:e.usage,description:e.schema.text.summary})))}function j(e){let t=M(e);if(t)return t;let n=o(e);if(!n)return null;let r=p(e,n),a=E(T(new Set(n.allowedFlags??[])),n.flagDescriptionOverrides),s=[];a.length>0&&s.push(D(`Command flags:`,a));let c=s.length>0?`\n\n${s.join(`
|
|
945
950
|
|
|
946
951
|
`)}`:``;return`Usage:
|
|
947
952
|
agent-device ${r}
|
|
948
953
|
|
|
949
|
-
${
|
|
954
|
+
${i(n.text)}${c}
|
|
950
955
|
`}function M(e){let t=y[e];return t?`${N(e,e===`commands`?C():t.body)}
|
|
951
956
|
|
|
952
957
|
Related:
|
|
953
958
|
agent-device help <command> command-specific flags
|
|
954
959
|
agent-device help manual-qa routine QA loop
|
|
955
960
|
agent-device help workflow full automation reference
|
|
956
|
-
`:null}function N(t
|
|
961
|
+
`:null}function N(e,t){let n=`agent-device help ${e}`;return t.startsWith(n)?`agent-device ${a()} — ${e}${t.slice(n.length)}`:t}export{j as buildCommandUsageText,w as buildUsageText};
|
package/dist/src/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{
|
|
2
|
-
`))}function H(e,t,n){return n||(e.push(t),``)}function Ue(e){if(!e?.metroProxyBaseUrl||!
|
|
3
|
-
`)}function Ye(e,t){if(e){
|
|
4
|
-
`),n}function tt(e){let t=
|
|
5
|
-
`)}function J(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,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
|
|
1
|
+
import{C as e,T as t,_ as n,v as r}from"./sdk-contracts.js";import{_ as i}from"./location-coordinates.js";import{kr as a,l as o}from"./sdk-batch-runner.js";import{mt as s,pt as c}from"./prepare-kind.js";import{n as l,r as u}from"./agent-device-client.js";import{_ as d}from"./screenshot-result.js";import{i as f,r as p,t as m}from"./command-catalog.js";import{S as h,x as g}from"./registry.js";import{n as _}from"./command-metadata.js";import{A as v,I as ee,M as y,N as te,j as b,k as ne,x as re}from"./sdk-android-adb.js";import{n as ie}from"./version.js";import{n as ae,t as x}from"./internal/bin.js";import{i as oe,n as S,t as se}from"./command-schema.js";import{t as ce}from"./update-check.js";import{n as C,r as w,t as le}from"./cli-config.js";import{exitAfterFlush as T}from"./process-exit.js";import{D as ue,E as de,S as fe,T as pe,h as me,n as he,w as ge}from"./connection-runtime.js";import{t as _e}from"./cli-grammar.js";import{i as ve}from"./auth-session.js";import E from"node:fs";import{pathToFileURL as ye}from"node:url";const D=`open <app> --relaunch`,O={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 k(e){if(e.length<=2)return[];let t=f(),n=t.filter(t=>t.startsWith(e));if(n.length>0)return n.sort((e,t)=>e.length-t.length||e.localeCompare(t)).slice(0,3);let r=A(e),i=t.map(t=>({name:t,distance:j(e,t)})).filter(e=>e.distance<=r);if(i.length===0)return[];let a=Math.min(...i.map(e=>e.distance));return i.filter(e=>e.distance===a).sort((e,t)=>e.name.localeCompare(t.name)).slice(0,3).map(e=>e.name)}function A(e){return e.length<4?1:e.length<=6?2:3}function j(e,t){return e===t?0:e.startsWith(t)||t.startsWith(e)?Math.abs(e.length-t.length):M(e,t)}function M(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 N(e){let t=e.toLowerCase(),n=O[t]?.example;if(n)return n;let r=k(t);if(r.length!==0)return r.length===1?r[0]:`one of: ${r.join(`, `)}`}const P=new Set([`--bundle-id`,`--bundleid`,`--bundle`,`--package`,`--package-name`,`--packagename`,`--app-id`,`--appid`,`--pkg`]),be=new Set([`--session-locked`,`--session-lock-conflicts`]);function xe(e){return P.has(e.toLowerCase())?`Unknown flag: ${e}. The app or bundle id is a positional argument, e.g. ${D}.`:be.has(e.toLowerCase())?`Unknown flag: ${e}. Use --session-lock reject|strip instead.`:e.toLowerCase()===i.cliToken?`Unknown flag: ${e}. ${i.migration.screenshot}. ${i.migration.record}.`:`Unknown flag: ${e}`}function F(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=B(l));continue}if(Te(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=B(l));continue}let[f,p]=u?I(l):[l,void 0];if(Ce(r,f))continue;let m=Ee(f,r);if(we(r,m)){a.push(l);continue}if(!m){if(je(r,a,l)){r?a.push(l):r=l;continue}throw new n(`INVALID_ARGS`,xe(f))}let h=ke(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 Se(i,t),{command:r,positionals:a,flags:t,warnings:o,providedFlags:s}}function Se(e,t){if(e)for(let n of x(e)?.impliedFlags??[])t[n]=!0}function Ce(e,t){return t===`-c`&&(e===`snapshot`||e===`diff`)}function we(e,t){return e===`react-devtools`?t?!C(t.key,e):!0:!1}function Te(e){return e===`cdp`}function Ee(e,t){let n=h().filter(t=>t.names.includes(e));if(n.length<=1)return n[0]??g(e);if(t){let e=n.find(e=>C(e.key,t));if(e)return e}return g(e)}function De(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&&!p(e.command)&&!a.help){let t=N(e.command);throw new n(`INVALID_ARGS`,t?`Unknown command: ${e.command}. Did you mean ${t}?`:`Unknown command: ${e.command}`)}let o=e.providedFlags.filter(t=>!C(t.key,e.command));if(o.length>0){let t=o.map(e=>e.token),s=Pe(e.command,t);if(r)throw new n(`INVALID_ARGS`,s);i.push(s);for(let e of o)delete a[e.key]}for(let t of Object.keys(a))a[t]!==void 0&&(C(t,e.command)||delete a[t]);Oe(e),se(e.command,a);let s=Ne({command:e.command,positionals:e.positionals,flags:a,warnings:i});if(S(s.command,s.positionals),s.command===`batch`&&+!!a.steps+ +!!a.stepsFile!=1)throw new n(`INVALID_ARGS`,`batch requires exactly one step source: --steps or --steps-file.`);return s}function Oe(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 I(e){let t=e.indexOf(`=`);return t===-1?[e,void 0]:[e.slice(0,t),e.slice(t+1)]}function ke(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||R(i)?{value:!0,consumeNext:!1}:Ae(i)?{value:i,consumeNext:!0}:{value:!0,consumeNext:!1}}let a=r??i;if(a===void 0||r===void 0&&R(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 ${L(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 ${L(t)}: ${a}`);return{value:e.type===`int`?Math.floor(o):o,consumeNext:r===void 0}}function L(e){return e.replace(/^-+/,``)}function R(e){if(!e.startsWith(`-`)||e===`-`)return!1;let[t]=e.startsWith(`--`)?I(e):[e,void 0];return g(t)!==void 0}function Ae(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 je(e,t,n){if(!Me(n)||!e)return!1;let r=oe(e);if(!r||r.allowsExtraPositionals)return!0;let i=r.positionalArgs??[];return i.length===0?!1:t.length<i.length?!0:i.some(e=>e.includes(`?`))}function Me(e){return/^-\d+(\.\d+)?$/.test(e)}function Ne(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 Pe(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 z(){let{buildUsageText:e}=await import(`./cli-help.js`);return e()}async function Fe(e){let{buildCommandUsageText:t}=await import(`./cli-help.js`);return t(B(e))}function B(e){if(e.toLowerCase()===`rotate`)throw new n(`INVALID_ARGS`,`rotate was renamed to orientation; for the two-finger gesture use: gesture rotate`);return ae(e)}function Ie(e){return _(e)}const Le={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,daemon:async()=>(await import(`./daemon.js`)).daemonCommand,device:async()=>(await import(`./device2.js`)).deviceCommand,proxy:async()=>(await import(`./proxy.js`)).proxyCommand,replay:async()=>(await import(`./replay.js`)).replayCommand,screenshot:async()=>(await import(`./screenshot.js`)).screenshotCommand,diff:async()=>(await import(`./screenshot.js`)).diffCommand};async function V(e){let t={...e.flags},n=Le[e.command];return n&&await(await n())({...e,flags:t})?!0:Ie(e.command)?await Re({...e,command:e.command,flags:t}):!1}async function Re(e){let{runGenericClientBackedCommand:t}=await import(`./generic.js`);return await t(e)}function ze(e){return[`exec`,`--yes`,`--package`,`agent-react-devtools@0.4.0`,`--`,`agent-react-devtools`,...e]}function Be(e){return e===`ios-instance`}function Ve(e){return e[0]===`wait`&&e.includes(`--connected`)}function He(e,t,n){n===0||!Ve(e)||!Be(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
|
+
`))}function H(e,t,n){return n||(e.push(t),``)}function Ue(e){if(!e?.metroProxyBaseUrl||!pe(e.leaseBackend))return null;let t=[],r={serverBaseUrl:H(t,`metroProxyBaseUrl`,e.metroProxyBaseUrl),bearerToken:H(t,`metroBearerToken`,e.metroBearerToken),tenantId:H(t,`tenant`,e.tenant),runId:H(t,`runId`,e.runId),leaseId:H(t,`leaseId`,e.leaseId)};if(t.length>0)throw new n(`INVALID_ARGS`,`react-devtools remote bridge requires ${t.join(`, `)}.`,{missing:t});return r}async function We(e,t,n){let{flags:r}=t,i=Ue(r);if(!i)return n();let a=t.stateDir??process.cwd(),o=t.session??r?.session??`default`,s=r?.remoteConfig??`${i.tenantId}:${i.runId}:${i.leaseId}`;if(e[0]===`stop`)try{return await n()}finally{await ue({projectRoot:t.cwd??process.cwd(),stateDir:a,profileKey:s,consumerKey:o})}return await de({projectRoot:t.cwd??process.cwd(),stateDir:a,serverBaseUrl:i.serverBaseUrl,bearerToken:i.bearerToken,bridgeScope:{tenantId:i.tenantId,runId:i.runId,leaseId:i.leaseId},session:o,profileKey:s,consumerKey:o,env:t.env??process.env}),await n()}function Ge(e,t){if(e[0]!==`start`)return!1;let{flags:n}=t;return n?n.leaseProvider===`limrun`&&n.leaseBackend===`android-instance`&&n.metroProxyBaseUrl===void 0&&t.configureDirectPortReverse!==void 0:!1}async function Ke(e,t={}){let n=t.cwd??process.cwd(),r=t.env??process.env,i=await We(e,t,async()=>(Ge(e,t)&&await t.configureDirectPortReverse?.(),(await re(`npm`,ze(e),{cwd:n,env:r,allowFailure:!0,onStdoutChunk:e=>{process.stdout.write(e)},onStderrChunk:e=>{process.stderr.write(e)}})).exitCode));return He(e,t.flags,i),i}async function qe(e,t){switch(e[0]){case`setup`:{Je(t.flags.json);let{setupManagedAgentBrowser:e}=await import(`./agent-browser-tool.js`).then(e=>e.t),n=await e({stateDir:t.stateDir});return Ye(t.flags.json,n),0}case`doctor`:{let{doctorManagedAgentBrowser:e}=await import(`./agent-browser-tool.js`).then(e=>e.t),n=await e({stateDir:t.stateDir});return Xe(t.flags.json,n.exitCode===0?`Web backend is healthy.`:`Web backend doctor reported issues.`,n),n.exitCode}default:throw new n(`INVALID_ARGS`,`web requires setup or doctor`)}}function Je(e){e||process.stdout.write(`Setting up managed agent-browser backend (downloads if needed)...
|
|
3
|
+
`)}function Ye(e,t){if(e){s({success:!0,data:{status:U(t)}});return}process.stdout.write(`Managed web backend installed.\nagent-browser available at: ${t.binaryPath}\n`)}function Xe(e,t,n){if(e){s({success:!0,data:Ze(n)});return}process.stdout.write(`${t}\n`)}function U(e){let{socketDir:t,...n}=e;return n}function Ze(e){let t=e.status;return Qe(t)?{...e,status:U(t)}:e}function Qe(e){return typeof e==`object`&&!!e&&`socketDir`in e&&`installDir`in e&&`binaryPath`in e}function $e(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 et(t)}function et(e){let t=!1,n=e.map((e,n)=>{if(nt(e))return rt(e,n+1);let r=it(e,n+1);return t=!0,tt(r)});return t&&process.stderr.write(`Warning: batch steps using positionals/flags are deprecated and will be removed in the next major version. Use {"command":"...","input":{...}} steps instead.
|
|
4
|
+
`),n}function tt(e){let t=_e(e.command,e.positionals??[],lt(e.flags));return{command:e.command,input:t,...e.runtime===void 0?{}:{runtime:e.runtime}}}function nt(e){return a(e)&&`input`in e&&!(`positionals`in e)&&!(`flags`in e)}function rt(e,t){let n=o(e.runtime,t),{runtime:r,...i}=e;return{...i,...n===void 0?{}:{runtime:n}}}function it(e,t){if(!a(e))throw new n(`INVALID_ARGS`,`Invalid batch step ${t}.`);ot(e,t);let r=at(e.command,t),i=st(e.positionals,t);S(r,i??[],`Batch step ${t}`);let s=ct(e.flags,t),c=o(e.runtime,t);return{command:r,...i===void 0?{}:{positionals:i},...s===void 0?{}:{flags:s},...c===void 0?{}:{runtime:c}}}function at(e,t){let r=typeof e==`string`?e.trim().toLowerCase():``;if(!r)throw new n(`INVALID_ARGS`,`Batch step ${t} requires command.`);if(_(r))return r;throw new n(`INVALID_ARGS`,`Batch step ${t} command is not available through command batch: ${String(e)}`)}function ot(e,t){let r=Object.keys(e).filter(e=>![`command`,`positionals`,`flags`,`runtime`].includes(e));if(r.length>0)throw new n(`INVALID_ARGS`,`Batch step ${t} has unknown legacy field(s): ${r.join(`, `)}.`)}function st(e,t){if(e!==void 0){if(!Array.isArray(e)||e.some(e=>typeof e!=`string`))throw new n(`INVALID_ARGS`,`Batch step ${t} positionals must contain only strings.`);return e}}function ct(e,t){if(e!==void 0){if(!a(e))throw new n(`INVALID_ARGS`,`Batch step ${t} flags must be an object.`);return e}}function lt(e){return{json:!1,help:!1,version:!1,...e}}function W(e,t={}){let n=G(t),r={...e};return n.defaultPlatform&&r.platform===void 0&&(r.platform=n.defaultPlatform),r}function G(e){let t=e.env??process.env,n=e.inheritedPlatform??e.configuredPlatform??dt(t.AGENT_DEVICE_PLATFORM),r=pt(e.configuredSession??t.AGENT_DEVICE_SESSION);return{defaultPlatform:n,lockPolicy:ut(e.policyOverrides,t,r)}}function ut(e,t,n){let r=e?.sessionLock??ft(t.AGENT_DEVICE_SESSION_LOCK);if(r)return r;if(n)return`reject`}function dt(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 ft(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 pt(e){return typeof e==`string`&&e.trim().length>0}function mt(e,t){let n=F(e),r=t?.env??process.env,i=t?.cwd??process.cwd(),a=ht(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{...De(n,{strictFlags:t?.strictFlags,defaultFlags:o}),providedFlags:n.providedFlags}}function ht(e){return e!==null}m.runtime;async function gt(e){let{command:t,request:n,transport:r,transportOptions:i}=e;return await r({...n,command:t},i)}const _t={sendToDaemon:u},vt=new Set([`launchUrl`,`kind`,`metroBearerToken`,`metroKind`,`metroListenHost`,`metroNoInstallDeps`,`metroNoReuseExisting`,`metroPreparePort`,`metroProbeTimeoutMs`,`metroProjectRoot`,`metroProxyBaseUrl`,`metroPublicBaseUrl`,`metroRuntimeFile`,`metroStartupTimeoutMs`,`metroStatusHost`]),yt=new Set([`connect`,`connection`,`close`,`daemon`,`device`,`disconnect`,`metro`,`proxy`,`session`]);async function K(e,t=_t){let n=ne(),r=ie(),i=kt(e),a=e.includes(`--json`);await ee({session:Vt(e)??process.env.AGENT_DEVICE_SESSION??`default`,requestId:n,command:e[0],debug:i},async()=>{let{parsed:o,command:s,positionals:c}=await bt(e,{version:r,jsonRequested:a,debugEnabled:i}),u=X(s,o.providedFlags),d=await xt(o,{command:s,positionals:c,requestId:n,debugOutputEnabled:u});q(d.effectiveFlags);let f=null;try{if(s===`react-devtools`){await T(await St(d,t));return}if(s===`web`){await T(await qe(c,{flags:d.effectiveFlags,stateDir:d.daemonPaths.baseDir}));return}if(ce({command:s,currentVersion:r,stateDir:d.daemonPaths.baseDir,flags:d.effectiveFlags}),await Ct(d,t),q(d.effectiveFlags),s===`cdp`){await T(await ge(c,{flags:d.effectiveFlags,runtime:d.resolvedRuntime,cwd:process.cwd(),env:process.env}));return}f=wt(d);let e=await Tt(d);await Et(d,l(J(d),{transport:Bt({command:s,flags:d.effectiveFlags,replayTestReporterRuntime:e,transport:t.sendToDaemon})}),e)}catch(e){await Dt(e,d,f)}finally{f&&f()}})}function q(e){e.daemonAuthToken&&te(e.daemonAuthToken)}async function bt(t,r){let i;try{i=mt(t,{cwd:process.cwd(),env:process.env})}catch(t){v({level:`error`,phase:`cli_parse_failed`,data:{error:t instanceof Error?t.message:String(t)}});let n=e(t,{diagnosticId:y().diagnosticId,logPath:b({force:!0})??void 0});return r.jsonRequested?s({success:!1,error:n}):c(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 c(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 z()}\n`),T(0);let t=await Fe(e);return t?(process.stdout.write(t),T(0)):(c(new n(`INVALID_ARGS`,At(e))),process.stdout.write(`${await z()}\n`),T(1))}return i.command?{parsed:i,command:i.command,positionals:i.positionals}:(process.stdout.write(`${await z()}\n`),T(1))}async function xt(t,n){let i=new Set(t.providedFlags.map(e=>e.key));try{let e=G({policyOverrides:t.flags,configuredPlatform:t.flags.platform,configuredSession:t.flags.session}),r=e.lockPolicy?{...t.flags}:W(t.flags,{policyOverrides:t.flags,configuredPlatform:t.flags.platform,configuredSession:t.flags.session}),a=d(r.stateDir),o=r.session??`default`,s=Pt({command:n.command,explicitFlagKeys:i,stateDir:a.baseDir,session:o,remoteConfig:r.remoteConfig,hasResolvedSession:r.session!==void 0}),c=s?Rt(r,s.flags,i):r;return{...n,binding:e,flags:r,daemonPaths:a,sessionName:o,connectionDefaults:s,explicitFlagKeys:i,effectiveFlags:c,resolvedRuntime:s?.runtime,connectionMetadata:s?.connection,parsedBatchSteps:void 0}}catch(i){let a=e(r(i),{diagnosticId:y().diagnosticId,logPath:b({force:!0})??void 0});return t.flags.json?s({success:!1,error:a}):c(a,{showDetails:n.debugOutputEnabled}),T(1)}}async function St(e,n){let{daemonAuthToken:r,...i}=e.effectiveFlags;return await Ke(e.positionals,{flags:{...i,leaseProvider:e.connectionDefaults?.connection?.leaseProvider},stateDir:e.daemonPaths.baseDir,session:e.effectiveFlags.session??e.sessionName,cwd:process.cwd(),env:process.env,configureDirectPortReverse:async()=>{let a=await gt({route:`react-devtools`,command:m.runtime,request:{positionals:[`port-reverse`],flags:{...i,leaseProvider:e.connectionDefaults?.connection?.leaseProvider,devicePort:8097,hostPort:8097,portReverseName:`react-devtools`},session:e.effectiveFlags.session??e.sessionName},transport:n.sendToDaemon,transportOptions:{authToken:r}});a.ok||t(a.error)}})}async function Ct(e,t){if(e.command===`batch`){if(e.positionals.length>0)throw new n(`INVALID_ARGS`,`batch does not accept positional arguments.`);e.parsedBatchSteps=Mt(e.flags)}if(Ft(e.command)&&(e.effectiveFlags=(await ve({command:e.command,flags:e.effectiveFlags,stateDir:e.daemonPaths.baseDir,env:process.env})).flags),e.effectiveFlags.remoteConfig&&Z(e.command)){let n=l(J(e),{transport:Q(t.sendToDaemon)}),r=await he({command:e.command,flags:e.effectiveFlags,client:n,runtime:e.resolvedRuntime,positionals:e.positionals,batchSteps:e.parsedBatchSteps,forceRuntimePrepare:zt(e.explicitFlagKeys)});e.effectiveFlags=r.flags,e.resolvedRuntime=r.runtime,e.connectionMetadata=r.connection}It({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.
|
|
5
|
+
`)}function J(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,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 wt(e){let t=e.effectiveFlags.daemonBaseUrl;return e.debugOutputEnabled&&!e.effectiveFlags.json&&!t?Ht(e.daemonPaths.logPath):null}async function Tt(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 Et(e,t,r){let{command:i,positionals:a,effectiveFlags:o}=e;if(i===`batch`){if(!e.parsedBatchSteps)throw new n(`INVALID_ARGS`,`batch requires --steps or --steps-file.`);let s=e.parsedBatchSteps.map((t,n)=>({...t,input:e.binding.lockPolicy&&e.flags.platform===void 0?{...t.input}:W(t.input,{policyOverrides:o,configuredPlatform:o.platform,configuredSession:o.session,inheritedPlatform:o.platform})}));if(await V({command:i,positionals:a,flags:{...o,batchSteps:s},client:t,debug:e.debugOutputEnabled,replayTestReporterRuntime:r}))return}else if(i===`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 V({command:i,positionals:a,flags:o,client:t,debug:e.debugOutputEnabled,replayTestReporterRuntime:r}))return;throw new n(`INVALID_ARGS`,jt(i))}async function Dt(t,n,i){let a=r(t),o=e(a,{diagnosticId:y().diagnosticId,logPath:b({force:!0})??void 0});if(n.command===`close`&&Nt(a)){n.effectiveFlags.json&&s({success:!0,data:{closed:`session`,source:`no-daemon`}});return}n.effectiveFlags.json?s({success:!1,error:o}):(c(o,{showDetails:n.debugOutputEnabled}),n.debugOutputEnabled&&Ot(n.daemonPaths.logPath)),i&&i(),await T(1)}const Y=64e3;function Ot(e){try{if(E.existsSync(e)){let t=E.readFileSync(e,`utf8`).split(`
|
|
6
6
|
`),n=t.slice(Math.max(0,t.length-200)).join(`
|
|
7
|
-
`);n.length>Y&&(n=n.slice(n.length-Y)),n.trim().length>0&&process.stderr.write(`\n[daemon log]\n${n}\n`)}}catch{}}function
|
|
7
|
+
`);n.length>Y&&(n=n.slice(n.length-Y)),n.trim().length>0&&process.stderr.write(`\n[daemon log]\n${n}\n`)}}catch{}}function kt(e){try{let t=F(e);return X(t.command??``,t.providedFlags)}catch{return e.includes(`--debug`)||e.includes(`-v`)||e.includes(`--verbose`)}}function At(e){let t=N(e);return t?`Unknown command: ${e}. Did you mean ${t}?`:`Unknown command: ${e}`}function jt(e){return p(e)?(v({level:`error`,phase:`cli_known_command_unhandled`,data:{command:e}}),`Command is registered but no CLI handler accepted it: ${e}`):`Unknown command: ${e}`}function X(e,t){return t.some(t=>t.key===`verbose`&&(t.token===`--debug`||t.token===`-v`||e!==`test`))}function Mt(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 $e(t)}function Nt(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 Pt(e){return e.command===`connect`||e.command===`connection`||e.command===`daemon`||e.command===`proxy`?null:fe({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 Z(e){return!yt.has(e)}function Ft(e){return e!==`auth`&&e!==`connection`&&e!==`daemon`&&e!==`device`&&e!==`proxy`}function It(e){return e.command!==`open`||e.runtime||e.flags.bundleUrl||e.flags.metroHost||e.flags.metroPort||e.flags.remoteConfig||e.hadConnectionDefaults?!1:Lt(e.explicitFlagKeys)}function Lt(e){return e.has(`daemonBaseUrl`)||e.has(`daemonTransport`)||e.has(`tenant`)||e.has(`sessionIsolation`)||e.has(`runId`)||e.has(`leaseId`)||e.has(`leaseBackend`)}function Rt(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 zt(e){for(let t of vt)if(e.has(t))return!0;return!1}function Bt(e){let{command:t,flags:n,replayTestReporterRuntime:r,transport:i}=e;return n.json?Q(i):async(e,n)=>{let a=t===`test`&&r?{...n,onProgress:r.onProgress}:n;return await $(i,{...e,meta:{...e.meta,requestProgress:t===`test`?`replay-test`:`command`}},a)}}function Q(e){return async(t,n)=>await $(e,t,n)}async function $(e,t,n){return await e(t,n)}function Vt(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}ye(process.argv[1]??``).href===import.meta.url&&K(process.argv.slice(2)).catch(async t=>{c(e(r(t)),{showDetails:!0}),await T(1)});function Ht(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{K as runCli};
|
package/dist/src/client-metro.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{_ as e,v as t}from"./sdk-contracts.js";import{C as n,b as r}from"./sdk-android-adb.js";import{n as i}from"./path-resolution.js";import{t as a}from"./timeouts.js";import{c as o,d as s,n as c,s as l}from"./host-process.js";import{a as u,c as d,d as f,f as ee,g as te,h as p,i as ne,l as re,m as ie,n as m,o as h,p as g,s as ae,t as oe,u as se}from"./url.js";import{a as ce,i as le,t as ue}from"./runtime-transport.js";import _ from"node:path";import{createHash as de}from"node:crypto";import v from"node:fs";import{fileURLToPath as fe}from"node:url";const y=`companion-tunnel`;function b(e){return de(`sha256`).update(e).digest(`hex`)}function x(e){return e?.trim()?e.trim():void 0}function pe(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 me(e,t){return e.tenantId===t.tenantId&&e.runId===t.runId&&e.leaseId===t.leaseId}function S(e,t,n,r){let i=r??_.join(e,`.agent-device`);if(!n)return{statePath:_.join(i,`${t.slug}.json`),logPath:_.join(i,`${t.slug}.log`)};let a=b(n).slice(0,12),o=_.join(i,t.slug);return{statePath:_.join(o,`${t.slug}-${a}.json`),logPath:_.join(o,`${t.slug}-${a}.log`)}}function C(e){try{let t=JSON.parse(v.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:x(typeof t.launchUrl==`string`?t.launchUrl:void 0),registerPath:x(typeof t.registerPath==`string`?t.registerPath:void 0),unregisterPath:x(typeof t.unregisterPath==`string`?t.unregisterPath:void 0),devicePort:Number.isInteger(t.devicePort)?Number(t.devicePort):void 0,session:x(typeof t.session==`string`?t.session:void 0),bridgeScope:pe(t.bridgeScope),tokenHash:t.tokenHash,consumers:n}}catch{return null}}function w(e,t){v.mkdirSync(_.dirname(e),{recursive:!0}),v.writeFileSync(e,`${JSON.stringify(t,null,2)}\n`,`utf8`)}function he(e){v.mkdirSync(_.dirname(e),{recursive:!0}),v.closeSync(v.openSync(e,`a`))}function ge(e){try{v.unlinkSync(e)}catch{}}function _e(e){try{v.unlinkSync(e)}catch{}}function T(e){try{v.readdirSync(e).length===0&&v.rmdirSync(e)}catch{}}function E(e,t){let n=_.dirname(e.statePath),r=_.dirname(e.logPath);ge(e.statePath),_e(e.logPath),T(n),r!==n&&T(r),_.basename(n)===t.slug&&T(_.dirname(n))}function D(e,t){return e.includes(t.runArg)}function ve(e,t){if(!c(e.pid))return!1;if(e.startTime){let t=o(e.pid);if(!t||t!==e.startTime)return!1}let n=l(e.pid);return!n||!D(n,t.definition)||!e.bridgeScope?!1:e.serverBaseUrl===m(t.serverBaseUrl)&&e.localBaseUrl===m(t.localBaseUrl)&&e.launchUrl===x(t.launchUrl)&&e.registerPath===x(t.registerPath)&&e.unregisterPath===x(t.unregisterPath)&&e.devicePort===t.devicePort&&e.session===x(t.session)&&me(e.bridgeScope,t.bridgeScope)&&e.tokenHash===b(t.bearerToken)}function O(e){return x(e.consumerKey)??x(e.profileKey)??null}function k(e,t){return!t||e.consumers.includes(t)?e:{...e,consumers:[...e.consumers,t]}}function ye(e,t){return t?{...e,consumers:e.consumers.filter(e=>e!==t)}:{...e,consumers:[]}}async function A(e,t){if(!c(e.pid))return;let n=l(e.pid);if(!(!n||!D(n,t))){try{process.kill(e.pid,`SIGTERM`)}catch(e){let t=e.code;if(t===`ESRCH`||t===`EPERM`)return;throw e}if(!await s(e.pid,1e3)){try{process.kill(e.pid,`SIGKILL`)}catch(e){let t=e.code;if(t===`ESRCH`||t===`EPERM`)return;throw e}await s(e.pid,1e3)}}}function be(e,t){let n={...t};return n[ee]=m(e.serverBaseUrl),n[ne]=e.bearerToken,n[ae]=m(e.localBaseUrl),n[ie]=S(e.projectRoot,e.definition,e.profileKey,e.stateDir).statePath,n[f]=e.bridgeScope.tenantId,n[se]=e.bridgeScope.runId,n[re]=e.bridgeScope.leaseId,e.launchUrl?.trim()?n[h]=e.launchUrl.trim():delete n[h],e.registerPath?.trim()?n[d]=e.registerPath.trim():delete n[d],e.unregisterPath?.trim()?n[p]=e.unregisterPath.trim():delete n[p],e.devicePort===void 0?delete n[u]:n[u]=String(e.devicePort),e.session?.trim()?n[g]=e.session.trim():delete n[g],n}function xe(e){let t=fe(import.meta.url),n=_.extname(t)||`.js`,r=[_.join(_.dirname(t),`${y}${n}`),_.join(_.dirname(t),`internal`,`${y}${n}`)].find(e=>v.existsSync(e));if(!r)throw Error(`${e.displayName} entrypoint not found. Rebuild the package to include the companion worker entry.`);return r}function Se(e,t){let n=xe(e.definition),i=n.endsWith(`.ts`)?[`--experimental-strip-types`]:[];v.mkdirSync(_.dirname(t),{recursive:!0});let a=v.openSync(t,`a`),s=0;try{s=r(process.execPath,[...i,n,e.definition.runArg],{env:be(e,e.env??process.env),stdio:[`ignore`,a,a]})}finally{v.closeSync(a)}if(!Number.isInteger(s)||s<=0)throw Error(`Failed to start ${e.definition.displayName} process.`);return{pid:s,startTime:o(s)??void 0,command:l(s)??void 0,serverBaseUrl:m(e.serverBaseUrl),localBaseUrl:m(e.localBaseUrl),launchUrl:x(e.launchUrl),registerPath:x(e.registerPath),unregisterPath:x(e.unregisterPath),devicePort:e.devicePort,session:x(e.session),bridgeScope:e.bridgeScope,tokenHash:b(e.bearerToken),consumers:[]}}async function j(e){let t=O(e),n=S(e.projectRoot,e.definition,e.profileKey,e.stateDir),r=C(n.statePath);if(r&&ve(r,e)){let e=k(r,t);return e!==r&&w(n.statePath,e),{pid:r.pid,spawned:!1,statePath:n.statePath,logPath:n.logPath}}r&&(await A(r,e.definition),E(n,e.definition)),he(n.statePath);let i;try{i=Se(e,n.logPath),w(n.statePath,k(i,t))}catch(t){throw i&&await A(i,e.definition).catch(()=>{}),E(n,e.definition),t}return{pid:i.pid,spawned:!0,statePath:n.statePath,logPath:n.logPath}}async function M(e){let t=O(e),n=S(e.projectRoot,e.definition,e.profileKey,e.stateDir),r=C(n.statePath);if(!r)return E(n,e.definition),{stopped:!1,statePath:n.statePath};let i=ye(r,t);return i.consumers.length>0?(w(n.statePath,i),{stopped:!1,statePath:n.statePath}):(await A(r,e.definition),E(n,e.definition),{stopped:!0,statePath:n.statePath})}const N={slug:`metro-companion`,runArg:te,displayName:`Metro companion`};async function Ce(e){return await j({...e,definition:N,registerPath:e.registerPath??`/api/metro/companion/register`})}async function we(e){return await M({...e,definition:N})}const P=8081,F=`.expo/.virtual-metro-entry.bundle`;function I(t,n){if(t==null||t===``)return n;let r=Number.parseInt(String(t),10);if(!Number.isInteger(r)||r<1||r>65535)throw new e(`INVALID_ARGS`,`Invalid Metro port: ${String(t)}. Use 1-65535.`);return r}function Te(t){let n=R(t.bundleUrl),r=n??t.runtime?.bundleUrl,i=!!n,a=!!R(r),o=ue({metroHost:Ee(t,i,a),metroPort:De(t,i,a),bundleUrl:r});if(!o)throw new e(`INVALID_ARGS`,`Unable to resolve Metro host and port for reload.`);let s=Oe(r);return{reloadUrl:L(o,o.scheme,`${s}/reload`),messageSocketUrl:L(o,o.scheme===`https`?`wss`:`ws`,`${s}/message`)}}function Ee(e,t,n){return R(e.metroHost)??(t?void 0:R(e.runtime?.metroHost))??(n?void 0:`localhost`)}function De(e,t,n){if(e.metroPort!==void 0)return I(e.metroPort,P);if(!t)return e.runtime?.metroPort??(n?void 0:P)}function Oe(e){let t=R(e);if(!t)return``;let n;try{n=new URL(t)}catch{return``}let r=n.pathname.replace(/\/+$/,``),i=`/${F}`;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 L(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 R(e){return typeof e==`string`&&e.trim()?e.trim():void 0}function z(e){return typeof e==`string`&&e.trim()?m(e.trim()):``}function B(e){return typeof e==`string`&&e.trim()?e.trim():void 0}function V(e,t,n){return i(e,{env:t,cwd:n})}function H(e){try{return v.accessSync(e,v.constants.F_OK),!0}catch{return!1}}function ke(e){try{return v.statSync(e).isDirectory()}catch{return!1}}function U(t){let n=_.join(t,`package.json`),r=ce(t);if(!r)throw new e(`INVALID_ARGS`,`package.json not found at ${n}`);return r}const Ae=[{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 je(e){let t=e;for(;;){for(let{file:e,command:n}of Ae)if(H(_.join(t,e)))return{command:n,installArgs:[`install`]};if(H(_.join(t,`.git`)))return null;let e=_.dirname(t);if(e===t)return null;t=e}}function Me(e){return je(e)??{command:`npm`,installArgs:[`install`]}}function Ne(e,t){if(t!==`auto`)return t;let n=le(e);return n===`expo`||n===`repack`?n:`react-native`}function W(e,t){return typeof{...e.dependencies??{},...e.devDependencies??{}}[t]==`string`}function G(e,t){return[`js`,`mjs`,`cjs`,`ts`,`mts`,`cts`].some(n=>H(_.join(e,`${t}.config.${n}`)))}function Pe(e,t){return G(e,`rspack`)?`rspack`:G(e,`webpack`)?`webpack`:W(t,`@rspack/core`)?`rspack`:W(t,`webpack`)?`webpack`:`rspack`}function K(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 Fe(e){return e===`expo`?F:`index.bundle`}function q(e,t,n){return{platform:t,bundleUrl:oe(e,t,Fe(n))}}function J(e,t){return{platform:t,metroHost:B(e?.metro_host),metroPort:e?.metro_port,bundleUrl:B(e?.metro_bundle_url),launchUrl:B(e?.launch_url)}}function Ie(e,t){if(ke(_.join(e,`node_modules`)))return{installed:!1};let r=Me(e);try{n(r.command,r.installArgs,{cwd:e,env:t})}catch(e){throw Le(e,r)}return{installed:!0,packageManager:r.command}}function Le(n,r){let i=t(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 e(i.code,i.message,{...i.details??{},hint:a,packageManager:r.command},i)}async function Y(e){await a(e)}async function X(t,n,r={}){try{let e=await fetch(t,{headers:r,signal:AbortSignal.timeout(n)});return{ok:e.ok,status:e.status,body:await e.text()}}catch(r){throw r instanceof Error&&r.name===`TimeoutError`?new e(`COMMAND_FAILED`,`Timed out fetching ${t} after ${n}ms`):r}}async function Re(e,t){try{let n=await X(e,t);return n.ok&&n.body.includes(`packager-status:running`)}catch{return!1}}function ze(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 Be(t,n,i,a,o,s,c){let l=ze(n,i,a,o);v.mkdirSync(_.dirname(s),{recursive:!0});let u=v.openSync(s,`a`),d=0;try{d=r(l.command,l.installArgs,{cwd:t,env:c,stdio:[`ignore`,u,u]})}finally{v.closeSync(u)}if(!Number.isInteger(d)||d<=0)throw new e(`COMMAND_FAILED`,`Failed to start React Native dev server. Expected a detached child PID.`);return{pid:d}}async function Ve(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 s(e,1e3)){try{process.kill(e,`SIGKILL`)}catch(e){let t=e.code;if(t===`ESRCH`||t===`EPERM`)return;throw e}await s(e,1e3)}}}function He(e,t){return{Authorization:`Bearer ${t}`,"Content-Type":`application/json`,...e.includes(`ngrok`)?{"ngrok-skip-browser-warning":`1`}:{}}}function Z(t,n){let r=new e(`COMMAND_FAILED`,t);return r.retryable=n,r}function Ue(e,t){return!!(e>=500||e===408||e===425||e===429||JSON.stringify(t).includes(`Metro companion is not connected`))}function We(e){return!!(e&&typeof e==`object`&&`retryable`in e&&e.retryable===!0)}async function Q(e){let t;try{t=await fetch(`${e.baseUrl}/api/metro/bridge`,{method:`POST`,headers:He(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`?Z(`/api/metro/bridge timed out after ${e.timeoutMs}ms calling ${e.baseUrl}/api/metro/bridge`,!0):Z(t instanceof Error?t.message:String(t),!0)}let n=Ge(await t.text(),t.status,e.baseUrl);if(!t.ok)throw Z(`/api/metro/bridge failed (${t.status}): ${JSON.stringify(n)}`,Ue(t.status,n));return qe(n)}function Ge(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 Z(`/api/metro/bridge returned invalid JSON (${t}) from ${n}: ${r instanceof Error?r.message:String(r)}. body=${JSON.stringify(i)}`,Ue(t,e))}}function Ke(e){return{enabled:e.enabled,baseUrl:e.base_url,statusUrl:e.status_url??``,bundleUrl:e.bundle_url??``,iosRuntime:J(e.ios_runtime,`ios`),androidRuntime:J(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 qe(e){let t=e.data??e;if(!t||typeof t!=`object`||Array.isArray(t))throw Z(`/api/metro/bridge returned malformed descriptor: Expected a JSON object.`,!1);try{return Ke(t)}catch(e){throw Z(`/api/metro/bridge returned malformed descriptor: ${e instanceof Error?e.message:String(e)}`,!1)}}function $(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 Je(t,n){if(!n?.iosRuntime.bundleUrl)throw new e(`COMMAND_FAILED`,$(t,`bridge descriptor is missing ios_runtime.metro_bundle_url`,n))}function Ye(t,n,r){let i=n||B(r.AGENT_DEVICE_METRO_BEARER_TOKEN)||``,a=i||t&&B(r.AGENT_DEVICE_DAEMON_AUTH_TOKEN)||``;if(t&&!a)throw new e(`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(!t&&i)throw new e(`INVALID_ARGS`,`metro prepare requires --proxy-base-url when proxy auth is provided.`);return{proxyEnabled:!!(t&&a),proxyBaseUrl:t,proxyBearerToken:a}}function Xe(t){if(!t?.tenantId||!t.runId||!t.leaseId)throw new e(`INVALID_ARGS`,`metro prepare with proxy requires tenantId, runId, and leaseId bridge scope.`);return t}function Ze(t,n){if(!(t||n))throw new e(`INVALID_ARGS`,`metro prepare requires --public-base-url <url> or --proxy-base-url <url>.`)}function Qe(e,t,n){return e.runtimeFilePath?V(e.runtimeFilePath,t,n):null}function $e(e,t,n,r){return V(e.logPath??_.join(r,`.agent-device`,`metro.log`),t,n)}function et(e){let t=e.env??process.env,n=process.cwd(),r=V(e.projectRoot??n,t,n),i=e.kind??`auto`,a=null,o;i===`auto`?(a=U(r),o=Ne(a,i)):o=i;let s=null;o===`repack`&&(a??=U(r),s=Pe(r,a));let c=z(e.publicBaseUrl),l=z(e.proxyBaseUrl);Ze(c,l);let{proxyEnabled:u,proxyBaseUrl:d,proxyBearerToken:f}=Ye(l,B(e.proxyBearerToken)??``,t);return{env:t,projectRoot:r,kind:o,repackBundler:s,metroPort:I(e.metroPort??8081,8081),listenHost:B(e.listenHost)??`0.0.0.0`,statusHost:B(e.statusHost)??`127.0.0.1`,publicBaseUrl:c,proxyBaseUrl:d,proxyBearerToken:f,bridgeScope:u?Xe(e.bridgeScope):null,startupTimeoutMs:K(e.startupTimeoutMs,18e4,3e4),probeTimeoutMs:K(e.probeTimeoutMs,1e4,1e3),reuseExisting:e.reuseExisting??!0,installProjectDeps:e.installDependenciesIfNeeded??!0,runtimeFilePath:Qe(e,t,n),logPath:$e(e,t,n,r)}}async function tt(e,t,n){let r=Date.now()+t;for(;Date.now()<r;){let t=r-Date.now();if(await Re(e,Math.min(n,Math.max(t,1))))return!0;let i=Math.min(500,Math.max(r-Date.now(),0));i>0&&await Y(i)}return!1}async function nt(t){let n=Date.now()+t.startupTimeoutMs,r=null,i=null;for(;Date.now()<n;){try{let e=await Q({baseUrl:t.baseUrl,bearerToken:t.bearerToken,scope:t.scope,runtime:t.runtime,timeoutMs:t.probeTimeoutMs});if(e.probe.reachable!==!1)return e;r=e,i=null}catch(n){if(i=n instanceof Error?n.message:String(n),!We(n))throw new e(`COMMAND_FAILED`,$(t.baseUrl,i,r,t.initialBridgeError,t.companionLogPath),void 0,n)}let a=Math.min(1e3,Math.max(n-Date.now(),0));a>0&&await Y(a)}throw new e(`COMMAND_FAILED`,$(t.baseUrl,i,r,t.initialBridgeError,t.companionLogPath))}async function rt(t){let n=`http://${t.statusHost}:${t.metroPort}/status`;if(t.reuseExisting&&await Re(n,t.probeTimeoutMs))return{started:!1,reused:!0,pid:0,statusUrl:n};let r=Be(t.projectRoot,t.kind,t.repackBundler,t.metroPort,t.listenHost,t.logPath,t.env);if(await tt(n,t.startupTimeoutMs,t.probeTimeoutMs))return{started:!0,reused:!1,pid:r.pid,statusUrl:n};throw await Ve(r.pid).catch(()=>{}),new e(`COMMAND_FAILED`,`React Native dev server did not become ready at ${n} within ${t.startupTimeoutMs}ms. Check ${t.logPath}.`,{logPath:t.logPath})}async function it(e,t){let n=t.bridgeScope;if(!n)return null;let r=null,i=null;try{r=await Q({baseUrl:t.proxyBaseUrl,bearerToken:t.proxyBearerToken,scope:n,timeoutMs:t.probeTimeoutMs})}catch(e){if(!We(e))throw e;i=e instanceof Error?e.message:String(e)}return(!r||r.probe.reachable===!1)&&(r=await at(e,t,n,r,i)),Je(t.proxyBaseUrl,r),r}async function at(t,n,r,i,a){let o;try{o=(await Ce({projectRoot:n.projectRoot,serverBaseUrl:n.proxyBaseUrl,bearerToken:n.proxyBearerToken,bridgeScope:r,localBaseUrl:`http://${n.statusHost}:${n.metroPort}`,launchUrl:B(t.launchUrl),profileKey:B(t.companionProfileKey),consumerKey:B(t.companionConsumerKey),env:n.env})).logPath}catch(t){throw new e(`COMMAND_FAILED`,$(n.proxyBaseUrl,t instanceof Error?t.message:String(t),i,a),void 0,t)}try{return await nt({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 ot(e,t){return{baseIosRuntime:e?q(e,`ios`,t):{platform:`ios`},baseAndroidRuntime:e?q(e,`android`,t):{platform:`android`}}}function st(e,t){e&&(v.mkdirSync(_.dirname(e),{recursive:!0}),v.writeFileSync(e,JSON.stringify(t,null,2)))}async function ct(e={}){let t=et(e),n=t.installProjectDeps?Ie(t.projectRoot,t.env):{installed:!1},r=await rt(t),{baseIosRuntime:i,baseAndroidRuntime:a}=ot(t.publicBaseUrl,t.kind),o=await it(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 st(t.runtimeFilePath,l),l}function lt(e){let t=e.trimStart().slice(0,15).toLowerCase();return t.startsWith(`<!doctype`)||t.startsWith(`<html`)}async function ut(t,n){await new Promise((r,i)=>{let a=new WebSocket(t),o=t=>{clearTimeout(s);try{a.close()}catch{}i(new e(`COMMAND_FAILED`,t))},s=setTimeout(()=>{o(`Timed out broadcasting reload to ${t} 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 ${t}`)})})}async function dt(t={}){let n=K(t.timeoutMs,1e4,1e3),{reloadUrl:r,messageSocketUrl:i}=Te(t),a=await X(r,n);if(a.ok&&!lt(a.body))return{reloaded:!0,reloadUrl:r,status:a.status,body:a.body,transport:`http`};try{await ut(i,n)}catch(t){throw new e(`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.`},t instanceof Error?t:void 0)}return{reloaded:!0,reloadUrl:i,status:a.status,body:``,transport:`message-socket`}}export{M as a,j as i,dt as n,we as r,ct as t};
|
|
1
|
+
import{_ as e,v as t}from"./sdk-contracts.js";import{S as n,y as r}from"./sdk-android-adb.js";import{n as i}from"./path-resolution.js";import{t as a}from"./timeouts.js";import{c as o,d as s,n as c,s as l}from"./host-process.js";import{a as u,c as d,d as f,f as ee,g as te,h as p,i as ne,l as re,m as ie,n as m,o as h,p as g,s as ae,t as oe,u as se}from"./url.js";import{n as ce,r as le}from"./project-runtime.js";import{t as ue}from"./runtime-transport.js";import _ from"node:path";import{createHash as de}from"node:crypto";import v from"node:fs";import{fileURLToPath as fe}from"node:url";const y=`companion-tunnel`;function b(e){return de(`sha256`).update(e).digest(`hex`)}function x(e){return e?.trim()?e.trim():void 0}function pe(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 me(e,t){return e.tenantId===t.tenantId&&e.runId===t.runId&&e.leaseId===t.leaseId}function S(e,t,n,r){let i=r??_.join(e,`.agent-device`);if(!n)return{statePath:_.join(i,`${t.slug}.json`),logPath:_.join(i,`${t.slug}.log`)};let a=b(n).slice(0,12),o=_.join(i,t.slug);return{statePath:_.join(o,`${t.slug}-${a}.json`),logPath:_.join(o,`${t.slug}-${a}.log`)}}function C(e){try{let t=JSON.parse(v.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:x(typeof t.launchUrl==`string`?t.launchUrl:void 0),registerPath:x(typeof t.registerPath==`string`?t.registerPath:void 0),unregisterPath:x(typeof t.unregisterPath==`string`?t.unregisterPath:void 0),devicePort:Number.isInteger(t.devicePort)?Number(t.devicePort):void 0,session:x(typeof t.session==`string`?t.session:void 0),bridgeScope:pe(t.bridgeScope),tokenHash:t.tokenHash,consumers:n}}catch{return null}}function w(e,t){v.mkdirSync(_.dirname(e),{recursive:!0}),v.writeFileSync(e,`${JSON.stringify(t,null,2)}\n`,`utf8`)}function he(e){v.mkdirSync(_.dirname(e),{recursive:!0}),v.closeSync(v.openSync(e,`a`))}function ge(e){try{v.unlinkSync(e)}catch{}}function _e(e){try{v.unlinkSync(e)}catch{}}function T(e){try{v.readdirSync(e).length===0&&v.rmdirSync(e)}catch{}}function E(e,t){let n=_.dirname(e.statePath),r=_.dirname(e.logPath);ge(e.statePath),_e(e.logPath),T(n),r!==n&&T(r),_.basename(n)===t.slug&&T(_.dirname(n))}function D(e,t){return e.includes(t.runArg)}function ve(e,t){if(!c(e.pid))return!1;if(e.startTime){let t=o(e.pid);if(!t||t!==e.startTime)return!1}let n=l(e.pid);return!n||!D(n,t.definition)||!e.bridgeScope?!1:e.serverBaseUrl===m(t.serverBaseUrl)&&e.localBaseUrl===m(t.localBaseUrl)&&e.launchUrl===x(t.launchUrl)&&e.registerPath===x(t.registerPath)&&e.unregisterPath===x(t.unregisterPath)&&e.devicePort===t.devicePort&&e.session===x(t.session)&&me(e.bridgeScope,t.bridgeScope)&&e.tokenHash===b(t.bearerToken)}function O(e){return x(e.consumerKey)??x(e.profileKey)??null}function k(e,t){return!t||e.consumers.includes(t)?e:{...e,consumers:[...e.consumers,t]}}function ye(e,t){return t?{...e,consumers:e.consumers.filter(e=>e!==t)}:{...e,consumers:[]}}async function A(e,t){if(!c(e.pid))return;let n=l(e.pid);if(!(!n||!D(n,t))){try{process.kill(e.pid,`SIGTERM`)}catch(e){let t=e.code;if(t===`ESRCH`||t===`EPERM`)return;throw e}if(!await s(e.pid,1e3)){try{process.kill(e.pid,`SIGKILL`)}catch(e){let t=e.code;if(t===`ESRCH`||t===`EPERM`)return;throw e}await s(e.pid,1e3)}}}function be(e,t){let n={...t};return n[ee]=m(e.serverBaseUrl),n[ne]=e.bearerToken,n[ae]=m(e.localBaseUrl),n[ie]=S(e.projectRoot,e.definition,e.profileKey,e.stateDir).statePath,n[f]=e.bridgeScope.tenantId,n[se]=e.bridgeScope.runId,n[re]=e.bridgeScope.leaseId,e.launchUrl?.trim()?n[h]=e.launchUrl.trim():delete n[h],e.registerPath?.trim()?n[d]=e.registerPath.trim():delete n[d],e.unregisterPath?.trim()?n[p]=e.unregisterPath.trim():delete n[p],e.devicePort===void 0?delete n[u]:n[u]=String(e.devicePort),e.session?.trim()?n[g]=e.session.trim():delete n[g],n}function xe(e){let t=fe(import.meta.url),n=_.extname(t)||`.js`,r=[_.join(_.dirname(t),`${y}${n}`),_.join(_.dirname(t),`internal`,`${y}${n}`)].find(e=>v.existsSync(e));if(!r)throw Error(`${e.displayName} entrypoint not found. Rebuild the package to include the companion worker entry.`);return r}function Se(e,t){let n=xe(e.definition),i=n.endsWith(`.ts`)?[`--experimental-strip-types`]:[];v.mkdirSync(_.dirname(t),{recursive:!0});let a=v.openSync(t,`a`),s=0;try{s=r(process.execPath,[...i,n,e.definition.runArg],{env:be(e,e.env??process.env),stdio:[`ignore`,a,a]})}finally{v.closeSync(a)}if(!Number.isInteger(s)||s<=0)throw Error(`Failed to start ${e.definition.displayName} process.`);return{pid:s,startTime:o(s)??void 0,command:l(s)??void 0,serverBaseUrl:m(e.serverBaseUrl),localBaseUrl:m(e.localBaseUrl),launchUrl:x(e.launchUrl),registerPath:x(e.registerPath),unregisterPath:x(e.unregisterPath),devicePort:e.devicePort,session:x(e.session),bridgeScope:e.bridgeScope,tokenHash:b(e.bearerToken),consumers:[]}}async function j(e){let t=O(e),n=S(e.projectRoot,e.definition,e.profileKey,e.stateDir),r=C(n.statePath);if(r&&ve(r,e)){let e=k(r,t);return e!==r&&w(n.statePath,e),{pid:r.pid,spawned:!1,statePath:n.statePath,logPath:n.logPath}}r&&(await A(r,e.definition),E(n,e.definition)),he(n.statePath);let i;try{i=Se(e,n.logPath),w(n.statePath,k(i,t))}catch(t){throw i&&await A(i,e.definition).catch(()=>{}),E(n,e.definition),t}return{pid:i.pid,spawned:!0,statePath:n.statePath,logPath:n.logPath}}async function M(e){let t=O(e),n=S(e.projectRoot,e.definition,e.profileKey,e.stateDir),r=C(n.statePath);if(!r)return E(n,e.definition),{stopped:!1,statePath:n.statePath};let i=ye(r,t);return i.consumers.length>0?(w(n.statePath,i),{stopped:!1,statePath:n.statePath}):(await A(r,e.definition),E(n,e.definition),{stopped:!0,statePath:n.statePath})}const N={slug:`metro-companion`,runArg:te,displayName:`Metro companion`};async function Ce(e){return await j({...e,definition:N,registerPath:e.registerPath??`/api/metro/companion/register`})}async function we(e){return await M({...e,definition:N})}const P=8081,F=`.expo/.virtual-metro-entry.bundle`;function I(t,n){if(t==null||t===``)return n;let r=Number.parseInt(String(t),10);if(!Number.isInteger(r)||r<1||r>65535)throw new e(`INVALID_ARGS`,`Invalid Metro port: ${String(t)}. Use 1-65535.`);return r}function Te(t){let n=R(t.bundleUrl),r=n??t.runtime?.bundleUrl,i=!!n,a=!!R(r),o=ue({metroHost:Ee(t,i,a),metroPort:De(t,i,a),bundleUrl:r});if(!o)throw new e(`INVALID_ARGS`,`Unable to resolve Metro host and port for reload.`);let s=Oe(r);return{reloadUrl:L(o,o.scheme,`${s}/reload`),messageSocketUrl:L(o,o.scheme===`https`?`wss`:`ws`,`${s}/message`)}}function Ee(e,t,n){return R(e.metroHost)??(t?void 0:R(e.runtime?.metroHost))??(n?void 0:`localhost`)}function De(e,t,n){if(e.metroPort!==void 0)return I(e.metroPort,P);if(!t)return e.runtime?.metroPort??(n?void 0:P)}function Oe(e){let t=R(e);if(!t)return``;let n;try{n=new URL(t)}catch{return``}let r=n.pathname.replace(/\/+$/,``),i=`/${F}`;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 L(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 R(e){return typeof e==`string`&&e.trim()?e.trim():void 0}function z(e){return typeof e==`string`&&e.trim()?m(e.trim()):``}function B(e){return typeof e==`string`&&e.trim()?e.trim():void 0}function V(e,t,n){return i(e,{env:t,cwd:n})}function H(e){try{return v.accessSync(e,v.constants.F_OK),!0}catch{return!1}}function ke(e){try{return v.statSync(e).isDirectory()}catch{return!1}}function U(t){let n=_.join(t,`package.json`),r=le(t);if(!r)throw new e(`INVALID_ARGS`,`package.json not found at ${n}`);return r}const Ae=[{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 je(e){let t=e;for(;;){for(let{file:e,command:n}of Ae)if(H(_.join(t,e)))return{command:n,installArgs:[`install`]};if(H(_.join(t,`.git`)))return null;let e=_.dirname(t);if(e===t)return null;t=e}}function Me(e){return je(e)??{command:`npm`,installArgs:[`install`]}}function Ne(e,t){if(t!==`auto`)return t;let n=ce(e);return n===`expo`||n===`repack`?n:`react-native`}function W(e,t){return typeof{...e.dependencies??{},...e.devDependencies??{}}[t]==`string`}function G(e,t){return[`js`,`mjs`,`cjs`,`ts`,`mts`,`cts`].some(n=>H(_.join(e,`${t}.config.${n}`)))}function Pe(e,t){return G(e,`rspack`)?`rspack`:G(e,`webpack`)?`webpack`:W(t,`@rspack/core`)?`rspack`:W(t,`webpack`)?`webpack`:`rspack`}function K(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 Fe(e){return e===`expo`?F:`index.bundle`}function q(e,t,n){return{platform:t,bundleUrl:oe(e,t,Fe(n))}}function J(e,t){return{platform:t,metroHost:B(e?.metro_host),metroPort:e?.metro_port,bundleUrl:B(e?.metro_bundle_url),launchUrl:B(e?.launch_url)}}function Ie(e,t){if(ke(_.join(e,`node_modules`)))return{installed:!1};let r=Me(e);try{n(r.command,r.installArgs,{cwd:e,env:t})}catch(e){throw Le(e,r)}return{installed:!0,packageManager:r.command}}function Le(n,r){let i=t(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 e(i.code,i.message,{...i.details??{},hint:a,packageManager:r.command},i)}async function Y(e){await a(e)}async function X(t,n,r={}){try{let e=await fetch(t,{headers:r,signal:AbortSignal.timeout(n)});return{ok:e.ok,status:e.status,body:await e.text()}}catch(r){throw r instanceof Error&&r.name===`TimeoutError`?new e(`COMMAND_FAILED`,`Timed out fetching ${t} after ${n}ms`):r}}async function Re(e,t){try{let n=await X(e,t);return n.ok&&n.body.includes(`packager-status:running`)}catch{return!1}}function ze(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 Be(t,n,i,a,o,s,c){let l=ze(n,i,a,o);v.mkdirSync(_.dirname(s),{recursive:!0});let u=v.openSync(s,`a`),d=0;try{d=r(l.command,l.installArgs,{cwd:t,env:c,stdio:[`ignore`,u,u]})}finally{v.closeSync(u)}if(!Number.isInteger(d)||d<=0)throw new e(`COMMAND_FAILED`,`Failed to start React Native dev server. Expected a detached child PID.`);return{pid:d}}async function Ve(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 s(e,1e3)){try{process.kill(e,`SIGKILL`)}catch(e){let t=e.code;if(t===`ESRCH`||t===`EPERM`)return;throw e}await s(e,1e3)}}}function He(e,t){return{Authorization:`Bearer ${t}`,"Content-Type":`application/json`,...e.includes(`ngrok`)?{"ngrok-skip-browser-warning":`1`}:{}}}function Z(t,n){let r=new e(`COMMAND_FAILED`,t);return r.retryable=n,r}function Ue(e,t){return!!(e>=500||e===408||e===425||e===429||JSON.stringify(t).includes(`Metro companion is not connected`))}function We(e){return!!(e&&typeof e==`object`&&`retryable`in e&&e.retryable===!0)}async function Q(e){let t;try{t=await fetch(`${e.baseUrl}/api/metro/bridge`,{method:`POST`,headers:He(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`?Z(`/api/metro/bridge timed out after ${e.timeoutMs}ms calling ${e.baseUrl}/api/metro/bridge`,!0):Z(t instanceof Error?t.message:String(t),!0)}let n=Ge(await t.text(),t.status,e.baseUrl);if(!t.ok)throw Z(`/api/metro/bridge failed (${t.status}): ${JSON.stringify(n)}`,Ue(t.status,n));return qe(n)}function Ge(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 Z(`/api/metro/bridge returned invalid JSON (${t}) from ${n}: ${r instanceof Error?r.message:String(r)}. body=${JSON.stringify(i)}`,Ue(t,e))}}function Ke(e){return{enabled:e.enabled,baseUrl:e.base_url,statusUrl:e.status_url??``,bundleUrl:e.bundle_url??``,iosRuntime:J(e.ios_runtime,`ios`),androidRuntime:J(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 qe(e){let t=e.data??e;if(!t||typeof t!=`object`||Array.isArray(t))throw Z(`/api/metro/bridge returned malformed descriptor: Expected a JSON object.`,!1);try{return Ke(t)}catch(e){throw Z(`/api/metro/bridge returned malformed descriptor: ${e instanceof Error?e.message:String(e)}`,!1)}}function $(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 Je(t,n){if(!n?.iosRuntime.bundleUrl)throw new e(`COMMAND_FAILED`,$(t,`bridge descriptor is missing ios_runtime.metro_bundle_url`,n))}function Ye(t,n,r){let i=n||B(r.AGENT_DEVICE_METRO_BEARER_TOKEN)||``,a=i||t&&B(r.AGENT_DEVICE_DAEMON_AUTH_TOKEN)||``;if(t&&!a)throw new e(`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(!t&&i)throw new e(`INVALID_ARGS`,`metro prepare requires --proxy-base-url when proxy auth is provided.`);return{proxyEnabled:!!(t&&a),proxyBaseUrl:t,proxyBearerToken:a}}function Xe(t){if(!t?.tenantId||!t.runId||!t.leaseId)throw new e(`INVALID_ARGS`,`metro prepare with proxy requires tenantId, runId, and leaseId bridge scope.`);return t}function Ze(t,n){if(!(t||n))throw new e(`INVALID_ARGS`,`metro prepare requires --public-base-url <url> or --proxy-base-url <url>.`)}function Qe(e,t,n){return e.runtimeFilePath?V(e.runtimeFilePath,t,n):null}function $e(e,t,n,r){return V(e.logPath??_.join(r,`.agent-device`,`metro.log`),t,n)}function et(e){let t=e.env??process.env,n=process.cwd(),r=V(e.projectRoot??n,t,n),i=e.kind??`auto`,a=null,o;i===`auto`?(a=U(r),o=Ne(a,i)):o=i;let s=null;o===`repack`&&(a??=U(r),s=Pe(r,a));let c=z(e.publicBaseUrl),l=z(e.proxyBaseUrl);Ze(c,l);let{proxyEnabled:u,proxyBaseUrl:d,proxyBearerToken:f}=Ye(l,B(e.proxyBearerToken)??``,t);return{env:t,projectRoot:r,kind:o,repackBundler:s,metroPort:I(e.metroPort??8081,8081),listenHost:B(e.listenHost)??`0.0.0.0`,statusHost:B(e.statusHost)??`127.0.0.1`,publicBaseUrl:c,proxyBaseUrl:d,proxyBearerToken:f,bridgeScope:u?Xe(e.bridgeScope):null,startupTimeoutMs:K(e.startupTimeoutMs,18e4,3e4),probeTimeoutMs:K(e.probeTimeoutMs,1e4,1e3),reuseExisting:e.reuseExisting??!0,installProjectDeps:e.installDependenciesIfNeeded??!0,runtimeFilePath:Qe(e,t,n),logPath:$e(e,t,n,r)}}async function tt(e,t,n){let r=Date.now()+t;for(;Date.now()<r;){let t=r-Date.now();if(await Re(e,Math.min(n,Math.max(t,1))))return!0;let i=Math.min(500,Math.max(r-Date.now(),0));i>0&&await Y(i)}return!1}async function nt(t){let n=Date.now()+t.startupTimeoutMs,r=null,i=null;for(;Date.now()<n;){try{let e=await Q({baseUrl:t.baseUrl,bearerToken:t.bearerToken,scope:t.scope,runtime:t.runtime,timeoutMs:t.probeTimeoutMs});if(e.probe.reachable!==!1)return e;r=e,i=null}catch(n){if(i=n instanceof Error?n.message:String(n),!We(n))throw new e(`COMMAND_FAILED`,$(t.baseUrl,i,r,t.initialBridgeError,t.companionLogPath),void 0,n)}let a=Math.min(1e3,Math.max(n-Date.now(),0));a>0&&await Y(a)}throw new e(`COMMAND_FAILED`,$(t.baseUrl,i,r,t.initialBridgeError,t.companionLogPath))}async function rt(t){let n=`http://${t.statusHost}:${t.metroPort}/status`;if(t.reuseExisting&&await Re(n,t.probeTimeoutMs))return{started:!1,reused:!0,pid:0,statusUrl:n};let r=Be(t.projectRoot,t.kind,t.repackBundler,t.metroPort,t.listenHost,t.logPath,t.env);if(await tt(n,t.startupTimeoutMs,t.probeTimeoutMs))return{started:!0,reused:!1,pid:r.pid,statusUrl:n};throw await Ve(r.pid).catch(()=>{}),new e(`COMMAND_FAILED`,`React Native dev server did not become ready at ${n} within ${t.startupTimeoutMs}ms. Check ${t.logPath}.`,{logPath:t.logPath})}async function it(e,t){let n=t.bridgeScope;if(!n)return null;let r=null,i=null;try{r=await Q({baseUrl:t.proxyBaseUrl,bearerToken:t.proxyBearerToken,scope:n,timeoutMs:t.probeTimeoutMs})}catch(e){if(!We(e))throw e;i=e instanceof Error?e.message:String(e)}return(!r||r.probe.reachable===!1)&&(r=await at(e,t,n,r,i)),Je(t.proxyBaseUrl,r),r}async function at(t,n,r,i,a){let o;try{o=(await Ce({projectRoot:n.projectRoot,serverBaseUrl:n.proxyBaseUrl,bearerToken:n.proxyBearerToken,bridgeScope:r,localBaseUrl:`http://${n.statusHost}:${n.metroPort}`,launchUrl:B(t.launchUrl),profileKey:B(t.companionProfileKey),consumerKey:B(t.companionConsumerKey),env:n.env})).logPath}catch(t){throw new e(`COMMAND_FAILED`,$(n.proxyBaseUrl,t instanceof Error?t.message:String(t),i,a),void 0,t)}try{return await nt({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 ot(e,t){return{baseIosRuntime:e?q(e,`ios`,t):{platform:`ios`},baseAndroidRuntime:e?q(e,`android`,t):{platform:`android`}}}function st(e,t){e&&(v.mkdirSync(_.dirname(e),{recursive:!0}),v.writeFileSync(e,JSON.stringify(t,null,2)))}async function ct(e={}){let t=et(e),n=t.installProjectDeps?Ie(t.projectRoot,t.env):{installed:!1},r=await rt(t),{baseIosRuntime:i,baseAndroidRuntime:a}=ot(t.publicBaseUrl,t.kind),o=await it(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 st(t.runtimeFilePath,l),l}function lt(e){let t=e.trimStart().slice(0,15).toLowerCase();return t.startsWith(`<!doctype`)||t.startsWith(`<html`)}async function ut(t,n){await new Promise((r,i)=>{let a=new WebSocket(t),o=t=>{clearTimeout(s);try{a.close()}catch{}i(new e(`COMMAND_FAILED`,t))},s=setTimeout(()=>{o(`Timed out broadcasting reload to ${t} 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 ${t}`)})})}async function dt(t={}){let n=K(t.timeoutMs,1e4,1e3),{reloadUrl:r,messageSocketUrl:i}=Te(t),a=await X(r,n);if(a.ok&&!lt(a.body))return{reloaded:!0,reloadUrl:r,status:a.status,body:a.body,transport:`http`};try{await ut(i,n)}catch(t){throw new e(`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.`},t instanceof Error?t:void 0)}return{reloaded:!0,reloadUrl:i,status:a.status,body:``,transport:`message-socket`}}export{M as a,j as i,dt as n,we as r,ct as t};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{g as e}from"./sdk-batch-runner.js";const t=s(`public`),n=s(`internal`),r=s(`local-cli`),i={help:`help`};function a(){return[...Object.values(t),...Object.values(r)].sort()}function o(e){return Object.values(i).includes(e)||Object.values(n).includes(e)?!0:a().includes(e)}function s(t){let n={};for(let[r,i]of e(t))n[r]=i;return n}export{a as i,t as n,o as r,n as t};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{_ as e}from"./sdk-batch-runner.js";import{o as t}from"./registry.js";const n=t(),r=new Map(n.map(e=>[e.name,e]));function i(){return[...n]}function a(){return e().map(e=>{let t=s(e);if(!t)throw Error(`Missing command metadata for MCP-exposed command: ${e}`);return t})}function o(e){return r.has(e)}function s(e){return r.get(e)}export{a as i,o as n,i as r,s as t};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{_ as e}from"./sdk-contracts.js";import{f as t,r as n,u as r}from"./registry.js";import{r as i}from"./command-metadata.js";const a={cdp:{text:{summary:`Inspect CDP targets, JS heap, and leaks`,description:`Run CDP commands for React Native diagnostics, JS heap usage, heap snapshots, and leak analysis`},usageOverride:`cdp [...args]`,listUsageOverride:`cdp`,positionalArgs:[`args?`],allowsExtraPositionals:!0,supportedFlags:r},auth:{text:{summary:`Manage cloud login state`,description:`Manage cloud login state used by remote daemon and cloud device workflows.`},usageOverride:`auth status|login|logout`,listUsageOverride:`auth`,positionalArgs:[`status|login|logout`],supportedFlags:[`remoteConfig`,`stateDir`]},daemon:{text:{summary:`Stop a local daemon and clean up resources`,description:`Stop a local daemon after verifying its PID/start-time identity. Use --clean to remove retained Apple runner processes and leases owned by that daemon.`},usageOverride:`daemon stop [--state-dir <path>] [--clean]`,listUsageOverride:`daemon stop`,positionalArgs:[`stop`],allowedFlags:[`clean`],supportedFlags:[`stateDir`]},device:{text:{summary:`Inspect local
|
|
1
|
+
import{_ as e}from"./sdk-contracts.js";import{f as t,r as n,u as r}from"./registry.js";import{r as i}from"./command-metadata.js";const a={cdp:{text:{summary:`Inspect CDP targets, JS heap, and leaks`,description:`Run CDP commands for React Native diagnostics, JS heap usage, heap snapshots, and leak analysis`},usageOverride:`cdp [...args]`,listUsageOverride:`cdp`,positionalArgs:[`args?`],allowsExtraPositionals:!0,supportedFlags:r},auth:{text:{summary:`Manage cloud login state`,description:`Manage cloud login state used by remote daemon and cloud device workflows.`},usageOverride:`auth status|login|logout`,listUsageOverride:`auth`,positionalArgs:[`status|login|logout`],supportedFlags:[`remoteConfig`,`stateDir`]},daemon:{text:{summary:`Stop a local daemon and clean up resources`,description:`Stop a local daemon after verifying its PID/start-time identity. Use --clean to remove retained Apple runner processes and leases owned by that daemon.`},usageOverride:`daemon stop [--state-dir <path>] [--clean]`,listUsageOverride:`daemon stop`,positionalArgs:[`stop`],allowedFlags:[`clean`],supportedFlags:[`stateDir`]},device:{text:{summary:`Inspect enforced local device ownership without daemon side effects`,description:`Inspect enforced host-local device ownership claims without starting or contacting a daemon. --stale only inspects proven-stale claims; automatic reclamation occurs during open or daemon startup after exact-owner resource reconciliation.`},usageOverride:`device status [--platform <platform>] [--udid <udid>] [--serial <serial>] [--stale]`,listUsageOverride:`device status`,positionalArgs:[`status`],allowedFlags:[`stale`],supportedFlags:[`platform`,`device`,`udid`,`serial`]},connect:{text:{summary:`Configure remote or provider state`,description:`Configure remote access without allocating a device. Direct providers validate credentials/resources before saving state and print the exact device/app preparation needed before open. AGENT_DEVICE_CLOUD_BASE_URL is the bridge/control-plane API origin; use AGENT_DEVICE_DAEMON_AUTH_TOKEN=adc_live_... for CI/service-token automation.`},usageOverride:`connect [cloud|proxy|limrun|browserstack|aws-device-farm] [--remote-config <path>] [--daemon-base-url <url>] [--tenant <id>] [--run-id <id>] [--lease-id <id>] [--lease-backend <backend>] [--force] [--no-login]`,listUsageOverride:`connect`,positionalArgs:[`provider?`],allowedFlags:`remoteConfig.daemonBaseUrl.tenant.runId.leaseId.leaseBackend.providerApp.providerOsVersion.providerProject.providerBuild.providerSessionName.providerDeviceOrientation.providerGeoLocation.providerTimezone.providerLanguage.providerLocale.providerNetworkProfile.providerCustomNetwork.providerNoResignApp.awsProjectArn.awsDeviceArn.awsAppArn.awsRegion.awsInteractionMode.force.noLogin`.split(`.`),supportedFlags:[`stateDir`,`daemonAuthToken`,`session`,`platform`,`device`,...t,`launchUrl`]},connection:{text:{summary:`Inspect the saved remote connection`,description:`Inspect active remote connection state`},usageOverride:`connection status`,listUsageOverride:`connection`,positionalArgs:[`status`],supportedFlags:[`remoteConfig`,`stateDir`,`session`]},disconnect:{text:{summary:`Clear remote connection state and release leases`,description:`Disconnect remote daemon state, stop owned Metro companion, and release lease`},listUsageOverride:`disconnect`,allowedFlags:[`shutdown`],supportedFlags:[`remoteConfig`,`stateDir`,`session`]},mcp:{text:{summary:`Start MCP server`,description:`Start the official stdio MCP server. It exposes structured command tools backed by the agent-device client.`}},proxy:{text:{summary:`Expose a local daemon through an HTTP tunnel`,description:`Expose the local daemon HTTP contract through a tunnel-friendly reverse proxy.
|
|
2
2
|
|
|
3
3
|
Run this on the host that has access to simulators/devices, expose the printed local proxy URL through a tunnel, then point another machine at the tunnel URL with connect proxy.
|
|
4
4
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{n as e}from"./rolldown-runtime.js";import{a as t}from"./registry.js";var n=e({runCommand:()=>a});const r=t(),i=new Map(r.map(e=>[e.name,e]));async function a(e,t,n){return await o(t).invoke(e,n)}function o(e){return i.get(e)}export{a as n,n as t};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=new Set;function t(t={}){let r=new Map,i=t.now??(()=>Date.now()),a=e=>{e?.timer&&clearTimeout(e.timer)},o={get(e){let t=r.get(e);if(t){if(t.expiresAt!==void 0&&t.expiresAt<=i()){o.delete(e);return}return t.value}},set(e,o){a(r.get(e));let s=n(t.ttlMs,i),c={value:o,expiresAt:s};t.scheduleExpiry&&s!==void 0&&(c.timer=setTimeout(()=>{r.delete(e)},Math.max(0,s-i())),c.timer.unref?.()),r.set(e,c)},delete(e){let t=r.get(e);return t?(a(t),r.delete(e)):!1},clear(){for(let e of r.values())a(e);r.clear()}};return e.add(o.clear),o}function n(e,t){if(!(e===void 0||!Number.isFinite(e)))return t()+Math.max(0,e)}const r=18e4,i=6e4,a=6e4,o=2e4,s=12e4,c=1e4,l=15e3,u=2e4,d=15e3,f=2e4,p=1e3,m=5e3;export{f as a,p as c,u as d,l as f,s as i,m as l,r as n,i as o,t as p,o as r,c as s,a as t,d as u};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{_ as e}from"./sdk-contracts.js";import{_ as t,a as n,b as r,c as i}from"./sdk-device.js";import{Tn as a,Xt as o,Yt as s,t as c,wn as l,xn as u}from"./prepare-kind.js";import{_ as d}from"./screenshot-result.js";import{t as f}from"./sdk-remote-config.js";import{S as p,j as m}from"./sdk-android-adb.js";import{v as h}from"./url.js";import{a as g,i as _}from"./client-metro.js";import{n as ee}from"./metro2.js";import{n as te,r as v,t as ne}from"./remote-config2.js";import{a as y,i as b}from"./src3.js";import x from"node:path";import S from"node:crypto";import C from"node:fs";const w={slug:`react-devtools-companion`,runArg:h,displayName:`React DevTools companion`};async function T(e){return await _({...e,definition:w,localBaseUrl:e.localBaseUrl??`http://127.0.0.1:8097`,registerPath:`/api/react-devtools/companion/register`,unregisterPath:`/api/react-devtools/companion/unregister`,devicePort:e.devicePort??8097})}async function E(e){return await g({...e,definition:w})}function D(e){return e===`android-instance`||e===`ios-instance`}function re(e){return[`exec`,`--yes`,`--package`,`agent-cdp@1.6.1`,`--`,`agent-cdp`,...e]}function ie(e){return e.some(e=>e===`--url`||e.startsWith(`--url=`))}function O(e){return e[0]===`target`&&(e[1]===`list`||e[1]===`select`)&&!ie(e)}function ae(e){let t=new URL(e);t.search=``,t.hash=``;let n=t.pathname.replace(/\/+$/,``);return t.pathname=n.endsWith(`/index.bundle`)?n.slice(0,-13)||`/`:n||`/`,t.toString().replace(/\/+$/,``)}function oe(e){let t=e?.metroPublicBaseUrl?.trim();return t?ae(t):null}function se(t,n={}){if(!O(t)||!n.flags?.metroProxyBaseUrl||!D(n.flags.leaseBackend))return t;let r=oe(n.flags);if(!r)throw new e(`INVALID_ARGS`,`cdp remote bridge target discovery requires a React Native dev-server public base URL.`,{hint:`Include metroPublicBaseUrl in the remote config so cdp can reach the local or tunneled Metro/Re.Pack CDP endpoint without bridge proxy authentication.`});return[...t,`--url`,r]}async function ce(e,t={}){return(await p(`npm`,re(se(e,t)),{cwd:t.cwd??process.cwd(),env:t.env??process.env,allowFailure:!0,onStdoutChunk:e=>{process.stdout.write(e)},onStderrChunk:e=>{process.stderr.write(e)}})).exitCode}function k(e){let t=P(e);if(!C.existsSync(t))return null;let n;try{n=JSON.parse(C.readFileSync(t,`utf8`))}catch(t){return z(e,t),null}return me(n)?n:(z(e),null)}function A(e){let t=P({stateDir:e.stateDir,session:e.state.session});C.mkdirSync(x.dirname(t),{recursive:!0}),R(t,e.state),R(F(e.stateDir),{session:e.state.session})}function j(e){return{baseUrl:pe(e.daemonBaseUrl),transport:e.daemonTransport,serverMode:e.daemonServerMode}}function M(e){C.rmSync(P(e),{force:!0});let t=F(e.stateDir);L(e.stateDir)===e.session&&C.rmSync(t,{force:!0})}function le(t){let n=t.validateRemoteConfigHash??!0,r=t.remoteConfig?te({configPath:t.remoteConfig,cwd:t.cwd,env:t.env}):void 0,i=k(t)??(t.allowActiveFallback?I({stateDir:t.stateDir}):null);if(!i||r&&i.remoteConfigPath!==r)return null;if(n&&N(i.remoteConfigPath)!==i.remoteConfigHash)throw new e(`INVALID_ARGS`,`Active remote connection config changed. Run agent-device connect --force to refresh it.`,{remoteConfig:i.remoteConfigPath});let o=fe(i,t),s=u(i);return{runtime:i.runtime,connection:a(s),flags:{...o,remoteConfig:i.remoteConfigPath,daemonBaseUrl:i.daemon?.baseUrl??o.daemonBaseUrl,daemonAuthToken:o.daemonAuthToken,daemonTransport:i.daemon?.transport??o.daemonTransport,daemonServerMode:i.daemon?.serverMode??o.daemonServerMode,...l(s),sessionIsolation:`tenant`,session:i.session,platform:i.platform??o.platform,target:i.target??o.target}}}function ue(e){return a(u(e))}function N(t){try{return S.createHash(`sha256`).update(C.readFileSync(t)).digest(`hex`)}catch(n){throw new e(`INVALID_ARGS`,`Remote config file not found: ${t}`,{cause:n instanceof Error?n.message:String(n)})}}function P(e){return x.join(e.stateDir,`remote-connections`,`${B(e.session)}.json`)}function F(e){return x.join(e,`remote-connections`,`.active-session.json`)}function I(e){let t=L(e.stateDir);return t?k({stateDir:e.stateDir,session:t}):null}function L(e){let t=F(e);if(C.existsSync(t))try{let e=JSON.parse(C.readFileSync(t,`utf8`));return typeof e.session==`string`?e.session:void 0}catch{return}}function de(e){if(e)return S.createHash(`sha256`).update(e).digest(`hex`).slice(0,12)}function fe(e,t){try{return v({configPath:e.remoteConfigPath,cwd:t.cwd,env:t.env}).profile}catch(e){if(t.validateRemoteConfigHash===!1)return{};throw e}}function R(e,t){let n=`${e}.${process.pid}.${S.randomUUID()}.tmp`;try{C.writeFileSync(n,`${JSON.stringify(t,null,2)}\n`,{encoding:`utf8`,mode:384}),C.renameSync(n,e)}catch(e){throw C.rmSync(n,{force:!0}),e}}function pe(e){if(!e)return;let t=new URL(e);t.username=``,t.password=``;for(let e of[...t.searchParams.keys()])/(auth|key|password|secret|token)/i.test(e)&&t.searchParams.delete(e);return t.toString().replace(/\/+$/,``)}function z(e,t){m({level:`warn`,phase:`remote_connection_state_invalid`,data:{session:e.session,cause:t instanceof Error?t.message:t?String(t):void 0}}),M(e)}function B(e){let t=e.replaceAll(/[^a-zA-Z0-9._-]/g,`_`);return t?t===e?t:`${t}-${S.createHash(`sha256`).update(e).digest(`hex`).slice(0,8)}`:`default`}function me(e){if(!e||typeof e!=`object`||Array.isArray(e))return!1;let t=e;return t.version===1&&he(t,[`session`,`remoteConfigPath`,`remoteConfigHash`,`tenant`,`runId`,`connectedAt`,`updatedAt`])&&ge(t,[`leaseId`,`leaseBackend`,`leaseProvider`,`deviceKey`,`clientId`])&&_e(t.daemon)}function he(e,t){return t.every(t=>typeof e[t]==`string`)}function ge(e,t){return t.every(t=>e[t]===void 0||typeof e[t]==`string`)}function _e(e){return e===void 0?!0:!e||typeof e!=`object`||Array.isArray(e)?!1:ve(e)}function ve(e){let t=e;return(t.baseUrl===void 0||typeof t.baseUrl==`string`)&&(t.authToken===void 0||typeof t.authToken==`string`)&&(t.transport===void 0||typeof t.transport==`string`)&&(t.serverMode===void 0||typeof t.serverMode==`string`)}const ye=f.map(e=>e.key);function V(e){let t={};for(let n of ye){let r=e[n];r!==void 0&&(t[n]=r)}return t}function be(e){return e.remoteConfig?{...V(v({configPath:e.remoteConfig,cwd:e.cwd,env:e.env}).profile),remoteConfig:e.remoteConfig}:{}}function xe(e){return e===`cloud`||e===`proxy`||H(e)}function H(e){return e===`limrun`||y(e)}function Se(){return[`cloud`,`proxy`,b.browserStack,b.awsDeviceFarm,`limrun`].join(`, `)}function U(e){return!H(e)}function Ce(e){return e===`proxy`?`proxy`:H(e)?`direct-device-provider`:`remote-provider`}function W(e){return{providerDeviceOrientation:e.providerDeviceOrientation,providerGeoLocation:e.providerGeoLocation,providerTimezone:e.providerTimezone,providerLanguage:e.providerLanguage,providerLocale:e.providerLocale,providerNetworkProfile:e.providerNetworkProfile,providerCustomNetwork:e.providerCustomNetwork,providerNoResignApp:e.providerNoResignApp}}function we(e){return{metroProjectRoot:e.metroProjectRoot,metroKind:e.metroKind,metroPublicBaseUrl:e.metroPublicBaseUrl,metroProxyBaseUrl:e.metroProxyBaseUrl,metroPreparePort:e.metroPreparePort,metroListenHost:e.metroListenHost,metroStatusHost:e.metroStatusHost,metroStartupTimeoutMs:e.metroStartupTimeoutMs,metroProbeTimeoutMs:e.metroProbeTimeoutMs,metroRuntimeFile:e.metroRuntimeFile,metroNoReuseExisting:e.metroNoReuseExisting,metroNoInstallDeps:e.metroNoInstallDeps,launchUrl:e.launchUrl}}const G=new Set([`artifacts`,`connect`,`connection`,`close`,`disconnect`,`metro`,`session`]),K=new Set([`open`]),Te=new Set([o.open,o.install,o.reinstall,s.installSource]);async function Ee(t){let{command:n,flags:r,client:i}=t;if(!r.remoteConfig)return{flags:r,runtime:t.runtime};let a=d(r.stateDir).baseDir,o=v({configPath:r.remoteConfig,cwd:process.cwd(),env:process.env}),s={...V(o.profile),...r,remoteConfig:o.resolvedPath},c=k({stateDir:a,session:s.session??`default`});if(c&&c.remoteConfigPath!==o.resolvedPath)throw new e(`INVALID_ARGS`,`A different remote connection is already active for this session. Run connect --force or disconnect before using a different --remote-config.`,{session:c.session,activeRemoteConfig:c.remoteConfigPath,requestedRemoteConfig:o.resolvedPath});let l=c??Ye(s,o.resolvedPath,o.profile),u={...s,session:l.session},f=Je(l.runtime,u.platform)??t.runtime,p=l,m=!c,h,g=Pe(p);if(g.shouldAllocate(n)){let e=await je({command:n,client:i,state:l,nextState:p,nextFlags:u,policy:g});p=e.state,m||=e.changed,h=e.acquiredLeaseForCleanup}let _=await De({command:n,flags:u,client:i,state:l,nextState:p,runtime:f,positionals:t.positionals,batchSteps:t.batchSteps,forceRuntimePrepare:t.forceRuntimePrepare});return p=_.state,f=_.runtime,m||=_.changed,await Ae({changed:m,stateDir:a,state:p,client:i,acquiredLeaseForCleanup:h,preparedMetroCleanupOnFailure:_.preparedMetroCleanupOnFailure,metroCleanupToStop:_.metroCleanupToStop}),{flags:{...u,session:p.session,leaseId:p.leaseId,leaseBackend:p.leaseBackend,platform:p.platform??u.platform,target:p.target??u.target},runtime:f,connection:ue(p)}}async function De(t){let{command:n,flags:r,state:i,client:a}=t,o=Oe(t.nextState,r),s=t.runtime;if(!Ke(n,r,t.batchSteps,t.positionals)||!Z(r)||!ke(t.forceRuntimePrepare,s,r.platform))return{state:o,runtime:s,changed:!1};if(!o.leaseId)throw new e(`INVALID_ARGS`,`${n} requires a resolved remote lease before Metro runtime can be prepared.`);let c=await Re(r,a,i.remoteConfigPath,i.session,{tenantId:i.tenant,runId:i.runId,leaseId:o.leaseId}),l=!qe(o.metro,c.cleanup);return o={...o,runtime:c.runtime,metro:c.cleanup,updatedAt:new Date().toISOString()},{state:o,runtime:c.runtime,changed:!0,metroCleanupToStop:l?t.nextState.metro:void 0,preparedMetroCleanupOnFailure:l?c.cleanup:void 0}}function Oe(e,t){return e.leaseId||!t.leaseId?e:{...e,leaseId:t.leaseId,leaseBackend:t.leaseBackend}}function ke(e,t,n){return e===!0||!t||!Q(t,n)}async function Ae(e){if(e.changed)try{A({stateDir:e.stateDir,state:e.state})}catch(t){throw await q(e.preparedMetroCleanupOnFailure),await We(e.client,e.state,e.acquiredLeaseForCleanup),t}await q(e.metroCleanupToStop)}async function je(e){let{command:t,client:n,state:r,nextFlags:i,policy:a}=e,o=r.leaseBackend??X(i),s=e.nextState,c=await a.resolveLeaseState({command:t,client:n,state:s,flags:i,leaseBackend:o});s=c.state,c.device&&$(i,c.device);let l=s.leaseBackend??o??Ge(i,t);tt(r,i,l);let u=await Xe(n,s,l,a,i),d=u.lease;return i.leaseId=d.leaseId,i.leaseBackend=l,i.platform=s.platform??i.platform,i.target=s.target??i.target,Me(s,d,l)?{state:s,changed:!1,acquiredLeaseForCleanup:u.acquired?d:void 0}:{state:Ne(s,d,l,i),changed:!0,acquiredLeaseForCleanup:u.acquired?d:void 0}}function Me(e,t,n){return e.leaseId===t.leaseId&&e.leaseBackend===n&&e.deviceKey===(t.deviceKey??e.deviceKey)}function Ne(e,t,n,r){return{...e,leaseId:t.leaseId,leaseBackend:n,leaseProvider:t.leaseProvider??e.leaseProvider,clientId:t.clientId??e.clientId,deviceKey:t.deviceKey??e.deviceKey,platform:e.platform??r.platform,target:e.target??r.target,updatedAt:new Date().toISOString()}}function Pe(e){return e.leaseProvider===`proxy`?Ie:y(e.leaseProvider)?Le:Fe}const Fe={shouldAllocate:e=>!G.has(e),ttlMs:()=>void 0,resolveLeaseState:async e=>({state:e.state})},Ie={shouldAllocate:e=>e!==`devices`&&!G.has(e),ttlMs:()=>3e5,resolveLeaseState:Ze},Le={shouldAllocate:e=>!G.has(e),ttlMs:()=>6e5,resolveLeaseState:async e=>({state:e.state})};async function Re(t,n,r,i,a){if(!t.metroProjectRoot&&!t.metroPublicBaseUrl&&!t.metroProxyBaseUrl)return{};if(t.platform!==`ios`&&t.platform!==`android`)throw new e(`INVALID_ARGS`,`Deferred Metro preparation requires platform "ios" or "android".`);if(!t.metroPublicBaseUrl&&!t.metroProxyBaseUrl)throw new e(`INVALID_ARGS`,`Deferred Metro preparation requires metroPublicBaseUrl or metroProxyBaseUrl when Metro settings are provided.`);let o=await n.metro.prepare({projectRoot:t.metroProjectRoot,kind:c(t.metroKind),publicBaseUrl:t.metroPublicBaseUrl,proxyBaseUrl:t.metroProxyBaseUrl,bearerToken:t.metroBearerToken,bridgeScope:a,launchUrl:t.launchUrl,companionProfileKey:r,companionConsumerKey:i,port:t.metroPreparePort,listenHost:t.metroListenHost,statusHost:t.metroStatusHost,startupTimeoutMs:t.metroStartupTimeoutMs,probeTimeoutMs:t.metroProbeTimeoutMs,reuseExisting:t.metroNoReuseExisting?!1:void 0,installDependenciesIfNeeded:t.metroNoInstallDeps?!1:void 0,runtimeFilePath:t.metroRuntimeFile});return{runtime:t.platform===`ios`?o.iosRuntime:o.androidRuntime,cleanup:t.metroProxyBaseUrl?{projectRoot:o.projectRoot,profileKey:r,consumerKey:i}:void 0}}async function q(e){if(e)try{await ee(e)}catch{}}async function ze(e){try{await E({projectRoot:process.cwd(),stateDir:e.stateDir,profileKey:e.state.remoteConfigPath,consumerKey:e.state.session})}catch{}}async function J(e,t,n){return t.leaseId?await e.leases.release({tenant:t.tenant,runId:t.runId,leaseId:t.leaseId,leaseBackend:t.leaseBackend,daemonBaseUrl:t.daemon?.baseUrl,daemonAuthToken:n,daemonTransport:t.daemon?.transport,daemonServerMode:t.daemon?.serverMode,leaseProvider:t.leaseProvider,clientId:t.clientId,deviceKey:t.deviceKey}):{released:!1}}function Be(e){let t=Ve(e.previous,e.cwd,e.env);return t?{canAuthenticate:!0,daemonAuthToken:t}:e.previous.daemon?.baseUrl===e.nextDaemonBaseUrl?{canAuthenticate:!0,daemonAuthToken:e.ambientDaemonAuthToken}:{canAuthenticate:!1}}function Ve(e,t,n){try{let{profile:r}=ne({configPath:e.remoteConfigPath,cwd:t,env:n});return r.daemonAuthToken&&He(e,r.daemonBaseUrl)?r.daemonAuthToken:void 0}catch{return}}function He(e,t){let n=j({daemonBaseUrl:t})?.baseUrl;return n!==void 0&&n===e.daemon?.baseUrl}async function Ue(e,t,n){if(!t.leaseId)return;let r=Be({previous:t,nextDaemonBaseUrl:n.nextDaemonBaseUrl,ambientDaemonAuthToken:n.ambientDaemonAuthToken,cwd:n.cwd,env:n.env});if(!r.canAuthenticate)return Y(t,`no credential known to belong to that endpoint was available`);try{await J(e,t,r.daemonAuthToken);return}catch{return Y(t,`the release request failed`)}}function Y(e,t){return{status:`unreleased`,message:`Could not release the previous lease ${e.leaseId} (tenant ${e.tenant}, run ${e.runId}) at ${e.daemon?.baseUrl??`its daemon`}: ${t}. It was left in place — release it manually if it is still active.`}}async function We(e,t,n){if(n)try{await e.leases.release({tenant:t.tenant,runId:t.runId,leaseId:n.leaseId,leaseBackend:t.leaseBackend??n.backend,leaseProvider:t.leaseProvider??n.leaseProvider,clientId:t.clientId??n.clientId,deviceKey:t.deviceKey??n.deviceKey})}catch{}}function X(e){if(e.leaseBackend)return e.leaseBackend;if(e.platform===`android`)return`android-instance`;if(e.platform===`ios`)return`ios-instance`}function Ge(t,n){let r=X(t);if(r)return r;throw new e(`INVALID_ARGS`,`${n} requires --platform ios|android or --lease-backend when the remote connection has not resolved a lease yet.`)}function Ke(e,t,n,r=[]){return e===`cdp`?O(r)&&!!t.metroPublicBaseUrl:K.has(e)?!0:e!==`batch`||!n?!1:n.some(e=>{let t=e.command.trim().toLowerCase();return K.has(t)&&e.runtime===void 0})}function Z(e){let t=e.metroKind;return!!(e.metroPublicBaseUrl||e.metroProxyBaseUrl||e.metroProjectRoot||t)}function Q(e,t){return!e.platform||!t||t!==`ios`&&t!==`android`?!0:e.platform===t}function qe(e,t){return e?.projectRoot===t?.projectRoot&&e?.profileKey===t?.profileKey&&e?.consumerKey===t?.consumerKey}function Je(e,t){if(e)return Q(e,t)?e:void 0}function Ye(t,n,r={}){if(!t.tenant)throw new e(`INVALID_ARGS`,`remote command requires tenant in remote config or via --tenant <id>.`);if(!t.runId)throw new e(`INVALID_ARGS`,`remote command requires runId in remote config or via --run-id <id>.`);if(!t.daemonBaseUrl&&U(r.leaseProvider))throw new e(`INVALID_ARGS`,`remote command requires daemonBaseUrl in remote config, config, env, or --daemon-base-url.`);let i=new Date().toISOString();return{version:1,session:t.session??`default`,remoteConfigPath:n,remoteConfigHash:N(n),daemon:j(t),tenant:t.tenant,runId:t.runId,leaseId:t.leaseId,leaseBackend:t.leaseBackend??X(t),leaseProvider:r.leaseProvider,clientId:r.clientId,deviceKey:r.deviceKey,platform:t.platform,target:t.target,connectedAt:i,updatedAt:i}}async function Xe(e,t,n,r,i){if(t.leaseId&&t.leaseBackend===n){let i=await nt(e,t.leaseId,{tenant:t.tenant,runId:t.runId,leaseBackend:n,leaseProvider:t.leaseProvider,clientId:t.clientId,deviceKey:t.deviceKey,ttlMs:r.ttlMs(t)});if(i)return{lease:i,acquired:!1}}return{lease:await e.leases.allocate({tenant:t.tenant,runId:t.runId,leaseBackend:n,leaseProvider:t.leaseProvider,clientId:t.clientId,deviceKey:t.deviceKey,ttlMs:r.ttlMs(t),platform:t.platform??i.platform,target:t.target??i.target,device:i.device,udid:i.udid,serial:i.serial,providerApp:i.providerApp,providerOsVersion:i.providerOsVersion,providerProject:i.providerProject,providerBuild:i.providerBuild,providerSessionName:i.providerSessionName,...W(i),awsProjectArn:i.awsProjectArn,awsDeviceArn:i.awsDeviceArn,awsAppArn:i.awsAppArn,awsRegion:i.awsRegion,awsInteractionMode:i.awsInteractionMode}),acquired:!0}}async function Ze(t){if(!Te.has(t.command)){if(t.state.leaseId&&t.state.deviceKey)return{state:t.state};throw new e(`INVALID_ARGS`,`No active proxy device lease for this session; run open first.`)}let n=await Qe(t.client,t.flags),r=$e(n);return{state:{...t.state,deviceKey:r,leaseBackend:t.state.leaseBackend??t.leaseBackend??et(n),platform:t.state.platform??n.platform,target:t.state.target??n.target,updatedAt:new Date().toISOString()},device:n}}function $(e,t){if(e.platform=t.platform,e.target=t.target??e.target,i(t)){e.udid=t.id;return}t.platform===`android`&&(e.serial=t.id)}async function Qe(e,t){return await r((await e.devices.list({platform:t.platform,target:t.target,device:t.device,udid:t.udid,serial:t.serial,iosSimulatorDeviceSet:t.iosSimulatorDeviceSet,androidDeviceAllowlist:t.androidDeviceAllowlist})).map(e=>({...n(e.platform),id:e.id,name:e.name,kind:e.kind,target:e.target,booted:e.booted})),{platform:t.platform,target:t.target,deviceName:t.device,udid:t.udid,serial:t.serial})}function $e(e){return`${t(e)}:${e.target??`mobile`}:${e.id}`}function et(e){if(i(e))return`ios-instance`;if(e.platform===`android`)return`android-instance`}function tt(t,n,r){if(t.leaseBackend&&t.leaseBackend!==r)throw new e(`INVALID_ARGS`,`Active remote connection is already bound to a different lease backend. Re-run connect --force to replace it.`,{session:t.session,leaseBackend:t.leaseBackend});if(t.platform&&n.platform&&t.platform!==n.platform)throw new e(`INVALID_ARGS`,`Active remote connection is already bound to a different platform. Re-run connect --force to replace it.`,{session:t.session,platform:t.platform});if(t.target&&n.target&&t.target!==n.target)throw new e(`INVALID_ARGS`,`Active remote connection is already bound to a different target. Re-run connect --force to replace it.`,{session:t.session,target:t.target})}async function nt(e,t,n){try{return await e.leases.heartbeat({tenant:n.tenant,runId:n.runId,leaseId:t,leaseBackend:n.leaseBackend,leaseProvider:n.leaseProvider,clientId:n.clientId,deviceKey:n.deviceKey,ttlMs:n.ttlMs})}catch(e){if(rt(e))return;throw e}}function rt(t){return!(t instanceof e)||t.code!==`UNAUTHORIZED`?!1:t.details?.reason===`LEASE_NOT_FOUND`||t.details?.reason===`LEASE_EXPIRED`||t.details?.reason===`LEASE_REVOKED`}export{A as C,E as D,T as E,le as S,D as T,de as _,X as a,k as b,W as c,Ce as d,U as f,j as g,be as h,J as i,we as l,V as m,Ee as n,q as o,xe as p,Ue as r,ze as s,Z as t,Se as u,N as v,ce as w,M as x,I as y};
|
|
1
|
+
import{_ as e}from"./sdk-contracts.js";import{_ as t,a as n,b as r,c as i}from"./sdk-device.js";import{Kt as a,Xt as o,Yt as s,t as c}from"./prepare-kind.js";import{_ as l}from"./screenshot-result.js";import{n as u,t as d}from"./command-catalog.js";import{t as f}from"./sdk-remote-config.js";import{A as p,x as m}from"./sdk-android-adb.js";import{v as h}from"./url.js";import{a as g,i as _}from"./client-metro.js";import{n as ee}from"./metro2.js";import{n as te,r as v,t as ne}from"./remote-config2.js";import{a as y,i as b}from"./src2.js";import x from"node:path";import S from"node:crypto";import C from"node:fs";const w={slug:`react-devtools-companion`,runArg:h,displayName:`React DevTools companion`};async function T(e){return await _({...e,definition:w,localBaseUrl:e.localBaseUrl??`http://127.0.0.1:8097`,registerPath:`/api/react-devtools/companion/register`,unregisterPath:`/api/react-devtools/companion/unregister`,devicePort:e.devicePort??8097})}async function E(e){return await g({...e,definition:w})}function D(e){return e===`android-instance`||e===`ios-instance`}function re(e){return[`exec`,`--yes`,`--package`,`agent-cdp@1.6.1`,`--`,`agent-cdp`,...e]}function ie(e){return e.some(e=>e===`--url`||e.startsWith(`--url=`))}function O(e){return e[0]===`target`&&(e[1]===`list`||e[1]===`select`)&&!ie(e)}function ae(e){let t=new URL(e);t.search=``,t.hash=``;let n=t.pathname.replace(/\/+$/,``);return t.pathname=n.endsWith(`/index.bundle`)?n.slice(0,-13)||`/`:n||`/`,t.toString().replace(/\/+$/,``)}function oe(e){let t=e?.metroPublicBaseUrl?.trim();return t?ae(t):null}function se(t,n={}){if(!O(t)||!n.flags?.metroProxyBaseUrl||!D(n.flags.leaseBackend))return t;let r=oe(n.flags);if(!r)throw new e(`INVALID_ARGS`,`cdp remote bridge target discovery requires a React Native dev-server public base URL.`,{hint:`Include metroPublicBaseUrl in the remote config so cdp can reach the local or tunneled Metro/Re.Pack CDP endpoint without bridge proxy authentication.`});return[...t,`--url`,r]}async function ce(e,t={}){return(await m(`npm`,re(se(e,t)),{cwd:t.cwd??process.cwd(),env:t.env??process.env,allowFailure:!0,onStdoutChunk:e=>{process.stdout.write(e)},onStderrChunk:e=>{process.stderr.write(e)}})).exitCode}function k(e){let t=P(e);if(!C.existsSync(t))return null;let n;try{n=JSON.parse(C.readFileSync(t,`utf8`))}catch(t){return z(e,t),null}return me(n)?n:(z(e),null)}function A(e){let t=P({stateDir:e.stateDir,session:e.state.session});C.mkdirSync(x.dirname(t),{recursive:!0}),R(t,e.state),R(F(e.stateDir),{session:e.state.session})}function j(e){return{baseUrl:pe(e.daemonBaseUrl),transport:e.daemonTransport,serverMode:e.daemonServerMode}}function M(e){C.rmSync(P(e),{force:!0});let t=F(e.stateDir);L(e.stateDir)===e.session&&C.rmSync(t,{force:!0})}function le(t){let n=t.validateRemoteConfigHash??!0,r=t.remoteConfig?te({configPath:t.remoteConfig,cwd:t.cwd,env:t.env}):void 0,i=k(t)??(t.allowActiveFallback?I({stateDir:t.stateDir}):null);if(!i||r&&i.remoteConfigPath!==r)return null;if(n&&N(i.remoteConfigPath)!==i.remoteConfigHash)throw new e(`INVALID_ARGS`,`Active remote connection config changed. Run agent-device connect --force to refresh it.`,{remoteConfig:i.remoteConfigPath});let c=fe(i,t),l=a(i);return{runtime:i.runtime,connection:o(l),flags:{...c,remoteConfig:i.remoteConfigPath,daemonBaseUrl:i.daemon?.baseUrl??c.daemonBaseUrl,daemonAuthToken:c.daemonAuthToken,daemonTransport:i.daemon?.transport??c.daemonTransport,daemonServerMode:i.daemon?.serverMode??c.daemonServerMode,...s(l),sessionIsolation:`tenant`,session:i.session,platform:i.platform??c.platform,target:i.target??c.target}}}function ue(e){return o(a(e))}function N(t){try{return S.createHash(`sha256`).update(C.readFileSync(t)).digest(`hex`)}catch(n){throw new e(`INVALID_ARGS`,`Remote config file not found: ${t}`,{cause:n instanceof Error?n.message:String(n)})}}function P(e){return x.join(e.stateDir,`remote-connections`,`${B(e.session)}.json`)}function F(e){return x.join(e,`remote-connections`,`.active-session.json`)}function I(e){let t=L(e.stateDir);return t?k({stateDir:e.stateDir,session:t}):null}function L(e){let t=F(e);if(C.existsSync(t))try{let e=JSON.parse(C.readFileSync(t,`utf8`));return typeof e.session==`string`?e.session:void 0}catch{return}}function de(e){if(e)return S.createHash(`sha256`).update(e).digest(`hex`).slice(0,12)}function fe(e,t){try{return v({configPath:e.remoteConfigPath,cwd:t.cwd,env:t.env}).profile}catch(e){if(t.validateRemoteConfigHash===!1)return{};throw e}}function R(e,t){let n=`${e}.${process.pid}.${S.randomUUID()}.tmp`;try{C.writeFileSync(n,`${JSON.stringify(t,null,2)}\n`,{encoding:`utf8`,mode:384}),C.renameSync(n,e)}catch(e){throw C.rmSync(n,{force:!0}),e}}function pe(e){if(!e)return;let t=new URL(e);t.username=``,t.password=``;for(let e of[...t.searchParams.keys()])/(auth|key|password|secret|token)/i.test(e)&&t.searchParams.delete(e);return t.toString().replace(/\/+$/,``)}function z(e,t){p({level:`warn`,phase:`remote_connection_state_invalid`,data:{session:e.session,cause:t instanceof Error?t.message:t?String(t):void 0}}),M(e)}function B(e){let t=e.replaceAll(/[^a-zA-Z0-9._-]/g,`_`);return t?t===e?t:`${t}-${S.createHash(`sha256`).update(e).digest(`hex`).slice(0,8)}`:`default`}function me(e){if(!e||typeof e!=`object`||Array.isArray(e))return!1;let t=e;return t.version===1&&he(t,[`session`,`remoteConfigPath`,`remoteConfigHash`,`tenant`,`runId`,`connectedAt`,`updatedAt`])&&ge(t,[`leaseId`,`leaseBackend`,`leaseProvider`,`deviceKey`,`clientId`])&&_e(t.daemon)}function he(e,t){return t.every(t=>typeof e[t]==`string`)}function ge(e,t){return t.every(t=>e[t]===void 0||typeof e[t]==`string`)}function _e(e){return e===void 0?!0:!e||typeof e!=`object`||Array.isArray(e)?!1:ve(e)}function ve(e){let t=e;return(t.baseUrl===void 0||typeof t.baseUrl==`string`)&&(t.authToken===void 0||typeof t.authToken==`string`)&&(t.transport===void 0||typeof t.transport==`string`)&&(t.serverMode===void 0||typeof t.serverMode==`string`)}const ye=f.map(e=>e.key);function V(e){let t={};for(let n of ye){let r=e[n];r!==void 0&&(t[n]=r)}return t}function be(e){return e.remoteConfig?{...V(v({configPath:e.remoteConfig,cwd:e.cwd,env:e.env}).profile),remoteConfig:e.remoteConfig}:{}}function xe(e){return e===`cloud`||e===`proxy`||H(e)}function H(e){return e===`limrun`||y(e)}function Se(){return[`cloud`,`proxy`,b.browserStack,b.awsDeviceFarm,`limrun`].join(`, `)}function U(e){return!H(e)}function Ce(e){return e===`proxy`?`proxy`:H(e)?`direct-device-provider`:`remote-provider`}function W(e){return{providerDeviceOrientation:e.providerDeviceOrientation,providerGeoLocation:e.providerGeoLocation,providerTimezone:e.providerTimezone,providerLanguage:e.providerLanguage,providerLocale:e.providerLocale,providerNetworkProfile:e.providerNetworkProfile,providerCustomNetwork:e.providerCustomNetwork,providerNoResignApp:e.providerNoResignApp}}function we(e){return{metroProjectRoot:e.metroProjectRoot,metroKind:e.metroKind,metroPublicBaseUrl:e.metroPublicBaseUrl,metroProxyBaseUrl:e.metroProxyBaseUrl,metroPreparePort:e.metroPreparePort,metroListenHost:e.metroListenHost,metroStatusHost:e.metroStatusHost,metroStartupTimeoutMs:e.metroStartupTimeoutMs,metroProbeTimeoutMs:e.metroProbeTimeoutMs,metroRuntimeFile:e.metroRuntimeFile,metroNoReuseExisting:e.metroNoReuseExisting,metroNoInstallDeps:e.metroNoInstallDeps,launchUrl:e.launchUrl}}const G=new Set([`artifacts`,`connect`,`connection`,`close`,`disconnect`,`metro`,`session`]),K=new Set([`open`]),Te=new Set([u.open,u.install,u.reinstall,d.installSource]);async function Ee(t){let{command:n,flags:r,client:i}=t;if(!r.remoteConfig)return{flags:r,runtime:t.runtime};let a=l(r.stateDir).baseDir,o=v({configPath:r.remoteConfig,cwd:process.cwd(),env:process.env}),s={...V(o.profile),...r,remoteConfig:o.resolvedPath},c=k({stateDir:a,session:s.session??`default`});if(c&&c.remoteConfigPath!==o.resolvedPath)throw new e(`INVALID_ARGS`,`A different remote connection is already active for this session. Run connect --force or disconnect before using a different --remote-config.`,{session:c.session,activeRemoteConfig:c.remoteConfigPath,requestedRemoteConfig:o.resolvedPath});let u=c??Ye(s,o.resolvedPath,o.profile),d={...s,session:u.session},f=Je(u.runtime,d.platform)??t.runtime,p=u,m=!c,h,g=Pe(p);if(g.shouldAllocate(n)){let e=await je({command:n,client:i,state:u,nextState:p,nextFlags:d,policy:g});p=e.state,m||=e.changed,h=e.acquiredLeaseForCleanup}let _=await De({command:n,flags:d,client:i,state:u,nextState:p,runtime:f,positionals:t.positionals,batchSteps:t.batchSteps,forceRuntimePrepare:t.forceRuntimePrepare});return p=_.state,f=_.runtime,m||=_.changed,await Ae({changed:m,stateDir:a,state:p,client:i,acquiredLeaseForCleanup:h,preparedMetroCleanupOnFailure:_.preparedMetroCleanupOnFailure,metroCleanupToStop:_.metroCleanupToStop}),{flags:{...d,session:p.session,leaseId:p.leaseId,leaseBackend:p.leaseBackend,platform:p.platform??d.platform,target:p.target??d.target},runtime:f,connection:ue(p)}}async function De(t){let{command:n,flags:r,state:i,client:a}=t,o=Oe(t.nextState,r),s=t.runtime;if(!Ke(n,r,t.batchSteps,t.positionals)||!Z(r)||!ke(t.forceRuntimePrepare,s,r.platform))return{state:o,runtime:s,changed:!1};if(!o.leaseId)throw new e(`INVALID_ARGS`,`${n} requires a resolved remote lease before Metro runtime can be prepared.`);let c=await Re(r,a,i.remoteConfigPath,i.session,{tenantId:i.tenant,runId:i.runId,leaseId:o.leaseId}),l=!qe(o.metro,c.cleanup);return o={...o,runtime:c.runtime,metro:c.cleanup,updatedAt:new Date().toISOString()},{state:o,runtime:c.runtime,changed:!0,metroCleanupToStop:l?t.nextState.metro:void 0,preparedMetroCleanupOnFailure:l?c.cleanup:void 0}}function Oe(e,t){return e.leaseId||!t.leaseId?e:{...e,leaseId:t.leaseId,leaseBackend:t.leaseBackend}}function ke(e,t,n){return e===!0||!t||!Q(t,n)}async function Ae(e){if(e.changed)try{A({stateDir:e.stateDir,state:e.state})}catch(t){throw await q(e.preparedMetroCleanupOnFailure),await We(e.client,e.state,e.acquiredLeaseForCleanup),t}await q(e.metroCleanupToStop)}async function je(e){let{command:t,client:n,state:r,nextFlags:i,policy:a}=e,o=r.leaseBackend??X(i),s=e.nextState,c=await a.resolveLeaseState({command:t,client:n,state:s,flags:i,leaseBackend:o});s=c.state,c.device&&$(i,c.device);let l=s.leaseBackend??o??Ge(i,t);tt(r,i,l);let u=await Xe(n,s,l,a,i),d=u.lease;return i.leaseId=d.leaseId,i.leaseBackend=l,i.platform=s.platform??i.platform,i.target=s.target??i.target,Me(s,d,l)?{state:s,changed:!1,acquiredLeaseForCleanup:u.acquired?d:void 0}:{state:Ne(s,d,l,i),changed:!0,acquiredLeaseForCleanup:u.acquired?d:void 0}}function Me(e,t,n){return e.leaseId===t.leaseId&&e.leaseBackend===n&&e.deviceKey===(t.deviceKey??e.deviceKey)}function Ne(e,t,n,r){return{...e,leaseId:t.leaseId,leaseBackend:n,leaseProvider:t.leaseProvider??e.leaseProvider,clientId:t.clientId??e.clientId,deviceKey:t.deviceKey??e.deviceKey,platform:e.platform??r.platform,target:e.target??r.target,updatedAt:new Date().toISOString()}}function Pe(e){return e.leaseProvider===`proxy`?Ie:y(e.leaseProvider)?Le:Fe}const Fe={shouldAllocate:e=>!G.has(e),ttlMs:()=>void 0,resolveLeaseState:async e=>({state:e.state})},Ie={shouldAllocate:e=>e!==`devices`&&!G.has(e),ttlMs:()=>3e5,resolveLeaseState:Ze},Le={shouldAllocate:e=>!G.has(e),ttlMs:()=>6e5,resolveLeaseState:async e=>({state:e.state})};async function Re(t,n,r,i,a){if(!t.metroProjectRoot&&!t.metroPublicBaseUrl&&!t.metroProxyBaseUrl)return{};if(t.platform!==`ios`&&t.platform!==`android`)throw new e(`INVALID_ARGS`,`Deferred Metro preparation requires platform "ios" or "android".`);if(!t.metroPublicBaseUrl&&!t.metroProxyBaseUrl)throw new e(`INVALID_ARGS`,`Deferred Metro preparation requires metroPublicBaseUrl or metroProxyBaseUrl when Metro settings are provided.`);let o=await n.metro.prepare({projectRoot:t.metroProjectRoot,kind:c(t.metroKind),publicBaseUrl:t.metroPublicBaseUrl,proxyBaseUrl:t.metroProxyBaseUrl,bearerToken:t.metroBearerToken,bridgeScope:a,launchUrl:t.launchUrl,companionProfileKey:r,companionConsumerKey:i,port:t.metroPreparePort,listenHost:t.metroListenHost,statusHost:t.metroStatusHost,startupTimeoutMs:t.metroStartupTimeoutMs,probeTimeoutMs:t.metroProbeTimeoutMs,reuseExisting:t.metroNoReuseExisting?!1:void 0,installDependenciesIfNeeded:t.metroNoInstallDeps?!1:void 0,runtimeFilePath:t.metroRuntimeFile});return{runtime:t.platform===`ios`?o.iosRuntime:o.androidRuntime,cleanup:t.metroProxyBaseUrl?{projectRoot:o.projectRoot,profileKey:r,consumerKey:i}:void 0}}async function q(e){if(e)try{await ee(e)}catch{}}async function ze(e){try{await E({projectRoot:process.cwd(),stateDir:e.stateDir,profileKey:e.state.remoteConfigPath,consumerKey:e.state.session})}catch{}}async function J(e,t,n){return t.leaseId?await e.leases.release({tenant:t.tenant,runId:t.runId,leaseId:t.leaseId,leaseBackend:t.leaseBackend,daemonBaseUrl:t.daemon?.baseUrl,daemonAuthToken:n,daemonTransport:t.daemon?.transport,daemonServerMode:t.daemon?.serverMode,leaseProvider:t.leaseProvider,clientId:t.clientId,deviceKey:t.deviceKey}):{released:!1}}function Be(e){let t=Ve(e.previous,e.cwd,e.env);return t?{canAuthenticate:!0,daemonAuthToken:t}:e.previous.daemon?.baseUrl===e.nextDaemonBaseUrl?{canAuthenticate:!0,daemonAuthToken:e.ambientDaemonAuthToken}:{canAuthenticate:!1}}function Ve(e,t,n){try{let{profile:r}=ne({configPath:e.remoteConfigPath,cwd:t,env:n});return r.daemonAuthToken&&He(e,r.daemonBaseUrl)?r.daemonAuthToken:void 0}catch{return}}function He(e,t){let n=j({daemonBaseUrl:t})?.baseUrl;return n!==void 0&&n===e.daemon?.baseUrl}async function Ue(e,t,n){if(!t.leaseId)return;let r=Be({previous:t,nextDaemonBaseUrl:n.nextDaemonBaseUrl,ambientDaemonAuthToken:n.ambientDaemonAuthToken,cwd:n.cwd,env:n.env});if(!r.canAuthenticate)return Y(t,`no credential known to belong to that endpoint was available`);try{await J(e,t,r.daemonAuthToken);return}catch{return Y(t,`the release request failed`)}}function Y(e,t){return{status:`unreleased`,message:`Could not release the previous lease ${e.leaseId} (tenant ${e.tenant}, run ${e.runId}) at ${e.daemon?.baseUrl??`its daemon`}: ${t}. It was left in place — release it manually if it is still active.`}}async function We(e,t,n){if(n)try{await e.leases.release({tenant:t.tenant,runId:t.runId,leaseId:n.leaseId,leaseBackend:t.leaseBackend??n.backend,leaseProvider:t.leaseProvider??n.leaseProvider,clientId:t.clientId??n.clientId,deviceKey:t.deviceKey??n.deviceKey})}catch{}}function X(e){if(e.leaseBackend)return e.leaseBackend;if(e.platform===`android`)return`android-instance`;if(e.platform===`ios`)return`ios-instance`}function Ge(t,n){let r=X(t);if(r)return r;throw new e(`INVALID_ARGS`,`${n} requires --platform ios|android or --lease-backend when the remote connection has not resolved a lease yet.`)}function Ke(e,t,n,r=[]){return e===`cdp`?O(r)&&!!t.metroPublicBaseUrl:K.has(e)?!0:e!==`batch`||!n?!1:n.some(e=>{let t=e.command.trim().toLowerCase();return K.has(t)&&e.runtime===void 0})}function Z(e){let t=e.metroKind;return!!(e.metroPublicBaseUrl||e.metroProxyBaseUrl||e.metroProjectRoot||t)}function Q(e,t){return!e.platform||!t||t!==`ios`&&t!==`android`?!0:e.platform===t}function qe(e,t){return e?.projectRoot===t?.projectRoot&&e?.profileKey===t?.profileKey&&e?.consumerKey===t?.consumerKey}function Je(e,t){if(e)return Q(e,t)?e:void 0}function Ye(t,n,r={}){if(!t.tenant)throw new e(`INVALID_ARGS`,`remote command requires tenant in remote config or via --tenant <id>.`);if(!t.runId)throw new e(`INVALID_ARGS`,`remote command requires runId in remote config or via --run-id <id>.`);if(!t.daemonBaseUrl&&U(r.leaseProvider))throw new e(`INVALID_ARGS`,`remote command requires daemonBaseUrl in remote config, config, env, or --daemon-base-url.`);let i=new Date().toISOString();return{version:1,session:t.session??`default`,remoteConfigPath:n,remoteConfigHash:N(n),daemon:j(t),tenant:t.tenant,runId:t.runId,leaseId:t.leaseId,leaseBackend:t.leaseBackend??X(t),leaseProvider:r.leaseProvider,clientId:r.clientId,deviceKey:r.deviceKey,platform:t.platform,target:t.target,connectedAt:i,updatedAt:i}}async function Xe(e,t,n,r,i){if(t.leaseId&&t.leaseBackend===n){let i=await nt(e,t.leaseId,{tenant:t.tenant,runId:t.runId,leaseBackend:n,leaseProvider:t.leaseProvider,clientId:t.clientId,deviceKey:t.deviceKey,ttlMs:r.ttlMs(t)});if(i)return{lease:i,acquired:!1}}return{lease:await e.leases.allocate({tenant:t.tenant,runId:t.runId,leaseBackend:n,leaseProvider:t.leaseProvider,clientId:t.clientId,deviceKey:t.deviceKey,ttlMs:r.ttlMs(t),platform:t.platform??i.platform,target:t.target??i.target,device:i.device,udid:i.udid,serial:i.serial,providerApp:i.providerApp,providerOsVersion:i.providerOsVersion,providerProject:i.providerProject,providerBuild:i.providerBuild,providerSessionName:i.providerSessionName,...W(i),awsProjectArn:i.awsProjectArn,awsDeviceArn:i.awsDeviceArn,awsAppArn:i.awsAppArn,awsRegion:i.awsRegion,awsInteractionMode:i.awsInteractionMode}),acquired:!0}}async function Ze(t){if(!Te.has(t.command)){if(t.state.leaseId&&t.state.deviceKey)return{state:t.state};throw new e(`INVALID_ARGS`,`No active proxy device lease for this session; run open first.`)}let n=await Qe(t.client,t.flags),r=$e(n);return{state:{...t.state,deviceKey:r,leaseBackend:t.state.leaseBackend??t.leaseBackend??et(n),platform:t.state.platform??n.platform,target:t.state.target??n.target,updatedAt:new Date().toISOString()},device:n}}function $(e,t){if(e.platform=t.platform,e.target=t.target??e.target,i(t)){e.udid=t.id;return}t.platform===`android`&&(e.serial=t.id)}async function Qe(e,t){return await r((await e.devices.list({platform:t.platform,target:t.target,device:t.device,udid:t.udid,serial:t.serial,iosSimulatorDeviceSet:t.iosSimulatorDeviceSet,androidDeviceAllowlist:t.androidDeviceAllowlist})).map(e=>({...n(e.platform),id:e.id,name:e.name,kind:e.kind,target:e.target,booted:e.booted})),{platform:t.platform,target:t.target,deviceName:t.device,udid:t.udid,serial:t.serial})}function $e(e){return`${t(e)}:${e.target??`mobile`}:${e.id}`}function et(e){if(i(e))return`ios-instance`;if(e.platform===`android`)return`android-instance`}function tt(t,n,r){if(t.leaseBackend&&t.leaseBackend!==r)throw new e(`INVALID_ARGS`,`Active remote connection is already bound to a different lease backend. Re-run connect --force to replace it.`,{session:t.session,leaseBackend:t.leaseBackend});if(t.platform&&n.platform&&t.platform!==n.platform)throw new e(`INVALID_ARGS`,`Active remote connection is already bound to a different platform. Re-run connect --force to replace it.`,{session:t.session,platform:t.platform});if(t.target&&n.target&&t.target!==n.target)throw new e(`INVALID_ARGS`,`Active remote connection is already bound to a different target. Re-run connect --force to replace it.`,{session:t.session,target:t.target})}async function nt(e,t,n){try{return await e.leases.heartbeat({tenant:n.tenant,runId:n.runId,leaseId:t,leaseBackend:n.leaseBackend,leaseProvider:n.leaseProvider,clientId:n.clientId,deviceKey:n.deviceKey,ttlMs:n.ttlMs})}catch(e){if(rt(e))return;throw e}}function rt(t){return!(t instanceof e)||t.code!==`UNAUTHORIZED`?!1:t.details?.reason===`LEASE_NOT_FOUND`||t.details?.reason===`LEASE_EXPIRED`||t.details?.reason===`LEASE_REVOKED`}export{A as C,E as D,T as E,le as S,D as T,de as _,X as a,k as b,W as c,Ce as d,U as f,j as g,be as h,J as i,we as l,V as m,Ee as n,q as o,xe as p,Ue as r,ze as s,Z as t,Se as u,N as v,ce as w,M as x,I as y};
|