execbro 0.0.1-reserve → 1.10.13
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/LICENSE +32 -0
- package/README.md +496 -0
- package/build/__tests__/helpers/fake-cdp-server.d.ts +56 -0
- package/build/__tests__/helpers/fake-cdp-server.d.ts.map +1 -0
- package/build/__tests__/helpers/fake-cdp-server.js +120 -0
- package/build/__tests__/helpers/fake-cdp-server.js.map +1 -0
- package/build/__tests__/helpers/tap-test-helpers.d.ts +36 -0
- package/build/__tests__/helpers/tap-test-helpers.d.ts.map +1 -0
- package/build/__tests__/helpers/tap-test-helpers.js +130 -0
- package/build/__tests__/helpers/tap-test-helpers.js.map +1 -0
- package/build/__tests__/integration/auto-reconnect.test.d.ts +2 -0
- package/build/__tests__/integration/auto-reconnect.test.d.ts.map +1 -0
- package/build/__tests__/integration/auto-reconnect.test.js +118 -0
- package/build/__tests__/integration/auto-reconnect.test.js.map +1 -0
- package/build/__tests__/integration/connection-health.test.d.ts +2 -0
- package/build/__tests__/integration/connection-health.test.d.ts.map +1 -0
- package/build/__tests__/integration/connection-health.test.js +157 -0
- package/build/__tests__/integration/connection-health.test.js.map +1 -0
- package/build/__tests__/integration/execute-in-app.test.d.ts +2 -0
- package/build/__tests__/integration/execute-in-app.test.d.ts.map +1 -0
- package/build/__tests__/integration/execute-in-app.test.js +124 -0
- package/build/__tests__/integration/execute-in-app.test.js.map +1 -0
- package/build/__tests__/integration/per-call-timeout.test.d.ts +2 -0
- package/build/__tests__/integration/per-call-timeout.test.d.ts.map +1 -0
- package/build/__tests__/integration/per-call-timeout.test.js +103 -0
- package/build/__tests__/integration/per-call-timeout.test.js.map +1 -0
- package/build/__tests__/integration/tap-strategies.test.d.ts +2 -0
- package/build/__tests__/integration/tap-strategies.test.d.ts.map +1 -0
- package/build/__tests__/integration/tap-strategies.test.js +330 -0
- package/build/__tests__/integration/tap-strategies.test.js.map +1 -0
- package/build/__tests__/integration/tools.test.d.ts +2 -0
- package/build/__tests__/integration/tools.test.d.ts.map +1 -0
- package/build/__tests__/integration/tools.test.js +227 -0
- package/build/__tests__/integration/tools.test.js.map +1 -0
- package/build/__tests__/setup.d.ts +2 -0
- package/build/__tests__/setup.d.ts.map +1 -0
- package/build/__tests__/setup.js +15 -0
- package/build/__tests__/setup.js.map +1 -0
- package/build/__tests__/unit/androidEmulatorAvds.test.d.ts +2 -0
- package/build/__tests__/unit/androidEmulatorAvds.test.d.ts.map +1 -0
- package/build/__tests__/unit/androidEmulatorAvds.test.js +98 -0
- package/build/__tests__/unit/androidEmulatorAvds.test.js.map +1 -0
- package/build/__tests__/unit/buildToken.test.d.ts +2 -0
- package/build/__tests__/unit/buildToken.test.d.ts.map +1 -0
- package/build/__tests__/unit/buildToken.test.js +22 -0
- package/build/__tests__/unit/buildToken.test.js.map +1 -0
- package/build/__tests__/unit/bundle.test.d.ts +2 -0
- package/build/__tests__/unit/bundle.test.d.ts.map +1 -0
- package/build/__tests__/unit/bundle.test.js +53 -0
- package/build/__tests__/unit/bundle.test.js.map +1 -0
- package/build/__tests__/unit/burst.test.d.ts +2 -0
- package/build/__tests__/unit/burst.test.d.ts.map +1 -0
- package/build/__tests__/unit/burst.test.js +54 -0
- package/build/__tests__/unit/burst.test.js.map +1 -0
- package/build/__tests__/unit/connection-health.test.d.ts +2 -0
- package/build/__tests__/unit/connection-health.test.d.ts.map +1 -0
- package/build/__tests__/unit/connection-health.test.js +38 -0
- package/build/__tests__/unit/connection-health.test.js.map +1 -0
- package/build/__tests__/unit/debugGlobals.test.d.ts +2 -0
- package/build/__tests__/unit/debugGlobals.test.d.ts.map +1 -0
- package/build/__tests__/unit/debugGlobals.test.js +14 -0
- package/build/__tests__/unit/debugGlobals.test.js.map +1 -0
- package/build/__tests__/unit/deviceDiscovery.test.d.ts +2 -0
- package/build/__tests__/unit/deviceDiscovery.test.d.ts.map +1 -0
- package/build/__tests__/unit/deviceDiscovery.test.js +119 -0
- package/build/__tests__/unit/deviceDiscovery.test.js.map +1 -0
- package/build/__tests__/unit/deviceResolver.test.d.ts +2 -0
- package/build/__tests__/unit/deviceResolver.test.d.ts.map +1 -0
- package/build/__tests__/unit/deviceResolver.test.js +261 -0
- package/build/__tests__/unit/deviceResolver.test.js.map +1 -0
- package/build/__tests__/unit/escapeNonAscii.test.d.ts +2 -0
- package/build/__tests__/unit/escapeNonAscii.test.d.ts.map +1 -0
- package/build/__tests__/unit/escapeNonAscii.test.js +76 -0
- package/build/__tests__/unit/escapeNonAscii.test.js.map +1 -0
- package/build/__tests__/unit/exec.test.d.ts +2 -0
- package/build/__tests__/unit/exec.test.d.ts.map +1 -0
- package/build/__tests__/unit/exec.test.js +54 -0
- package/build/__tests__/unit/exec.test.js.map +1 -0
- package/build/__tests__/unit/executor.test.d.ts +2 -0
- package/build/__tests__/unit/executor.test.d.ts.map +1 -0
- package/build/__tests__/unit/executor.test.js +220 -0
- package/build/__tests__/unit/executor.test.js.map +1 -0
- package/build/__tests__/unit/failureArtifact.test.d.ts +2 -0
- package/build/__tests__/unit/failureArtifact.test.d.ts.map +1 -0
- package/build/__tests__/unit/failureArtifact.test.js +207 -0
- package/build/__tests__/unit/failureArtifact.test.js.map +1 -0
- package/build/__tests__/unit/fastRefreshRecorder.test.d.ts +2 -0
- package/build/__tests__/unit/fastRefreshRecorder.test.d.ts.map +1 -0
- package/build/__tests__/unit/fastRefreshRecorder.test.js +68 -0
- package/build/__tests__/unit/fastRefreshRecorder.test.js.map +1 -0
- package/build/__tests__/unit/fastRefreshTools.test.d.ts +2 -0
- package/build/__tests__/unit/fastRefreshTools.test.d.ts.map +1 -0
- package/build/__tests__/unit/fastRefreshTools.test.js +112 -0
- package/build/__tests__/unit/fastRefreshTools.test.js.map +1 -0
- package/build/__tests__/unit/fiberMatch.test.d.ts +2 -0
- package/build/__tests__/unit/fiberMatch.test.d.ts.map +1 -0
- package/build/__tests__/unit/fiberMatch.test.js +114 -0
- package/build/__tests__/unit/fiberMatch.test.js.map +1 -0
- package/build/__tests__/unit/fingerprint.test.d.ts +2 -0
- package/build/__tests__/unit/fingerprint.test.d.ts.map +1 -0
- package/build/__tests__/unit/fingerprint.test.js +99 -0
- package/build/__tests__/unit/fingerprint.test.js.map +1 -0
- package/build/__tests__/unit/focusedInput.test.d.ts +2 -0
- package/build/__tests__/unit/focusedInput.test.d.ts.map +1 -0
- package/build/__tests__/unit/focusedInput.test.js +58 -0
- package/build/__tests__/unit/focusedInput.test.js.map +1 -0
- package/build/__tests__/unit/focusedInputTools.test.d.ts +2 -0
- package/build/__tests__/unit/focusedInputTools.test.d.ts.map +1 -0
- package/build/__tests__/unit/focusedInputTools.test.js +79 -0
- package/build/__tests__/unit/focusedInputTools.test.js.map +1 -0
- package/build/__tests__/unit/iconSemantics.test.d.ts +2 -0
- package/build/__tests__/unit/iconSemantics.test.d.ts.map +1 -0
- package/build/__tests__/unit/iconSemantics.test.js +80 -0
- package/build/__tests__/unit/iconSemantics.test.js.map +1 -0
- package/build/__tests__/unit/imageBuffer.test.d.ts +2 -0
- package/build/__tests__/unit/imageBuffer.test.d.ts.map +1 -0
- package/build/__tests__/unit/imageBuffer.test.js +128 -0
- package/build/__tests__/unit/imageBuffer.test.js.map +1 -0
- package/build/__tests__/unit/logs.test.d.ts +2 -0
- package/build/__tests__/unit/logs.test.d.ts.map +1 -0
- package/build/__tests__/unit/logs.test.js +90 -0
- package/build/__tests__/unit/logs.test.js.map +1 -0
- package/build/__tests__/unit/measureComponent.test.d.ts +2 -0
- package/build/__tests__/unit/measureComponent.test.d.ts.map +1 -0
- package/build/__tests__/unit/measureComponent.test.js +66 -0
- package/build/__tests__/unit/measureComponent.test.js.map +1 -0
- package/build/__tests__/unit/measureComponentTools.test.d.ts +2 -0
- package/build/__tests__/unit/measureComponentTools.test.d.ts.map +1 -0
- package/build/__tests__/unit/measureComponentTools.test.js +94 -0
- package/build/__tests__/unit/measureComponentTools.test.js.map +1 -0
- package/build/__tests__/unit/metro.test.d.ts +2 -0
- package/build/__tests__/unit/metro.test.d.ts.map +1 -0
- package/build/__tests__/unit/metro.test.js +61 -0
- package/build/__tests__/unit/metro.test.js.map +1 -0
- package/build/__tests__/unit/network.test.d.ts +2 -0
- package/build/__tests__/unit/network.test.d.ts.map +1 -0
- package/build/__tests__/unit/network.test.js +102 -0
- package/build/__tests__/unit/network.test.js.map +1 -0
- package/build/__tests__/unit/networkInterceptor.test.d.ts +2 -0
- package/build/__tests__/unit/networkInterceptor.test.d.ts.map +1 -0
- package/build/__tests__/unit/networkInterceptor.test.js +104 -0
- package/build/__tests__/unit/networkInterceptor.test.js.map +1 -0
- package/build/__tests__/unit/probe.test.d.ts +2 -0
- package/build/__tests__/unit/probe.test.d.ts.map +1 -0
- package/build/__tests__/unit/probe.test.js +62 -0
- package/build/__tests__/unit/probe.test.js.map +1 -0
- package/build/__tests__/unit/rnGlobalsBootstrap.test.d.ts +2 -0
- package/build/__tests__/unit/rnGlobalsBootstrap.test.d.ts.map +1 -0
- package/build/__tests__/unit/rnGlobalsBootstrap.test.js +29 -0
- package/build/__tests__/unit/rnGlobalsBootstrap.test.js.map +1 -0
- package/build/__tests__/unit/screenState.test.d.ts +2 -0
- package/build/__tests__/unit/screenState.test.d.ts.map +1 -0
- package/build/__tests__/unit/screenState.test.js +384 -0
- package/build/__tests__/unit/screenState.test.js.map +1 -0
- package/build/__tests__/unit/screenshot-diff.test.d.ts +2 -0
- package/build/__tests__/unit/screenshot-diff.test.d.ts.map +1 -0
- package/build/__tests__/unit/screenshot-diff.test.js +97 -0
- package/build/__tests__/unit/screenshot-diff.test.js.map +1 -0
- package/build/__tests__/unit/tap-evidence.test.d.ts +2 -0
- package/build/__tests__/unit/tap-evidence.test.d.ts.map +1 -0
- package/build/__tests__/unit/tap-evidence.test.js +89 -0
- package/build/__tests__/unit/tap-evidence.test.js.map +1 -0
- package/build/__tests__/unit/tap.test.d.ts +2 -0
- package/build/__tests__/unit/tap.test.d.ts.map +1 -0
- package/build/__tests__/unit/tap.test.js +767 -0
- package/build/__tests__/unit/tap.test.js.map +1 -0
- package/build/__tests__/unit/timeoutClamp.test.d.ts +2 -0
- package/build/__tests__/unit/timeoutClamp.test.d.ts.map +1 -0
- package/build/__tests__/unit/timeoutClamp.test.js +17 -0
- package/build/__tests__/unit/timeoutClamp.test.js.map +1 -0
- package/build/__tests__/unit/toolDescriptions.test.d.ts +2 -0
- package/build/__tests__/unit/toolDescriptions.test.d.ts.map +1 -0
- package/build/__tests__/unit/toolDescriptions.test.js +145 -0
- package/build/__tests__/unit/toolDescriptions.test.js.map +1 -0
- package/build/__tests__/unit/transportClassify.test.d.ts +2 -0
- package/build/__tests__/unit/transportClassify.test.d.ts.map +1 -0
- package/build/__tests__/unit/transportClassify.test.js +60 -0
- package/build/__tests__/unit/transportClassify.test.js.map +1 -0
- package/build/__tests__/unit/verifyAction.test.d.ts +2 -0
- package/build/__tests__/unit/verifyAction.test.d.ts.map +1 -0
- package/build/__tests__/unit/verifyAction.test.js +26 -0
- package/build/__tests__/unit/verifyAction.test.js.map +1 -0
- package/build/core/android.d.ts +299 -0
- package/build/core/android.d.ts.map +1 -0
- package/build/core/android.js +1582 -0
- package/build/core/android.js.map +1 -0
- package/build/core/appDetection.d.ts +20 -0
- package/build/core/appDetection.d.ts.map +1 -0
- package/build/core/appDetection.js +167 -0
- package/build/core/appDetection.js.map +1 -0
- package/build/core/bundle.d.ts +49 -0
- package/build/core/bundle.d.ts.map +1 -0
- package/build/core/bundle.js +356 -0
- package/build/core/bundle.js.map +1 -0
- package/build/core/componentSearch.d.ts +41 -0
- package/build/core/componentSearch.d.ts.map +1 -0
- package/build/core/componentSearch.js +588 -0
- package/build/core/componentSearch.js.map +1 -0
- package/build/core/componentTree.d.ts +13 -0
- package/build/core/componentTree.d.ts.map +1 -0
- package/build/core/componentTree.js +275 -0
- package/build/core/componentTree.js.map +1 -0
- package/build/core/config.d.ts +9 -0
- package/build/core/config.d.ts.map +1 -0
- package/build/core/config.js +28 -0
- package/build/core/config.js.map +1 -0
- package/build/core/connection.d.ts +102 -0
- package/build/core/connection.d.ts.map +1 -0
- package/build/core/connection.js +1710 -0
- package/build/core/connection.js.map +1 -0
- package/build/core/connectionState.d.ts +122 -0
- package/build/core/connectionState.d.ts.map +1 -0
- package/build/core/connectionState.js +313 -0
- package/build/core/connectionState.js.map +1 -0
- package/build/core/debugGlobals.d.ts +6 -0
- package/build/core/debugGlobals.d.ts.map +1 -0
- package/build/core/debugGlobals.js +370 -0
- package/build/core/debugGlobals.js.map +1 -0
- package/build/core/deviceDiscovery.d.ts +52 -0
- package/build/core/deviceDiscovery.d.ts.map +1 -0
- package/build/core/deviceDiscovery.js +74 -0
- package/build/core/deviceDiscovery.js.map +1 -0
- package/build/core/deviceResolver.d.ts +44 -0
- package/build/core/deviceResolver.d.ts.map +1 -0
- package/build/core/deviceResolver.js +225 -0
- package/build/core/deviceResolver.js.map +1 -0
- package/build/core/errorScreenParser.d.ts +30 -0
- package/build/core/errorScreenParser.d.ts.map +1 -0
- package/build/core/errorScreenParser.js +198 -0
- package/build/core/errorScreenParser.js.map +1 -0
- package/build/core/errors.d.ts +14 -0
- package/build/core/errors.d.ts.map +1 -0
- package/build/core/errors.js +17 -0
- package/build/core/errors.js.map +1 -0
- package/build/core/escapeNonAscii.d.ts +18 -0
- package/build/core/escapeNonAscii.d.ts.map +1 -0
- package/build/core/escapeNonAscii.js +352 -0
- package/build/core/escapeNonAscii.js.map +1 -0
- package/build/core/exec.d.ts +22 -0
- package/build/core/exec.d.ts.map +1 -0
- package/build/core/exec.js +54 -0
- package/build/core/exec.js.map +1 -0
- package/build/core/executor.d.ts +9 -0
- package/build/core/executor.d.ts.map +1 -0
- package/build/core/executor.js +12 -0
- package/build/core/executor.js.map +1 -0
- package/build/core/failureArtifact.d.ts +120 -0
- package/build/core/failureArtifact.d.ts.map +1 -0
- package/build/core/failureArtifact.js +113 -0
- package/build/core/failureArtifact.js.map +1 -0
- package/build/core/fastRefreshRecorder.d.ts +23 -0
- package/build/core/fastRefreshRecorder.d.ts.map +1 -0
- package/build/core/fastRefreshRecorder.js +83 -0
- package/build/core/fastRefreshRecorder.js.map +1 -0
- package/build/core/fastRefreshTools.d.ts +19 -0
- package/build/core/fastRefreshTools.d.ts.map +1 -0
- package/build/core/fastRefreshTools.js +71 -0
- package/build/core/fastRefreshTools.js.map +1 -0
- package/build/core/feedback.d.ts +18 -0
- package/build/core/feedback.d.ts.map +1 -0
- package/build/core/feedback.js +73 -0
- package/build/core/feedback.js.map +1 -0
- package/build/core/fiberMatch.d.ts +25 -0
- package/build/core/fiberMatch.d.ts.map +1 -0
- package/build/core/fiberMatch.js +35 -0
- package/build/core/fiberMatch.js.map +1 -0
- package/build/core/fingerprint.d.ts +4 -0
- package/build/core/fingerprint.d.ts.map +1 -0
- package/build/core/fingerprint.js +47 -0
- package/build/core/fingerprint.js.map +1 -0
- package/build/core/focusedInput.d.ts +27 -0
- package/build/core/focusedInput.d.ts.map +1 -0
- package/build/core/focusedInput.js +110 -0
- package/build/core/focusedInput.js.map +1 -0
- package/build/core/focusedInputTools.d.ts +21 -0
- package/build/core/focusedInputTools.d.ts.map +1 -0
- package/build/core/focusedInputTools.js +51 -0
- package/build/core/focusedInputTools.js.map +1 -0
- package/build/core/format.d.ts +8 -0
- package/build/core/format.d.ts.map +1 -0
- package/build/core/format.js +34 -0
- package/build/core/format.js.map +1 -0
- package/build/core/guides.d.ts +21 -0
- package/build/core/guides.d.ts.map +1 -0
- package/build/core/guides.js +397 -0
- package/build/core/guides.js.map +1 -0
- package/build/core/iconSemantics.d.ts +18 -0
- package/build/core/iconSemantics.d.ts.map +1 -0
- package/build/core/iconSemantics.js +114 -0
- package/build/core/iconSemantics.js.map +1 -0
- package/build/core/imageBuffer.d.ts +37 -0
- package/build/core/imageBuffer.d.ts.map +1 -0
- package/build/core/imageBuffer.js +58 -0
- package/build/core/imageBuffer.js.map +1 -0
- package/build/core/index.d.ts +37 -0
- package/build/core/index.d.ts.map +1 -0
- package/build/core/index.js +66 -0
- package/build/core/index.js.map +1 -0
- package/build/core/inspector.d.ts +55 -0
- package/build/core/inspector.d.ts.map +1 -0
- package/build/core/inspector.js +603 -0
- package/build/core/inspector.js.map +1 -0
- package/build/core/ios.d.ts +263 -0
- package/build/core/ios.d.ts.map +1 -0
- package/build/core/ios.js +1705 -0
- package/build/core/ios.js.map +1 -0
- package/build/core/jsExecute.d.ts +62 -0
- package/build/core/jsExecute.d.ts.map +1 -0
- package/build/core/jsExecute.js +696 -0
- package/build/core/jsExecute.js.map +1 -0
- package/build/core/license.d.ts +48 -0
- package/build/core/license.d.ts.map +1 -0
- package/build/core/license.js +267 -0
- package/build/core/license.js.map +1 -0
- package/build/core/logbox.d.ts +58 -0
- package/build/core/logbox.d.ts.map +1 -0
- package/build/core/logbox.js +330 -0
- package/build/core/logbox.js.map +1 -0
- package/build/core/logs.d.ts +44 -0
- package/build/core/logs.d.ts.map +1 -0
- package/build/core/logs.js +149 -0
- package/build/core/logs.js.map +1 -0
- package/build/core/measureComponent.d.ts +19 -0
- package/build/core/measureComponent.d.ts.map +1 -0
- package/build/core/measureComponent.js +94 -0
- package/build/core/measureComponent.js.map +1 -0
- package/build/core/measureComponentTools.d.ts +6 -0
- package/build/core/measureComponentTools.d.ts.map +1 -0
- package/build/core/measureComponentTools.js +43 -0
- package/build/core/measureComponentTools.js.map +1 -0
- package/build/core/metro.d.ts +31 -0
- package/build/core/metro.d.ts.map +1 -0
- package/build/core/metro.js +124 -0
- package/build/core/metro.js.map +1 -0
- package/build/core/nativeOnlyHints.d.ts +14 -0
- package/build/core/nativeOnlyHints.d.ts.map +1 -0
- package/build/core/nativeOnlyHints.js +58 -0
- package/build/core/nativeOnlyHints.js.map +1 -0
- package/build/core/network.d.ts +43 -0
- package/build/core/network.d.ts.map +1 -0
- package/build/core/network.js +217 -0
- package/build/core/network.js.map +1 -0
- package/build/core/networkInterceptor.d.ts +30 -0
- package/build/core/networkInterceptor.d.ts.map +1 -0
- package/build/core/networkInterceptor.js +211 -0
- package/build/core/networkInterceptor.js.map +1 -0
- package/build/core/ocr.d.ts +87 -0
- package/build/core/ocr.d.ts.map +1 -0
- package/build/core/ocr.js +335 -0
- package/build/core/ocr.js.map +1 -0
- package/build/core/paths.d.ts +2 -0
- package/build/core/paths.d.ts.map +1 -0
- package/build/core/paths.js +28 -0
- package/build/core/paths.js.map +1 -0
- package/build/core/posthog.d.ts +5 -0
- package/build/core/posthog.d.ts.map +1 -0
- package/build/core/posthog.js +52 -0
- package/build/core/posthog.js.map +1 -0
- package/build/core/pressables.d.ts +46 -0
- package/build/core/pressables.d.ts.map +1 -0
- package/build/core/pressables.js +1719 -0
- package/build/core/pressables.js.map +1 -0
- package/build/core/probe.d.ts +12 -0
- package/build/core/probe.d.ts.map +1 -0
- package/build/core/probe.js +56 -0
- package/build/core/probe.js.map +1 -0
- package/build/core/redux.d.ts +22 -0
- package/build/core/redux.d.ts.map +1 -0
- package/build/core/redux.js +116 -0
- package/build/core/redux.js.map +1 -0
- package/build/core/register.d.ts +8 -0
- package/build/core/register.d.ts.map +1 -0
- package/build/core/register.js +202 -0
- package/build/core/register.js.map +1 -0
- package/build/core/rnGlobalsBootstrap.d.ts +16 -0
- package/build/core/rnGlobalsBootstrap.d.ts.map +1 -0
- package/build/core/rnGlobalsBootstrap.js +116 -0
- package/build/core/rnGlobalsBootstrap.js.map +1 -0
- package/build/core/screenLayout.d.ts +53 -0
- package/build/core/screenLayout.d.ts.map +1 -0
- package/build/core/screenLayout.js +878 -0
- package/build/core/screenLayout.js.map +1 -0
- package/build/core/screenState.d.ts +166 -0
- package/build/core/screenState.d.ts.map +1 -0
- package/build/core/screenState.js +1352 -0
- package/build/core/screenState.js.map +1 -0
- package/build/core/sdkBridge.d.ts +67 -0
- package/build/core/sdkBridge.d.ts.map +1 -0
- package/build/core/sdkBridge.js +148 -0
- package/build/core/sdkBridge.js.map +1 -0
- package/build/core/state.d.ts +37 -0
- package/build/core/state.d.ts.map +1 -0
- package/build/core/state.js +124 -0
- package/build/core/state.js.map +1 -0
- package/build/core/telemetry.d.ts +50 -0
- package/build/core/telemetry.d.ts.map +1 -0
- package/build/core/telemetry.js +653 -0
- package/build/core/telemetry.js.map +1 -0
- package/build/core/toolHelpers.d.ts +24 -0
- package/build/core/toolHelpers.d.ts.map +1 -0
- package/build/core/toolHelpers.js +118 -0
- package/build/core/toolHelpers.js.map +1 -0
- package/build/core/types.d.ts +162 -0
- package/build/core/types.d.ts.map +1 -0
- package/build/core/types.js +2 -0
- package/build/core/types.js.map +1 -0
- package/build/index.d.ts +4 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +132 -0
- package/build/index.js.map +1 -0
- package/build/pro/screenshot-diff.d.ts +10 -0
- package/build/pro/screenshot-diff.d.ts.map +1 -0
- package/build/pro/screenshot-diff.js +38 -0
- package/build/pro/screenshot-diff.js.map +1 -0
- package/build/pro/tap.d.ts +291 -0
- package/build/pro/tap.d.ts.map +1 -0
- package/build/pro/tap.js +1839 -0
- package/build/pro/tap.js.map +1 -0
- package/build/pro/verifyAction.d.ts +50 -0
- package/build/pro/verifyAction.d.ts.map +1 -0
- package/build/pro/verifyAction.js +285 -0
- package/build/pro/verifyAction.js.map +1 -0
- package/build/tools/_deviceArg.d.ts +45 -0
- package/build/tools/_deviceArg.d.ts.map +1 -0
- package/build/tools/_deviceArg.js +58 -0
- package/build/tools/_deviceArg.js.map +1 -0
- package/build/tools/accountTools.d.ts +46 -0
- package/build/tools/accountTools.d.ts.map +1 -0
- package/build/tools/accountTools.js +223 -0
- package/build/tools/accountTools.js.map +1 -0
- package/build/tools/bundleTools.d.ts +3 -0
- package/build/tools/bundleTools.d.ts.map +1 -0
- package/build/tools/bundleTools.js +375 -0
- package/build/tools/bundleTools.js.map +1 -0
- package/build/tools/componentTools.d.ts +3 -0
- package/build/tools/componentTools.d.ts.map +1 -0
- package/build/tools/componentTools.js +746 -0
- package/build/tools/componentTools.js.map +1 -0
- package/build/tools/connectionTools.d.ts +3 -0
- package/build/tools/connectionTools.d.ts.map +1 -0
- package/build/tools/connectionTools.js +625 -0
- package/build/tools/connectionTools.js.map +1 -0
- package/build/tools/deviceTools.d.ts +3 -0
- package/build/tools/deviceTools.d.ts.map +1 -0
- package/build/tools/deviceTools.js +423 -0
- package/build/tools/deviceTools.js.map +1 -0
- package/build/tools/executionTools.d.ts +3 -0
- package/build/tools/executionTools.d.ts.map +1 -0
- package/build/tools/executionTools.js +243 -0
- package/build/tools/executionTools.js.map +1 -0
- package/build/tools/interactionTools.d.ts +3 -0
- package/build/tools/interactionTools.d.ts.map +1 -0
- package/build/tools/interactionTools.js +539 -0
- package/build/tools/interactionTools.js.map +1 -0
- package/build/tools/logTools.d.ts +3 -0
- package/build/tools/logTools.d.ts.map +1 -0
- package/build/tools/logTools.js +371 -0
- package/build/tools/logTools.js.map +1 -0
- package/build/tools/metaTools.d.ts +7 -0
- package/build/tools/metaTools.d.ts.map +1 -0
- package/build/tools/metaTools.js +186 -0
- package/build/tools/metaTools.js.map +1 -0
- package/build/tools/networkTools.d.ts +3 -0
- package/build/tools/networkTools.d.ts.map +1 -0
- package/build/tools/networkTools.js +478 -0
- package/build/tools/networkTools.js.map +1 -0
- package/build/tools/reduxTools.d.ts +3 -0
- package/build/tools/reduxTools.d.ts.map +1 -0
- package/build/tools/reduxTools.js +83 -0
- package/build/tools/reduxTools.js.map +1 -0
- package/build/tools/screenshotTools.d.ts +3 -0
- package/build/tools/screenshotTools.d.ts.map +1 -0
- package/build/tools/screenshotTools.js +703 -0
- package/build/tools/screenshotTools.js.map +1 -0
- package/package.json +63 -2
|
@@ -0,0 +1,625 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { registerToolWithTelemetry } from "../core/register.js";
|
|
3
|
+
import { scanMetroPorts, fetchDevices, filterDebuggableDevices, connectToDevice, ensureConnection, getConnectedAppByDevice, getConnectedApps, getContextHealth, getAllConnectionMetadata, getAllConnectionStates, getConnectionEvents, formatDuration, cancelAllReconnectionTimers, cancelReconnectionTimer, clearAllCDPMessageTimes, clearAllConnectionState, suppressReconnection, clearReconnectionSuppression, purgeStaleConnectionsForPorts, connectMetroBuildEvents, disconnectMetroBuildEvents, reloadApp, connectedApps, isUiDriverAvailable, getTotalLogCount, suppressReconnectionForKey, getWebSocketStateName, awaitAppDetection, } from "../core/index.js";
|
|
4
|
+
export function registerConnectionTools(server) {
|
|
5
|
+
// Tool: Scan for Metro servers
|
|
6
|
+
registerToolWithTelemetry(server, "scan_metro", {
|
|
7
|
+
description: "Scan for running Metro bundler servers and automatically connect to any found React Native apps. This is typically the FIRST tool to call when starting a debugging session - it establishes the connection needed for other tools like get_logs, list_debug_globals, execute_in_app, and reload_app.\n" +
|
|
8
|
+
"PURPOSE: Discover Metro on common ports (8081, 8082, 19000-19002) and auto-connect all React Native debugger targets it advertises.\n" +
|
|
9
|
+
"WHEN TO USE: At the start of any session, or after the user restarts Metro / boots a new simulator.\n" +
|
|
10
|
+
"WORKFLOW: scan_metro -> get_apps -> get_logs / ios_screenshot / tap.\n" +
|
|
11
|
+
"GOOD: scan_metro()\n" +
|
|
12
|
+
"BAD: scan_metro() called repeatedly in a loop — use ensure_connection to re-verify an existing connection.\n" +
|
|
13
|
+
"SEE ALSO: call get_usage_guide(topic=\"setup\") for the full session-setup playbook.",
|
|
14
|
+
inputSchema: {
|
|
15
|
+
startPort: z.coerce.number().optional().default(8081).describe("Start port for scanning (default: 8081)"),
|
|
16
|
+
endPort: z.coerce.number().optional().default(19002).describe("End port for scanning (default: 19002)")
|
|
17
|
+
}
|
|
18
|
+
}, async ({ startPort, endPort }) => {
|
|
19
|
+
// Clear reconnection suppression (in case user previously called disconnect_metro)
|
|
20
|
+
clearReconnectionSuppression();
|
|
21
|
+
const openPorts = await scanMetroPorts(startPort, endPort);
|
|
22
|
+
if (openPorts.length === 0) {
|
|
23
|
+
return {
|
|
24
|
+
content: [
|
|
25
|
+
{
|
|
26
|
+
type: "text",
|
|
27
|
+
text: "No Metro servers found. Make sure Metro bundler is running (npm start or expo start)."
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
// Phase 1: Fetch devices from all ports first
|
|
33
|
+
const portDevices = new Map();
|
|
34
|
+
for (const port of openPorts) {
|
|
35
|
+
const devices = await fetchDevices(port);
|
|
36
|
+
const debuggable = filterDebuggableDevices(devices);
|
|
37
|
+
if (debuggable.length > 0) {
|
|
38
|
+
portDevices.set(port, debuggable);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// Phase 1.5: Purge stale connections for scanned ports
|
|
42
|
+
// When Metro restarts with a different app, device IDs change.
|
|
43
|
+
// Old connections remain in connectedApps — remove them before connecting new devices.
|
|
44
|
+
const purged = purgeStaleConnectionsForPorts(portDevices);
|
|
45
|
+
// Phase 2: Assign each device to the best port
|
|
46
|
+
// If a device appears on multiple ports, prefer the port where it has
|
|
47
|
+
// the fewest OTHER unique devices (i.e. its dedicated Metro server)
|
|
48
|
+
const devicePortAssignment = new Map(); // deviceName -> best port
|
|
49
|
+
const allDeviceNames = new Map();
|
|
50
|
+
for (const [port, devices] of portDevices) {
|
|
51
|
+
for (const device of devices) {
|
|
52
|
+
const name = device.deviceName || device.title;
|
|
53
|
+
const entry = allDeviceNames.get(name);
|
|
54
|
+
if (entry) {
|
|
55
|
+
entry.ports.push(port);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
allDeviceNames.set(name, { device, ports: [port] });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
for (const [name, { ports }] of allDeviceNames) {
|
|
63
|
+
if (ports.length === 1) {
|
|
64
|
+
devicePortAssignment.set(name, ports[0]);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
// Prefer the port with fewer OTHER unique devices (the dedicated Metro)
|
|
68
|
+
let bestPort = ports[0];
|
|
69
|
+
let fewestOthers = Infinity;
|
|
70
|
+
for (const port of ports) {
|
|
71
|
+
const othersOnPort = (portDevices.get(port) || [])
|
|
72
|
+
.filter(d => (d.deviceName || d.title) !== name).length;
|
|
73
|
+
if (othersOnPort < fewestOthers) {
|
|
74
|
+
fewestOthers = othersOnPort;
|
|
75
|
+
bestPort = port;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
devicePortAssignment.set(name, bestPort);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// Phase 3: Connect devices to their assigned ports
|
|
82
|
+
const results = [];
|
|
83
|
+
if (purged.length > 0) {
|
|
84
|
+
results.push(`Purged ${purged.length} stale connection(s): ${purged.join(", ")}`);
|
|
85
|
+
}
|
|
86
|
+
for (const port of openPorts) {
|
|
87
|
+
const devices = portDevices.get(port);
|
|
88
|
+
if (!devices) {
|
|
89
|
+
results.push(`Port ${port}: No debuggable devices found`);
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
results.push(`Port ${port}: Found ${devices.length} device(s)`);
|
|
93
|
+
for (const device of devices) {
|
|
94
|
+
const name = device.deviceName || device.title;
|
|
95
|
+
const assignedPort = devicePortAssignment.get(name);
|
|
96
|
+
if (assignedPort !== port) {
|
|
97
|
+
results.push(` - ${name}: Skipped (assigned to port ${assignedPort})`);
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
try {
|
|
101
|
+
const connectionResult = await connectToDevice(device, port);
|
|
102
|
+
const isStale = connectionResult.includes("stale CDP target");
|
|
103
|
+
const prefix = isStale ? " - STALE" : " -";
|
|
104
|
+
results.push(`${prefix} ${connectionResult}`);
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
results.push(` - ${name}: Failed - ${error}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// Connect to Metro build events for this port
|
|
111
|
+
try {
|
|
112
|
+
await connectMetroBuildEvents(port);
|
|
113
|
+
results.push(` - Connected to Metro build events`);
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
// Build events connection is optional
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// Advisory if any CDP targets failed the liveness probe
|
|
120
|
+
const staleCount = results.filter((r) => r.startsWith(" - STALE")).length;
|
|
121
|
+
if (staleCount > 0) {
|
|
122
|
+
results.push("");
|
|
123
|
+
results.push(`Note: ${staleCount} stale CDP target(s) advertised by Metro were rejected.`);
|
|
124
|
+
results.push("If you expected one of these to be live, restart Metro: the target is a leftover from a previous device/app session.");
|
|
125
|
+
}
|
|
126
|
+
// Proactive check: warn if iOS UI driver is missing
|
|
127
|
+
const hasIosDevice = Array.from(allDeviceNames.values()).some(({ device }) => {
|
|
128
|
+
const title = (device.title || "").toLowerCase();
|
|
129
|
+
return title.includes("iphone") || title.includes("ipad") || title.includes("ios");
|
|
130
|
+
});
|
|
131
|
+
if (hasIosDevice) {
|
|
132
|
+
const uiDriverOk = await isUiDriverAvailable();
|
|
133
|
+
if (!uiDriverOk) {
|
|
134
|
+
results.push("");
|
|
135
|
+
results.push("⚠️ WARNING: iOS UI driver is NOT installed. The `tap` tool and other UI-interaction tools will fail.");
|
|
136
|
+
results.push(" Install the default driver: brew install cameroncooke/axe/axe");
|
|
137
|
+
results.push(" Alternative: brew install idb-companion (set IOS_DRIVER=idb to use it)");
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return {
|
|
141
|
+
content: [
|
|
142
|
+
{
|
|
143
|
+
type: "text",
|
|
144
|
+
text: `Metro scan results:\n${results.join("\n")}`
|
|
145
|
+
}
|
|
146
|
+
]
|
|
147
|
+
};
|
|
148
|
+
});
|
|
149
|
+
// Tool: Ensure connection health
|
|
150
|
+
registerToolWithTelemetry(server, "ensure_connection", {
|
|
151
|
+
description: "Verify or establish a healthy connection to a React Native app. Use before running commands if connection may be stale, or after navigation/reload. This tool runs a health check and will auto-reconnect if needed.\n" +
|
|
152
|
+
"PURPOSE: Health-check the existing CDP connection and transparently reconnect if it has gone stale, without rescanning all Metro ports.\n" +
|
|
153
|
+
"WHEN TO USE: After a suspected disconnect (silent gaps, reload_app, app crash) or before long-running flows where a mid-flow drop would be costly. Cheaper than scan_metro when you already connected once this session.\n" +
|
|
154
|
+
"WORKFLOW: scan_metro (once) -> ensure_connection(healthCheck=true) -> resume tool calls. Use forceRefresh=true if the first probe still looks dead.\n" +
|
|
155
|
+
"GOOD: ensure_connection({ healthCheck: true })\n" +
|
|
156
|
+
"BAD: ensure_connection() before scan_metro has ever run — call scan_metro first.\n" +
|
|
157
|
+
"SEE ALSO: call get_usage_guide(topic=\"setup\") for the full session-setup playbook.",
|
|
158
|
+
inputSchema: {
|
|
159
|
+
port: z.coerce.number().optional().describe("Metro port (default: auto-detect)"),
|
|
160
|
+
healthCheck: z
|
|
161
|
+
.boolean()
|
|
162
|
+
.optional()
|
|
163
|
+
.default(true)
|
|
164
|
+
.describe("Run health check to verify page context is responsive (default: true)"),
|
|
165
|
+
forceRefresh: z
|
|
166
|
+
.boolean()
|
|
167
|
+
.optional()
|
|
168
|
+
.default(false)
|
|
169
|
+
.describe("Force close existing connection and reconnect (default: false)")
|
|
170
|
+
}
|
|
171
|
+
}, async ({ port, healthCheck, forceRefresh }) => {
|
|
172
|
+
const result = await ensureConnection({ port, healthCheck, forceRefresh });
|
|
173
|
+
if (!result.connected) {
|
|
174
|
+
return {
|
|
175
|
+
content: [
|
|
176
|
+
{
|
|
177
|
+
type: "text",
|
|
178
|
+
text: result.error || "Connection failed: No error details available. Try running scan_metro to check if Metro is running, then ensure_connection with forceRefresh=true."
|
|
179
|
+
}
|
|
180
|
+
],
|
|
181
|
+
isError: true
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
const lines = [];
|
|
185
|
+
lines.push("=== Connection Ensured ===\n");
|
|
186
|
+
const infos = result.connectionInfos;
|
|
187
|
+
if (infos.length === 0) {
|
|
188
|
+
lines.push("(no connected devices)");
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
infos.forEach((info, idx) => {
|
|
192
|
+
if (idx > 0)
|
|
193
|
+
lines.push("");
|
|
194
|
+
lines.push(`Device: ${info.deviceName} [${info.platform}]`);
|
|
195
|
+
lines.push(` Bundle: ${info.deviceTitle}`);
|
|
196
|
+
lines.push(` Port: ${info.port}`);
|
|
197
|
+
lines.push(` Uptime: ${info.uptime}`);
|
|
198
|
+
if (info.contextId !== null) {
|
|
199
|
+
lines.push(` Context ID: ${info.contextId}`);
|
|
200
|
+
}
|
|
201
|
+
lines.push(` Health Check: ${info.healthCheckPassed ? "PASSED" : "FAILED"}`);
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
lines.push("");
|
|
205
|
+
lines.push(`Reconnected: ${result.wasReconnected ? "Yes" : "No"}`);
|
|
206
|
+
if (infos.length > 1) {
|
|
207
|
+
const healthyCount = infos.filter(i => i.healthCheckPassed).length;
|
|
208
|
+
lines.push(`Overall: ${healthyCount}/${infos.length} devices healthy`);
|
|
209
|
+
lines.push(`Use device="<deviceName>" to target a specific device (substring match against the Device line above).`);
|
|
210
|
+
}
|
|
211
|
+
if (!result.healthCheckPassed) {
|
|
212
|
+
const failed = infos.filter(i => !i.healthCheckPassed).map(i => i.deviceName);
|
|
213
|
+
lines.push("");
|
|
214
|
+
if (failed.length > 0) {
|
|
215
|
+
lines.push(`Warning: Health check failed for: ${failed.join(", ")}. The page context may be stale.`);
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
lines.push("Warning: Health check failed. The page context may be stale.");
|
|
219
|
+
}
|
|
220
|
+
lines.push("Consider using forceRefresh=true or reload_app to get a fresh context.");
|
|
221
|
+
}
|
|
222
|
+
return {
|
|
223
|
+
content: [{ type: "text", text: lines.join("\n") }]
|
|
224
|
+
};
|
|
225
|
+
});
|
|
226
|
+
// Tool: Get connected apps
|
|
227
|
+
registerToolWithTelemetry(server, "get_apps", {
|
|
228
|
+
description: "List currently connected React Native apps and their connection status. If no apps are connected, run scan_metro first to establish a connection.\n" +
|
|
229
|
+
"PURPOSE: Enumerate active debug targets with device names, platforms, ports, and detected RN/Expo versions so you can target the right one.\n" +
|
|
230
|
+
"WHEN TO USE: After scan_metro to confirm what connected, or before passing a device=\"...\" filter to another tool.\n" +
|
|
231
|
+
"WORKFLOW: scan_metro -> get_apps -> get_logs / ios_screenshot / tap (with device=\"...\" if multiple).\n" +
|
|
232
|
+
"LIMITATIONS: Only lists devices the MCP has successfully connected to — stale targets don't appear here, use get_connection_status for health details.\n" +
|
|
233
|
+
"GOOD: get_apps()\n" +
|
|
234
|
+
"BAD: Calling get_apps in a tight loop — the list doesn't change without a scan_metro or disconnect_metro.\n" +
|
|
235
|
+
"SEE ALSO: call get_usage_guide(topic=\"setup\") for the full session-setup playbook.",
|
|
236
|
+
inputSchema: {}
|
|
237
|
+
}, async () => {
|
|
238
|
+
// Brief settle: if any entry is non-OPEN, wait once for sibling
|
|
239
|
+
// sockets to finish handshaking (e.g. an Android target that
|
|
240
|
+
// connected microseconds after scan_metro returned but isn't
|
|
241
|
+
// yet OPEN). Avoids flapping the listing right after scan_metro.
|
|
242
|
+
let apps = getConnectedApps();
|
|
243
|
+
if (apps.length > 0 && apps.some(({ isConnected }) => !isConnected)) {
|
|
244
|
+
await new Promise((r) => setTimeout(r, 250));
|
|
245
|
+
apps = getConnectedApps();
|
|
246
|
+
}
|
|
247
|
+
// Wait for any in-flight app-detection probes so we don't print
|
|
248
|
+
// presumptive "RN unknown" placeholders right after a fresh
|
|
249
|
+
// connect. Capped at 3500ms per device (covers the 500ms
|
|
250
|
+
// schedule delay + full 3000ms detectApp timeout). Probes run
|
|
251
|
+
// in parallel so the total wall time is bounded by the slowest
|
|
252
|
+
// device, not the sum. Subsequent calls are no-ops because
|
|
253
|
+
// the stored appDetectionPromise resolved.
|
|
254
|
+
await Promise.all(apps.map(({ app }) => awaitAppDetection(app, 3500)));
|
|
255
|
+
apps = getConnectedApps();
|
|
256
|
+
if (apps.length === 0) {
|
|
257
|
+
return {
|
|
258
|
+
content: [
|
|
259
|
+
{
|
|
260
|
+
type: "text",
|
|
261
|
+
text: "No connected devices. Run scan_metro to discover and connect to Metro servers."
|
|
262
|
+
}
|
|
263
|
+
]
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
// Show every tracked entry, marking non-OPEN sockets with their
|
|
267
|
+
// WebSocket state (CONNECTING / CLOSING / CLOSED) so flapping is
|
|
268
|
+
// visible instead of silently filtered out.
|
|
269
|
+
const deviceLines = apps.map(({ app, isConnected }, i) => {
|
|
270
|
+
const name = app.deviceInfo.deviceName || app.deviceInfo.title;
|
|
271
|
+
const appId = app.deviceInfo.appId || app.deviceInfo.title.split(" (")[0] || "unknown";
|
|
272
|
+
const statusSuffix = isConnected
|
|
273
|
+
? ""
|
|
274
|
+
: ` [${getWebSocketStateName(app.ws.readyState).toLowerCase()} — reconnecting]`;
|
|
275
|
+
const lines = [` ${i + 1}. ${name} — ${appId} (${app.platform}, port ${app.port})${statusSuffix}`];
|
|
276
|
+
if (app.simulatorUdid) {
|
|
277
|
+
lines.push(` Simulator UDID: ${app.simulatorUdid}`);
|
|
278
|
+
}
|
|
279
|
+
if (app.adbSerial) {
|
|
280
|
+
lines.push(` ADB Serial: ${app.adbSerial}`);
|
|
281
|
+
}
|
|
282
|
+
if (app.appDetection) {
|
|
283
|
+
const d = app.appDetection;
|
|
284
|
+
const version = d.reactNativeVersion !== "unknown" ? `RN ${d.reactNativeVersion}` : "RN unknown";
|
|
285
|
+
const expo = d.expoSdkVersion ? `, Expo SDK ${d.expoSdkVersion}` : "";
|
|
286
|
+
lines.push(` Environment: ${version}, ${d.architecture} arch, ${d.jsEngine}, ${app.platform} ${d.osVersion}${expo}`);
|
|
287
|
+
}
|
|
288
|
+
return lines.join("\n");
|
|
289
|
+
});
|
|
290
|
+
const firstApp = apps[0].app;
|
|
291
|
+
const firstIdentifier = firstApp.simulatorUdid ??
|
|
292
|
+
firstApp.adbSerial ??
|
|
293
|
+
firstApp.deviceInfo.deviceName;
|
|
294
|
+
const text = [
|
|
295
|
+
`Connected devices:`,
|
|
296
|
+
...deviceLines,
|
|
297
|
+
``,
|
|
298
|
+
`Use device="${firstApp.deviceInfo.deviceName}", device="${firstIdentifier}", or any UDID/serial above to target a specific device.`,
|
|
299
|
+
``,
|
|
300
|
+
`Total logs in buffer: ${getTotalLogCount()}`
|
|
301
|
+
].join("\n");
|
|
302
|
+
// Structured payload — downstream tools and tests can read this
|
|
303
|
+
// without parsing the prose above.
|
|
304
|
+
const structured = apps.map(({ app, isConnected }) => ({
|
|
305
|
+
deviceName: app.deviceInfo.deviceName,
|
|
306
|
+
appId: app.deviceInfo.appId,
|
|
307
|
+
platform: app.platform,
|
|
308
|
+
port: app.port,
|
|
309
|
+
simulatorUdid: app.simulatorUdid ?? null,
|
|
310
|
+
adbSerial: app.adbSerial ?? null,
|
|
311
|
+
isConnected,
|
|
312
|
+
appDetection: app.appDetection ?? null
|
|
313
|
+
}));
|
|
314
|
+
return {
|
|
315
|
+
content: [
|
|
316
|
+
{ type: "text", text },
|
|
317
|
+
{ type: "text", text: JSON.stringify({ apps: structured }, null, 2) }
|
|
318
|
+
]
|
|
319
|
+
};
|
|
320
|
+
});
|
|
321
|
+
// Tool: Get connection status (detailed health and gap tracking)
|
|
322
|
+
registerToolWithTelemetry(server, "get_connection_status", {
|
|
323
|
+
description: "Get detailed connection health status including uptime, recent disconnects/reconnects, and connection gaps that may indicate missing data.\n" +
|
|
324
|
+
"PURPOSE: Diagnose flaky CDP sessions — quantify uptime, count reconnects, and expose gaps where logs/network data could be missing.\n" +
|
|
325
|
+
"WHEN TO USE: When logs look suspiciously empty, tools complain about disconnect/reconnect, or the app was suspended and resumed.\n" +
|
|
326
|
+
"WORKFLOW: get_connection_status -> if unhealthy: disconnect_metro -> scan_metro to rebuild a clean session.\n" +
|
|
327
|
+
"LIMITATIONS: Reports only MCP-side view; doesn't know why Metro dropped the socket (simulator sleep, app backgrounded, etc).\n" +
|
|
328
|
+
"GOOD: get_connection_status() after noticing stale data.\n" +
|
|
329
|
+
"BAD: Polling get_connection_status as a heartbeat — use ensure_connection(healthCheck=true) for a live probe.\n" +
|
|
330
|
+
"Pass events=true to include the recent connection event log (connect/close/reconnect lifecycle) — useful when a target drops mid-session and you need to see why reconnect didn't recover it.\n" +
|
|
331
|
+
"SEE ALSO: call get_usage_guide(topic=\"setup\") for the full session-setup playbook.",
|
|
332
|
+
inputSchema: {
|
|
333
|
+
events: z
|
|
334
|
+
.boolean()
|
|
335
|
+
.optional()
|
|
336
|
+
.describe("Include the recent connection event log (lifecycle: connect, close, reconnect attempts/failures, stale-target, etc). Default: false."),
|
|
337
|
+
eventLimit: z
|
|
338
|
+
.coerce
|
|
339
|
+
.number()
|
|
340
|
+
.optional()
|
|
341
|
+
.describe("When events=true, show only the last N events. Default: 50."),
|
|
342
|
+
eventAppKey: z
|
|
343
|
+
.string()
|
|
344
|
+
.optional()
|
|
345
|
+
.describe("When events=true, filter the event log to a single appKey (format: '<port>-<deviceId>').")
|
|
346
|
+
}
|
|
347
|
+
}, async ({ events, eventLimit, eventAppKey }) => {
|
|
348
|
+
const connections = getConnectedApps();
|
|
349
|
+
const states = getAllConnectionStates();
|
|
350
|
+
const metadata = getAllConnectionMetadata();
|
|
351
|
+
const lines = [];
|
|
352
|
+
lines.push("=== Connection Status ===\n");
|
|
353
|
+
const appendEventsBlock = () => {
|
|
354
|
+
if (!events)
|
|
355
|
+
return;
|
|
356
|
+
const limit = eventLimit && eventLimit > 0 ? eventLimit : 50;
|
|
357
|
+
const eventList = getConnectionEvents({ appKey: eventAppKey, last: limit });
|
|
358
|
+
lines.push("");
|
|
359
|
+
lines.push(`=== Recent Connection Events (last ${eventList.length}${eventAppKey ? ` for ${eventAppKey}` : ""}) ===`);
|
|
360
|
+
if (eventList.length === 0) {
|
|
361
|
+
lines.push(" (no events recorded yet)");
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
for (const ev of eventList) {
|
|
365
|
+
const detail = ev.detail ? ` — ${ev.detail}` : "";
|
|
366
|
+
const title = ev.deviceTitle ? ` ${ev.deviceTitle}` : "";
|
|
367
|
+
lines.push(` ${ev.timestamp.toLocaleTimeString()} [${ev.type}] ${ev.appKey}${title}${detail}`);
|
|
368
|
+
}
|
|
369
|
+
};
|
|
370
|
+
if (connections.length === 0 && states.size === 0) {
|
|
371
|
+
lines.push("No connections established. Run scan_metro to connect.");
|
|
372
|
+
appendEventsBlock();
|
|
373
|
+
return {
|
|
374
|
+
content: [{ type: "text", text: lines.join("\n") }]
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
// Show active connections
|
|
378
|
+
for (const { key, app, isConnected } of connections) {
|
|
379
|
+
const state = states.get(key);
|
|
380
|
+
const contextHealth = getContextHealth(key);
|
|
381
|
+
lines.push(`--- ${app.deviceInfo.title} (Port ${app.port}) ---`);
|
|
382
|
+
lines.push(` Status: ${isConnected ? "CONNECTED" : "DISCONNECTED"}`);
|
|
383
|
+
if (state) {
|
|
384
|
+
if (state.lastConnectedTime) {
|
|
385
|
+
const uptime = Date.now() - state.lastConnectedTime.getTime();
|
|
386
|
+
lines.push(` Connected since: ${state.lastConnectedTime.toLocaleTimeString()}`);
|
|
387
|
+
lines.push(` Uptime: ${formatDuration(uptime)}`);
|
|
388
|
+
}
|
|
389
|
+
if (state.status === "reconnecting") {
|
|
390
|
+
lines.push(` Reconnecting: Attempt ${state.reconnectionAttempts}`);
|
|
391
|
+
}
|
|
392
|
+
// Show recent gaps (last 5 minutes)
|
|
393
|
+
if (state.connectionGaps.length > 0) {
|
|
394
|
+
const recentGaps = state.connectionGaps.filter((g) => Date.now() - g.disconnectedAt.getTime() < 300000);
|
|
395
|
+
if (recentGaps.length > 0) {
|
|
396
|
+
lines.push(` Recent gaps: ${recentGaps.length}`);
|
|
397
|
+
for (const gap of recentGaps.slice(-3)) {
|
|
398
|
+
const duration = gap.durationMs ? formatDuration(gap.durationMs) : "ongoing";
|
|
399
|
+
lines.push(` - ${gap.disconnectedAt.toLocaleTimeString()} (${duration}): ${gap.reason}`);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
// Show context health
|
|
405
|
+
if (contextHealth) {
|
|
406
|
+
lines.push(` Context Health:`);
|
|
407
|
+
lines.push(` Context ID: ${contextHealth.contextId ?? "unknown"}`);
|
|
408
|
+
lines.push(` Status: ${contextHealth.isStale ? "STALE" : "HEALTHY"}`);
|
|
409
|
+
if (contextHealth.lastHealthCheck) {
|
|
410
|
+
const healthResult = contextHealth.lastHealthCheckSuccess ? "PASS" : "FAIL";
|
|
411
|
+
lines.push(` Last Check: ${contextHealth.lastHealthCheck.toLocaleTimeString()} (${healthResult})`);
|
|
412
|
+
}
|
|
413
|
+
if (contextHealth.lastContextCreated) {
|
|
414
|
+
lines.push(` Context Created: ${contextHealth.lastContextCreated.toLocaleTimeString()}`);
|
|
415
|
+
}
|
|
416
|
+
if (contextHealth.lastContextDestroyed) {
|
|
417
|
+
lines.push(` Context Destroyed: ${contextHealth.lastContextDestroyed.toLocaleTimeString()}`);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
lines.push("");
|
|
421
|
+
}
|
|
422
|
+
// Show disconnected/reconnecting states without active connections
|
|
423
|
+
for (const [key, state] of states.entries()) {
|
|
424
|
+
if (!connections.find((c) => c.key === key)) {
|
|
425
|
+
const meta = metadata.get(key);
|
|
426
|
+
lines.push(`--- ${meta?.deviceInfo.title || key} (Disconnected) ---`);
|
|
427
|
+
lines.push(` Status: ${state.status.toUpperCase()}`);
|
|
428
|
+
if (state.lastDisconnectTime) {
|
|
429
|
+
lines.push(` Disconnected at: ${state.lastDisconnectTime.toLocaleTimeString()}`);
|
|
430
|
+
}
|
|
431
|
+
if (state.reconnectionAttempts > 0) {
|
|
432
|
+
lines.push(` Reconnection attempts: ${state.reconnectionAttempts}`);
|
|
433
|
+
}
|
|
434
|
+
lines.push("");
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
appendEventsBlock();
|
|
438
|
+
return {
|
|
439
|
+
content: [{ type: "text", text: lines.join("\n") }]
|
|
440
|
+
};
|
|
441
|
+
});
|
|
442
|
+
// Tool: Connect to specific Metro port
|
|
443
|
+
registerToolWithTelemetry(server, "connect_metro", {
|
|
444
|
+
description: "Connect to a Metro server on a specific port.\n" +
|
|
445
|
+
"[DEPRECATED IN PRACTICE — prefer `scan_metro` which auto-discovers all common ports and connects every Bridgeless target at once. Use `connect_metro` only when you need to target a specific non-default port]\n" +
|
|
446
|
+
"PURPOSE: Establish a CDP WebSocket connection to a single Metro server on a known, non-default port.\n" +
|
|
447
|
+
"WHEN TO USE: Only when the Metro bundler is running on a port outside the common 8081/8082/19000-19002 range that `scan_metro` already covers — otherwise always prefer `scan_metro`.\n" +
|
|
448
|
+
"SEE ALSO: call scan_metro for auto-discovery; call get_apps afterwards to confirm the device attached.",
|
|
449
|
+
inputSchema: {
|
|
450
|
+
port: z.coerce.number().default(8081).describe("Metro server port (default: 8081)")
|
|
451
|
+
}
|
|
452
|
+
}, async ({ port }) => {
|
|
453
|
+
try {
|
|
454
|
+
const devices = await fetchDevices(port);
|
|
455
|
+
if (devices.length === 0) {
|
|
456
|
+
return {
|
|
457
|
+
content: [
|
|
458
|
+
{
|
|
459
|
+
type: "text",
|
|
460
|
+
text: `No devices found on port ${port}. Make sure the app is running.`
|
|
461
|
+
}
|
|
462
|
+
]
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
const results = [`Found ${devices.length} device(s) on port ${port}:`];
|
|
466
|
+
for (const device of devices) {
|
|
467
|
+
try {
|
|
468
|
+
const result = await connectToDevice(device, port);
|
|
469
|
+
results.push(` - ${result}`);
|
|
470
|
+
}
|
|
471
|
+
catch (error) {
|
|
472
|
+
results.push(` - ${device.title}: Failed - ${error}`);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
// Also connect to Metro build events
|
|
476
|
+
try {
|
|
477
|
+
await connectMetroBuildEvents(port);
|
|
478
|
+
results.push(` - Connected to Metro build events`);
|
|
479
|
+
}
|
|
480
|
+
catch {
|
|
481
|
+
// Build events connection is optional
|
|
482
|
+
}
|
|
483
|
+
return {
|
|
484
|
+
content: [
|
|
485
|
+
{
|
|
486
|
+
type: "text",
|
|
487
|
+
text: results.join("\n")
|
|
488
|
+
}
|
|
489
|
+
]
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
catch (error) {
|
|
493
|
+
return {
|
|
494
|
+
content: [
|
|
495
|
+
{
|
|
496
|
+
type: "text",
|
|
497
|
+
text: `Failed to connect: ${error}`
|
|
498
|
+
}
|
|
499
|
+
]
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
});
|
|
503
|
+
// Tool: Disconnect from Metro
|
|
504
|
+
registerToolWithTelemetry(server, "disconnect_metro", {
|
|
505
|
+
description: "Disconnect from Metro servers and stop auto-reconnection. Without device param: disconnects ALL devices. With device param: disconnects only the matching device. Use this to remove stale connections or free the CDP slot for the built-in debugger. Log and network buffers are preserved. Reconnect later with scan_metro.\n" +
|
|
506
|
+
"PURPOSE: Cleanly release CDP slots so another debugger (Flipper, React DevTools, Chrome) can attach, or nuke a stale connection the MCP keeps reviving.\n" +
|
|
507
|
+
"WHEN TO USE: Before launching a native debugger, when connections keep flapping, or after a simulator/device restart left zombie targets.\n" +
|
|
508
|
+
"WORKFLOW: disconnect_metro -> attach other debugger / restart app -> scan_metro to reconnect.\n" +
|
|
509
|
+
"LIMITATIONS: Suppresses auto-reconnect until scan_metro or connect_metro is called again; buffers persist but won't receive new events.\n" +
|
|
510
|
+
"GOOD: disconnect_metro(); disconnect_metro({ device: \"iPhone\" })\n" +
|
|
511
|
+
"BAD: Using disconnect_metro to clear logs — use clear_logs instead; disconnect breaks capture.\n" +
|
|
512
|
+
"SEE ALSO: call get_usage_guide(topic=\"setup\") for the full session-setup playbook.",
|
|
513
|
+
inputSchema: {
|
|
514
|
+
device: z.string().optional().describe("Target device name (substring match) to disconnect. Omit to disconnect all devices. Run get_apps to see connected devices.")
|
|
515
|
+
}
|
|
516
|
+
}, async ({ device }) => {
|
|
517
|
+
const connections = getConnectedApps();
|
|
518
|
+
if (connections.length === 0) {
|
|
519
|
+
return {
|
|
520
|
+
content: [
|
|
521
|
+
{
|
|
522
|
+
type: "text",
|
|
523
|
+
text: "No active Metro connections to disconnect."
|
|
524
|
+
}
|
|
525
|
+
]
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
// Targeted disconnect: only disconnect a specific device
|
|
529
|
+
if (device) {
|
|
530
|
+
const app = getConnectedAppByDevice(device);
|
|
531
|
+
if (!app) {
|
|
532
|
+
return {
|
|
533
|
+
content: [{ type: "text", text: `No connected device matches "${device}". Run get_apps to see connected devices.` }],
|
|
534
|
+
isError: true
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
// Find and close the matching connection
|
|
538
|
+
for (const [key, connectedApp] of connectedApps.entries()) {
|
|
539
|
+
if (connectedApp.ws === app.ws) {
|
|
540
|
+
// Suppress reconnection for this specific device
|
|
541
|
+
suppressReconnectionForKey(key);
|
|
542
|
+
cancelReconnectionTimer(key);
|
|
543
|
+
try {
|
|
544
|
+
connectedApp.ws.close();
|
|
545
|
+
}
|
|
546
|
+
catch {
|
|
547
|
+
// Ignore close errors
|
|
548
|
+
}
|
|
549
|
+
connectedApps.delete(key);
|
|
550
|
+
const name = connectedApp.deviceInfo.deviceName || connectedApp.deviceInfo.title;
|
|
551
|
+
return {
|
|
552
|
+
content: [{ type: "text", text: `Disconnected from ${name} (port ${connectedApp.port}). Buffers preserved. Use scan_metro to reconnect.` }]
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
// Disconnect all
|
|
558
|
+
const disconnected = [];
|
|
559
|
+
// Suppress reconnection BEFORE closing sockets
|
|
560
|
+
// (close handlers fire async and would re-schedule reconnection)
|
|
561
|
+
suppressReconnection();
|
|
562
|
+
cancelAllReconnectionTimers();
|
|
563
|
+
// Close all CDP WebSocket connections
|
|
564
|
+
for (const [key, app] of connectedApps.entries()) {
|
|
565
|
+
try {
|
|
566
|
+
app.ws.close();
|
|
567
|
+
}
|
|
568
|
+
catch {
|
|
569
|
+
// Ignore close errors
|
|
570
|
+
}
|
|
571
|
+
disconnected.push(`${app.deviceInfo.title} (port ${app.port})`);
|
|
572
|
+
connectedApps.delete(key);
|
|
573
|
+
}
|
|
574
|
+
// Disconnect Metro build events WebSocket
|
|
575
|
+
disconnectMetroBuildEvents();
|
|
576
|
+
// Clear connection state (but NOT log/network buffers)
|
|
577
|
+
clearAllConnectionState();
|
|
578
|
+
clearAllCDPMessageTimes();
|
|
579
|
+
const lines = [
|
|
580
|
+
`Disconnected from ${disconnected.length} app(s):`,
|
|
581
|
+
...disconnected.map((d) => ` - ${d}`),
|
|
582
|
+
"",
|
|
583
|
+
"Metro CDP connection is now free for the built-in React Native debugger.",
|
|
584
|
+
"Log and network buffers are preserved.",
|
|
585
|
+
'Use "scan_metro" to reconnect when ready.'
|
|
586
|
+
];
|
|
587
|
+
return {
|
|
588
|
+
content: [{ type: "text", text: lines.join("\n") }]
|
|
589
|
+
};
|
|
590
|
+
});
|
|
591
|
+
// Tool: Reload the app
|
|
592
|
+
registerToolWithTelemetry(server, "reload_app", {
|
|
593
|
+
description: "Reload the React Native app (triggers JavaScript bundle reload like pressing 'r' in Metro).\n" +
|
|
594
|
+
"PURPOSE: Force a full JS bundle reload when Fast Refresh isn't enough — clears in-memory state and re-runs the bundle from scratch.\n" +
|
|
595
|
+
"WHEN TO USE (only these cases): (1) native code, app.json, Info.plist, Podfile, or a native module changed; (2) Fast Refresh visibly failed (red-screen or stale render confirmed via screenshot after a few seconds); (3) the app is in a broken state; (4) you need to reset app state completely; (5) the user explicitly asks.\n" +
|
|
596
|
+
"AVOID: reloading reflexively after JS/TS/TSX/style edits — Fast Refresh applies those in 1-2s. A reload discards navigation stack, context, hooks state, BLE/WebSocket connections, paired devices, and auth sessions, which can force re-pairing or re-login and break your verification loop.\n" +
|
|
597
|
+
"WORKFLOW: screenshot → wait 2s for Fast Refresh → if still stale, reload_app. Will auto-connect to Metro if no connection exists. After reload, wait a few seconds before running other tools.\n" +
|
|
598
|
+
"SEE ALSO: get_refresh_status (did Fast Refresh accept?), get_bundle_status (did Metro compile?).",
|
|
599
|
+
inputSchema: {
|
|
600
|
+
device: z.string().optional().describe("Target device name (substring match). Omit for default device. Run get_apps to see connected devices.")
|
|
601
|
+
}
|
|
602
|
+
}, async ({ device }) => {
|
|
603
|
+
const result = await reloadApp(device);
|
|
604
|
+
if (!result.success) {
|
|
605
|
+
return {
|
|
606
|
+
content: [
|
|
607
|
+
{
|
|
608
|
+
type: "text",
|
|
609
|
+
text: `Error: ${result.error}`
|
|
610
|
+
}
|
|
611
|
+
],
|
|
612
|
+
isError: true
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
return {
|
|
616
|
+
content: [
|
|
617
|
+
{
|
|
618
|
+
type: "text",
|
|
619
|
+
text: result.result ?? "App reload triggered"
|
|
620
|
+
}
|
|
621
|
+
]
|
|
622
|
+
};
|
|
623
|
+
});
|
|
624
|
+
}
|
|
625
|
+
//# sourceMappingURL=connectionTools.js.map
|