mobile-debug-mcp 0.34.0 → 0.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/mcp-builder/SKILL.md +44 -64
- package/.agents/skills/mcp-builder/references/build-flags.md +44 -43
- package/.agents/skills/mcp-builder/references/diagnostics-schema.md +4 -1
- package/.agents/skills/mcp-builder/references/toolchain-details.md +49 -62
- package/.agents/skills/spec-review/references/spec-review-checklist.md +7 -0
- package/.agents/skills/test-authoring/SKILL.md +7 -6
- package/.agents/skills/test-authoring/references/repo-test-layout.md +3 -1
- package/.agents/skills/test-authoring/references/test-authoring-workflow.md +16 -7
- package/.agents/skills/test-authoring/references/test-quality-checklist.md +2 -1
- package/.cursor-plugin/marketplace.json +1 -1
- package/.github/copilot-instructions.md +14 -36
- package/.github/workflows/ci.yml +4 -4
- package/AGENTS.md +12 -3
- package/CONTRIBUTING.md +79 -0
- package/README.md +218 -129
- package/agent-plugin/.antigravity-plugin/README.md +48 -0
- package/agent-plugin/.antigravity-plugin/plugin.json +18 -0
- package/agent-plugin/.claude-plugin/plugin.json +2 -2
- package/agent-plugin/.codex-plugin/plugin.json +1 -1
- package/agent-plugin/.cursor-plugin/plugin.json +2 -2
- package/agent-plugin/.mcp.json +1 -1
- package/agent-plugin/README.md +50 -11
- package/agent-plugin/cursor/.cursor-plugin/plugin.json +23 -0
- package/agent-plugin/cursor/LICENSE +201 -0
- package/agent-plugin/cursor/README.md +9 -0
- package/agent-plugin/cursor/skills/mobile-debug-mcp/SKILL.md +253 -0
- package/agent-plugin/mcp.json +1 -1
- package/agent-plugin/mcp_config.json +13 -0
- package/agent-plugin/plugin.json +1 -1
- package/agent-plugin/skills/mobile-debug-mcp/SKILL.md +62 -17
- package/dist/contracts/execution-controls.js +24 -0
- package/dist/contracts/selector.js +8 -0
- package/dist/contracts/target.js +15 -0
- package/dist/contracts/ui.js +1 -0
- package/dist/debugger/android.js +2 -1
- package/dist/debugger/diagnostics.js +54 -0
- package/dist/debugger/guard.js +4 -4
- package/dist/debugger/ios-worker.js +62 -0
- package/dist/debugger/ios.js +57 -0
- package/dist/debugger/protocol.js +33 -0
- package/dist/debugger/sessions.js +133 -74
- package/dist/debugger/worker.js +59 -46
- package/dist/interact/adjustment/adjustment-context.js +41 -0
- package/dist/interact/adjustment/adjustment-gestures.js +55 -0
- package/dist/interact/adjustment/adjustment-plan.js +18 -0
- package/dist/interact/adjustment/adjustment-resolution.js +127 -0
- package/dist/interact/adjustment/adjustment-result.js +19 -0
- package/dist/interact/adjustment/adjustment-semantic.js +64 -0
- package/dist/interact/adjustment/adjustment-verification.js +35 -0
- package/dist/interact/adjustment/adjustment.js +52 -0
- package/dist/interact/adjustment/control-geometry.js +87 -0
- package/dist/interact/adjustment/control-values.js +136 -0
- package/dist/interact/adjustment/slider-labels.js +84 -0
- package/dist/interact/assertions/screen-assertion.js +37 -0
- package/dist/interact/assertions/state-assertion-context.js +35 -0
- package/dist/interact/assertions/state-assertion.js +76 -0
- package/dist/interact/assertions/state-comparison.js +141 -0
- package/dist/interact/assertions/visibility-assertion.js +34 -0
- package/dist/interact/conditional-action.js +12 -7
- package/dist/interact/index.js +77 -3092
- package/dist/interact/input-service.js +1 -0
- package/dist/interact/interaction-trace.js +21 -0
- package/dist/interact/model.js +1 -0
- package/dist/interact/observation.js +1 -0
- package/dist/interact/targeting/candidate-ancestor.js +58 -0
- package/dist/interact/targeting/candidate-result.js +23 -0
- package/dist/interact/targeting/candidate-scoring.js +50 -0
- package/dist/interact/targeting/element-helpers.js +216 -0
- package/dist/interact/targeting/find-element.js +65 -0
- package/dist/interact/targeting/nearby-control.js +56 -0
- package/dist/interact/targeting/resolved-elements.js +21 -0
- package/dist/interact/targeting/tap-target.js +17 -0
- package/dist/interact/targeting/target-scope.js +104 -0
- package/dist/interact/waits/legacy-log-wait.js +38 -0
- package/dist/interact/waits/legacy-wait-observations.js +103 -0
- package/dist/interact/waits/legacy-wait-state.js +34 -0
- package/dist/interact/waits/legacy-wait.js +48 -0
- package/dist/interact/waits/screen-wait.js +49 -0
- package/dist/interact/waits/ui-change-helpers.js +157 -0
- package/dist/interact/waits/ui-change-state.js +18 -0
- package/dist/interact/waits/ui-change-wait.js +77 -0
- package/dist/interact/waits/ui-wait-condition.js +56 -0
- package/dist/interact/waits/ui-wait-state.js +38 -0
- package/dist/interact/waits/ui-wait.js +106 -0
- package/dist/manage/android.js +55 -51
- package/dist/manage/index.js +38 -75
- package/dist/manage/ios/build-types.js +1 -0
- package/dist/manage/ios/build.js +210 -0
- package/dist/manage/ios/project-discovery.js +29 -0
- package/dist/manage/ios/scheme.js +18 -0
- package/dist/manage/ios.js +44 -256
- package/dist/observe/android/context.js +1 -0
- package/dist/observe/android/current-screen.js +55 -0
- package/dist/observe/android/fingerprint.js +13 -0
- package/dist/observe/android/log-stream.js +132 -0
- package/dist/observe/android/logs.js +107 -0
- package/dist/observe/android/screenshot.js +70 -0
- package/dist/observe/android/ui-tree.js +107 -0
- package/dist/observe/android.js +16 -520
- package/dist/observe/evidence.js +114 -75
- package/dist/observe/index.js +16 -263
- package/dist/observe/ios/context.js +16 -0
- package/dist/observe/ios/fingerprint.js +12 -0
- package/dist/observe/ios/log-stream.js +105 -0
- package/dist/observe/ios/logs.js +168 -0
- package/dist/observe/ios/screenshot.js +22 -0
- package/dist/observe/ios/ui-elements.js +241 -0
- package/dist/observe/ios/ui-tree.js +137 -0
- package/dist/observe/ios-trace/artifact.js +63 -0
- package/dist/observe/ios-trace/capabilities.js +86 -0
- package/dist/observe/ios-trace/native.js +93 -0
- package/dist/observe/ios-trace/notification.js +35 -0
- package/dist/observe/ios-trace/process.js +98 -0
- package/dist/observe/ios-trace/sessions.js +244 -0
- package/dist/observe/ios.js +17 -715
- package/dist/observe/logs/model.js +1 -0
- package/dist/{network → observe/network}/index.js +2 -2
- package/dist/observe/readiness-service.js +5 -3
- package/dist/observe/readiness.js +33 -14
- package/dist/observe/screenshot-encoding.js +41 -0
- package/dist/observe/snapshot-collection.js +79 -0
- package/dist/observe/snapshot-logs.js +30 -0
- package/dist/observe/snapshot-metadata.js +43 -31
- package/dist/observe/snapshot-semantic.js +115 -0
- package/dist/observe/system-trace-error.js +7 -0
- package/dist/observe/system-trace-router.js +81 -0
- package/dist/observe/system-trace.js +26 -21
- package/dist/runtime/action-results.js +270 -0
- package/dist/runtime/clock.js +4 -0
- package/dist/server/common.js +1 -256
- package/dist/server/definitions/assert.js +162 -0
- package/dist/server/definitions/diagnostic.js +118 -0
- package/dist/server/definitions/input.js +274 -0
- package/dist/server/definitions/manage.js +194 -0
- package/dist/server/definitions/observe.js +149 -0
- package/dist/server/definitions/target.js +138 -0
- package/dist/server/definitions/wait.js +105 -0
- package/dist/server/handlers/action-execution.js +163 -0
- package/dist/server/handlers/correlation.js +23 -0
- package/dist/server/handlers/debugger-handlers.js +67 -0
- package/dist/server/handlers/debugger-response.js +9 -0
- package/dist/server/handlers/diagnostic.js +77 -0
- package/dist/server/handlers/handler-types.js +1 -0
- package/dist/server/handlers/input.js +154 -0
- package/dist/server/handlers/interact.js +113 -0
- package/dist/server/handlers/journey-assertions.js +35 -0
- package/dist/server/handlers/journey.js +147 -0
- package/dist/server/handlers/manage.js +119 -0
- package/dist/server/handlers/observe.js +95 -0
- package/dist/server/handlers/payload.js +4 -0
- package/dist/server/handlers/tool-handlers.js +170 -0
- package/dist/server/schemas/condition-schema.js +2 -0
- package/dist/server/{debugger-schema.js → schemas/debugger-schema.js} +20 -12
- package/dist/server/{journey-schema.js → schemas/journey-schema.js} +7 -22
- package/dist/server/schemas/system-trace-schema.js +22 -0
- package/dist/server/tool-definitions.js +58 -1135
- package/dist/server-core.js +2 -2
- package/dist/server.js +4 -4
- package/dist/system/android-status.js +101 -0
- package/dist/system/android.js +37 -27
- package/dist/system/index.js +13 -439
- package/dist/system/ios-status.js +132 -0
- package/dist/system/ios.js +11 -8
- package/dist/system/model.js +1 -0
- package/dist/system/probes.js +105 -0
- package/dist/system/status-summary.js +43 -0
- package/dist/system/unsupported-status.js +52 -0
- package/dist/utils/android/commands.js +89 -0
- package/dist/utils/android/gradle.js +139 -0
- package/dist/utils/android/logs.js +103 -0
- package/dist/utils/android/ui-tree.js +233 -0
- package/dist/utils/android/utils.js +6 -564
- package/dist/utils/cli/idb/idb-helper.js +4 -6
- package/dist/utils/cli/idb/install-idb.js +13 -9
- package/dist/utils/cli/ios/preflight-ios.js +42 -38
- package/dist/utils/ios/utils.js +48 -46
- package/dist/utils/java.js +65 -49
- package/dist/utils/resolve-device.js +4 -2
- package/dist/utils/ui/index.js +26 -26
- package/docs/CHANGELOG.md +67 -1
- package/docs/README.md +38 -0
- package/docs/agent-plugin-installation-verification.md +39 -0
- package/docs/benchmarks/README.md +18 -0
- package/docs/benchmarks/interaction-latency/README.md +14 -0
- package/docs/benchmarks/interaction-latency/final.md +4 -1
- package/docs/benchmarks/interaction-latency/ios-validation.md +2 -0
- package/docs/benchmarks/ui-tree-performance/README.md +24 -16
- package/docs/benchmarks/ui-tree-performance/comparison.md +11 -10
- package/docs/code-structure.md +120 -0
- package/docs/specs/001-state-verification/spec.md +16 -14
- package/docs/specs/002-richer-element-identity/spec.md +12 -10
- package/docs/specs/003-wait-and-synchronization-reliability/spec.md +12 -10
- package/docs/specs/004-action-verification-routing/spec.md +3 -3
- package/docs/specs/005-unified-action-execution-and-verification-model/spec.md +2 -0
- package/docs/specs/006-runtime-action-instrumentation-and-binding-layer/spec.md +2 -0
- package/docs/specs/007-actionability-resolution-and-executable-target-selection/spec.md +3 -1
- package/docs/specs/008-adjustable-control-support-and-semantic-value-manipulation/spec.md +3 -4
- package/docs/specs/009-semantic-control-modeling-for-custom-and-composite-controls/spec.md +2 -0
- package/docs/specs/010-verification-stabilization-and-temporal-convergence/spec.md +2 -2
- package/docs/specs/011-recovery-and-replanning-for-failed-or-ambiguous-interaction-flows/spec.md +2 -2
- package/docs/specs/011.1-recovery-contract-types-and-runtime-wiring-spec/spec.md +2 -0
- package/docs/specs/012-action-trace-and-xecution-observability/spec.md +2 -3
- package/docs/specs/013-wait-and-synchronization-reliability/spec.md +19 -19
- package/docs/specs/014-actionability-resolution/spec.md +20 -18
- package/docs/specs/015-adjustable-control-support/spec.md +17 -15
- package/docs/specs/016-environment-tools/spec.md +20 -20
- package/docs/specs/018-interaction-latency-and-batched-journeys/spec.md +2 -0
- package/docs/specs/019-ui-tree-observation-performance/spec.md +3 -1
- package/docs/specs/020-conditional-actions/intent.md +5 -3
- package/docs/specs/020-conditional-actions/plan.md +8 -9
- package/docs/specs/020-conditional-actions/spec.md +4 -2
- package/docs/specs/021-app-readiness-signals/intent.md +4 -2
- package/docs/specs/021-app-readiness-signals/plan.md +7 -6
- package/docs/specs/021-app-readiness-signals/spec.md +3 -1
- package/docs/specs/022-correlated-evidence/intent.md +4 -4
- package/docs/specs/022-correlated-evidence/plan.md +10 -11
- package/docs/specs/022-correlated-evidence/spec.md +3 -1
- package/docs/specs/023-android-system-traces/intent.md +3 -2
- package/docs/specs/023-android-system-traces/plan.md +5 -7
- package/docs/specs/023-android-system-traces/spec.md +3 -1
- package/docs/specs/024-android-heap-dump-capture/intent.md +3 -1
- package/docs/specs/025-android-runtime-debugger/intent.md +4 -3
- package/docs/specs/025-android-runtime-debugger/plan.md +3 -1
- package/docs/specs/025-android-runtime-debugger/spec.md +4 -3
- package/docs/specs/026-code-structure-and-quality-gates/health-plan.md +88 -0
- package/docs/specs/026-code-structure-and-quality-gates/intent.md +47 -0
- package/docs/specs/026-code-structure-and-quality-gates/plan.md +191 -0
- package/docs/specs/026-code-structure-and-quality-gates/spec.md +138 -0
- package/docs/specs/026-code-structure-and-quality-gates/verification-final.json +200 -0
- package/docs/specs/026-code-structure-and-quality-gates/verification-thin-facade.json +154 -0
- package/docs/specs/026-code-structure-and-quality-gates/verification.json +136 -0
- package/docs/specs/027-debugger-failure-diagnostics/intent.md +43 -0
- package/docs/specs/027-debugger-failure-diagnostics/plan.md +86 -0
- package/docs/specs/027-debugger-failure-diagnostics/spec.md +133 -0
- package/docs/specs/028-compact-debugger-responses/intent.md +41 -0
- package/docs/specs/028-compact-debugger-responses/plan.md +112 -0
- package/docs/specs/028-compact-debugger-responses/spec.md +108 -0
- package/docs/specs/029-kotlin-locals-validation/report.md +119 -0
- package/docs/specs/030-android-coroutine-validation/evidence.json +475 -0
- package/docs/specs/030-android-coroutine-validation/intent.md +47 -0
- package/docs/specs/030-android-coroutine-validation/plan.md +147 -0
- package/docs/specs/030-android-coroutine-validation/report.md +240 -0
- package/docs/specs/030-android-coroutine-validation/spec.md +107 -0
- package/docs/specs/031-ios-system-traces/intent.md +38 -0
- package/docs/specs/031-ios-system-traces/investigation.md +92 -0
- package/docs/specs/031-ios-system-traces/late-run-failure-evidence.json +32 -0
- package/docs/specs/031-ios-system-traces/plan.md +138 -0
- package/docs/specs/031-ios-system-traces/pr102-monitor-evidence.json +22 -0
- package/docs/specs/031-ios-system-traces/simulator-evidence.json +47 -0
- package/docs/specs/031-ios-system-traces/spec.md +135 -0
- package/docs/specs/032-ios-runtime-debugger/evidence.json +176 -0
- package/docs/specs/032-ios-runtime-debugger/intent.md +38 -0
- package/docs/specs/032-ios-runtime-debugger/plan.md +95 -0
- package/docs/specs/032-ios-runtime-debugger/report.md +205 -0
- package/docs/specs/032-ios-runtime-debugger/spec.md +153 -0
- package/docs/tools/TOOLS.md +31 -18
- package/docs/tools/{evidence.md → correlated-evidence.md} +9 -1
- package/docs/tools/debugger.md +120 -4
- package/docs/tools/interact.md +42 -20
- package/docs/tools/manage.md +25 -44
- package/docs/tools/observe.md +55 -23
- package/docs/tools/system-traces.md +89 -14
- package/docs/tools/system.md +12 -5
- package/package.json +12 -8
- package/scripts/agent-plugin.mjs +55 -5
- package/scripts/architecture-graph.mjs +69 -0
- package/scripts/check-architecture.mjs +47 -0
- package/scripts/code-quality-baseline.json +1 -0
- package/scripts/code-quality.mjs +161 -0
- package/src/contracts/execution-controls.ts +26 -0
- package/src/contracts/selector.ts +17 -0
- package/src/contracts/target.ts +19 -0
- package/src/contracts/ui.ts +94 -0
- package/src/debugger/android.ts +3 -2
- package/src/debugger/diagnostics.ts +43 -0
- package/src/debugger/guard.ts +10 -5
- package/src/debugger/ios-worker.ts +49 -0
- package/src/debugger/ios.ts +45 -0
- package/{worker → src/debugger/java}/DebuggerWorker.java +9 -3
- package/src/debugger/lldb/breakpoints.py +51 -0
- package/src/debugger/lldb/inspection.py +109 -0
- package/src/debugger/lldb/worker.py +203 -0
- package/src/debugger/protocol.ts +37 -0
- package/src/debugger/sessions.ts +326 -155
- package/src/debugger/worker.ts +57 -41
- package/src/interact/adjustment/adjustment-context.ts +83 -0
- package/src/interact/adjustment/adjustment-gestures.ts +48 -0
- package/src/interact/adjustment/adjustment-plan.ts +23 -0
- package/src/interact/adjustment/adjustment-resolution.ts +104 -0
- package/src/interact/adjustment/adjustment-result.ts +34 -0
- package/src/interact/adjustment/adjustment-semantic.ts +53 -0
- package/src/interact/adjustment/adjustment-verification.ts +60 -0
- package/src/interact/adjustment/adjustment.ts +49 -0
- package/src/interact/adjustment/control-geometry.ts +120 -0
- package/src/interact/adjustment/control-values.ts +141 -0
- package/src/interact/adjustment/slider-labels.ts +84 -0
- package/src/interact/assertions/screen-assertion.ts +39 -0
- package/src/interact/assertions/state-assertion-context.ts +48 -0
- package/src/interact/assertions/state-assertion.ts +64 -0
- package/src/interact/assertions/state-comparison.ts +168 -0
- package/src/interact/assertions/visibility-assertion.ts +41 -0
- package/src/interact/conditional-action.ts +18 -12
- package/src/interact/index.ts +89 -3494
- package/src/interact/input-service.ts +11 -0
- package/src/interact/interaction-trace.ts +36 -0
- package/src/interact/model.ts +109 -0
- package/src/interact/observation.ts +7 -0
- package/src/interact/targeting/candidate-ancestor.ts +49 -0
- package/src/interact/targeting/candidate-result.ts +24 -0
- package/src/interact/targeting/candidate-scoring.ts +42 -0
- package/src/interact/targeting/element-helpers.ts +243 -0
- package/src/interact/targeting/find-element.ts +47 -0
- package/src/interact/targeting/nearby-control.ts +46 -0
- package/src/interact/targeting/resolved-elements.ts +20 -0
- package/src/interact/targeting/tap-target.ts +22 -0
- package/src/interact/targeting/target-scope.ts +121 -0
- package/src/interact/waits/legacy-log-wait.ts +30 -0
- package/src/interact/waits/legacy-wait-observations.ts +55 -0
- package/src/interact/waits/legacy-wait-state.ts +48 -0
- package/src/interact/waits/legacy-wait.ts +34 -0
- package/src/interact/waits/screen-wait.ts +37 -0
- package/src/interact/waits/ui-change-helpers.ts +184 -0
- package/src/interact/waits/ui-change-state.ts +26 -0
- package/src/interact/waits/ui-change-wait.ts +59 -0
- package/src/interact/waits/ui-wait-condition.ts +52 -0
- package/src/interact/waits/ui-wait-state.ts +55 -0
- package/src/interact/waits/ui-wait.ts +84 -0
- package/src/manage/android.ts +56 -50
- package/src/manage/index.ts +63 -93
- package/src/manage/ios/build-types.ts +14 -0
- package/src/manage/ios/build.ts +230 -0
- package/src/manage/ios/project-discovery.ts +26 -0
- package/src/manage/ios/scheme.ts +16 -0
- package/src/manage/ios.ts +67 -298
- package/src/observe/android/context.ts +1 -0
- package/src/observe/android/current-screen.ts +63 -0
- package/src/observe/android/fingerprint.ts +13 -0
- package/src/observe/android/log-stream.ts +127 -0
- package/src/observe/android/logs.ts +110 -0
- package/src/observe/android/screenshot.ts +79 -0
- package/src/observe/android/ui-tree.ts +113 -0
- package/src/observe/android.ts +17 -531
- package/src/observe/evidence.ts +122 -70
- package/src/observe/index.ts +24 -286
- package/src/observe/ios/context.ts +22 -0
- package/src/observe/ios/fingerprint.ts +12 -0
- package/src/observe/ios/log-stream.ts +103 -0
- package/src/observe/ios/logs.ts +179 -0
- package/src/observe/ios/screenshot.ts +26 -0
- package/src/observe/ios/ui-elements.ts +266 -0
- package/src/observe/ios/ui-tree.ts +143 -0
- package/src/observe/ios-trace/artifact.ts +55 -0
- package/src/observe/ios-trace/capabilities.ts +74 -0
- package/src/observe/ios-trace/native.ts +72 -0
- package/src/observe/ios-trace/notification.ts +30 -0
- package/src/observe/ios-trace/process.ts +82 -0
- package/src/observe/ios-trace/sessions.ts +204 -0
- package/src/observe/ios.ts +18 -749
- package/src/observe/logs/model.ts +11 -0
- package/src/{network → observe/network}/index.ts +2 -2
- package/src/observe/readiness-service.ts +6 -4
- package/src/observe/readiness.ts +42 -21
- package/src/observe/screenshot-encoding.ts +32 -0
- package/src/observe/snapshot-collection.ts +69 -0
- package/src/observe/snapshot-logs.ts +26 -0
- package/src/observe/snapshot-metadata.ts +51 -31
- package/src/observe/snapshot-semantic.ts +153 -0
- package/src/observe/system-trace-error.ts +3 -0
- package/src/observe/system-trace-router.ts +61 -0
- package/src/observe/system-trace.ts +28 -19
- package/src/runtime/action-results.ts +376 -0
- package/src/runtime/clock.ts +9 -0
- package/src/server/common.ts +9 -359
- package/src/server/definitions/assert.ts +164 -0
- package/src/server/definitions/diagnostic.ts +120 -0
- package/src/server/definitions/input.ts +276 -0
- package/src/server/definitions/manage.ts +196 -0
- package/src/server/definitions/observe.ts +151 -0
- package/src/server/definitions/target.ts +140 -0
- package/src/server/definitions/wait.ts +107 -0
- package/src/server/handlers/action-execution.ts +164 -0
- package/src/server/handlers/correlation.ts +20 -0
- package/src/server/handlers/debugger-handlers.ts +58 -0
- package/src/server/handlers/debugger-response.ts +7 -0
- package/src/server/handlers/diagnostic.ts +86 -0
- package/src/server/handlers/handler-types.ts +7 -0
- package/src/server/handlers/input.ts +173 -0
- package/src/server/handlers/interact.ts +135 -0
- package/src/server/handlers/journey-assertions.ts +39 -0
- package/src/server/handlers/journey.ts +132 -0
- package/src/server/handlers/manage.ts +141 -0
- package/src/server/handlers/observe.ts +116 -0
- package/src/server/handlers/payload.ts +36 -0
- package/src/server/handlers/tool-handlers.ts +170 -0
- package/src/server/schemas/condition-schema.ts +2 -0
- package/src/server/schemas/debugger-schema.ts +46 -0
- package/src/server/{journey-schema.ts → schemas/journey-schema.ts} +7 -22
- package/src/server/schemas/system-trace-schema.ts +23 -0
- package/src/server/tool-definitions.ts +67 -1143
- package/src/server-core.ts +2 -2
- package/src/server.ts +4 -4
- package/src/system/android-status.ts +124 -0
- package/src/system/android.ts +33 -21
- package/src/system/index.ts +21 -525
- package/src/system/ios-status.ts +147 -0
- package/src/system/ios.ts +14 -10
- package/src/system/model.ts +41 -0
- package/src/system/probes.ts +114 -0
- package/src/system/status-summary.ts +47 -0
- package/src/system/unsupported-status.ts +55 -0
- package/src/types.ts +16 -106
- package/src/utils/android/commands.ts +81 -0
- package/src/utils/android/gradle.ts +132 -0
- package/src/utils/android/logs.ts +103 -0
- package/src/utils/android/ui-tree.ts +239 -0
- package/src/utils/android/utils.ts +16 -556
- package/src/utils/cli/idb/check-idb.ts +4 -4
- package/src/utils/cli/idb/idb-helper.ts +6 -8
- package/src/utils/cli/idb/install-idb.ts +15 -9
- package/src/utils/cli/ios/preflight-ios.ts +39 -31
- package/src/utils/cli/ios/run-ios-ui-tree-tap.ts +4 -4
- package/src/utils/ios/utils.ts +60 -61
- package/src/utils/java.ts +62 -43
- package/src/utils/resolve-device.ts +9 -6
- package/src/utils/ui/index.ts +28 -28
- package/test/device/automated/debugger/coroutine-lifecycle.ts +27 -0
- package/test/device/automated/debugger/coroutine-support.ts +140 -0
- package/test/device/automated/debugger/coroutine.android.test.ts +169 -0
- package/test/device/automated/debugger/kotlin.android.test.ts +127 -0
- package/test/device/automated/debugger/runtime.android.test.ts +19 -3
- package/test/device/automated/debugger/runtime.ios.test.ts +221 -0
- package/test/device/automated/interact/interaction.android.test.ts +56 -0
- package/test/device/automated/observe/ios-system-trace.smoke.ts +119 -0
- package/test/device/automated/observe/system-trace.smoke.ts +1 -1
- package/test/device/manual/interact/modul8_selector_tap.manual.ts +1 -1
- package/test/fixtures/contracts/tool-definitions.json +3696 -0
- package/test/fixtures/coroutine-app/MainActivity.kt +100 -0
- package/test/fixtures/coroutine-app/README.md +48 -0
- package/test/fixtures/coroutine-app/build.ts +35 -0
- package/test/fixtures/debugger-app/MainActivity.java +21 -0
- package/test/fixtures/debugger-app/MainActivity.kt +32 -0
- package/test/fixtures/debugger-app/README.md +52 -0
- package/test/fixtures/debugger-app/build.ts +25 -15
- package/test/fixtures/ios-debugger-app/Main.swift +95 -0
- package/test/fixtures/ios-debugger-app/README.md +27 -0
- package/test/fixtures/ios-debugger-app/build.ts +21 -0
- package/test/fixtures/latency-journey-app/README.md +2 -0
- package/test/fixtures/readiness-app/README.md +2 -0
- package/test/helpers/ios-trace-shutdown.ts +29 -0
- package/test/unit/debugger/coroutine-lifecycle.test.ts +43 -0
- package/test/unit/debugger/diagnostic-sessions.test.ts +67 -0
- package/test/unit/debugger/diagnostics.test.ts +80 -0
- package/test/unit/debugger/guards.test.ts +4 -0
- package/test/unit/debugger/handle-guards.test.ts +88 -0
- package/test/unit/debugger/ios-preparation.test.ts +57 -0
- package/test/unit/debugger/ios.test.ts +104 -0
- package/test/unit/debugger/lldb-worker.py +166 -0
- package/test/unit/debugger/lldb-worker.test.ts +10 -0
- package/test/unit/debugger/preparation.test.ts +32 -0
- package/test/unit/debugger/protocol.test.ts +15 -0
- package/test/unit/debugger/sessions.test.ts +1 -1
- package/test/unit/interact/adjustment_service.test.ts +42 -0
- package/test/unit/interact/adjustment_verification.test.ts +35 -0
- package/test/unit/interact/clock_dependencies.test.ts +63 -0
- package/test/unit/interact/element_helpers.test.ts +19 -0
- package/test/unit/interact/legacy_wait_service.test.ts +17 -0
- package/test/unit/interact/state_comparison.test.ts +20 -0
- package/test/unit/interact/target_scope.test.ts +35 -0
- package/test/unit/network/get_network_activity.test.ts +1 -1
- package/test/unit/observe/ios-trace-native.test.ts +90 -0
- package/test/unit/observe/ios-trace-sessions.test.ts +131 -0
- package/test/unit/observe/readiness.test.ts +1 -1
- package/test/unit/observe/screenshot-encoding.test.ts +30 -0
- package/test/unit/observe/snapshot-logs.test.ts +14 -0
- package/test/unit/observe/system-trace-router.test.ts +49 -0
- package/test/unit/quality/agent-plugin-export.test.ts +38 -0
- package/test/unit/quality/architecture.test.ts +60 -0
- package/test/unit/quality/code-quality.test.ts +58 -0
- package/test/unit/quality/interaction_boundaries.test.ts +24 -0
- package/test/unit/server/conditional_actions.test.ts +1 -1
- package/test/unit/server/conditional_schema.test.ts +2 -2
- package/test/unit/server/debugger-response.test.ts +63 -0
- package/test/unit/server/system-trace.test.ts +12 -3
- package/test/unit/server/tool_definitions_parity.test.ts +8 -0
- package/dist/server/debugger-handlers.js +0 -38
- package/dist/server/system-trace-schema.js +0 -17
- package/dist/server/tool-handlers.js +0 -1000
- package/docs/ROADMAP.md +0 -646
- package/docs/benchmarks/ui-tree-performance/bridge-probe.json +0 -29
- package/docs/benchmarks/ui-tree-performance/initial-baseline.json +0 -59560
- package/docs/specs/baseline-spec-v0.md +0 -312
- package/docs/specs/mcp-tooling-spec-v1.md +0 -446
- package/src/server/debugger-handlers.ts +0 -29
- package/src/server/debugger-schema.ts +0 -37
- package/src/server/system-trace-schema.ts +0 -17
- package/src/server/tool-handlers.ts +0 -1008
- /package/dist/{server/condition-schema.js → contracts/condition.js} +0 -0
- /package/dist/server/{readiness-schema.js → schemas/readiness-schema.js} +0 -0
- /package/src/{server/condition-schema.ts → contracts/condition.ts} +0 -0
- /package/src/server/{readiness-schema.ts → schemas/readiness-schema.ts} +0 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import type { Tool } from '@modelcontextprotocol/sdk/types.js'
|
|
2
|
+
|
|
3
|
+
export const targetTools: Tool[] = [
|
|
4
|
+
{
|
|
5
|
+
name: 'adjust_control',
|
|
6
|
+
description: `Purpose:
|
|
7
|
+
Adjust a numeric control value with verification.
|
|
8
|
+
|
|
9
|
+
This is the initial adjustable-control surface for slider-like controls and other controls that expose a numeric value or value_range.
|
|
10
|
+
|
|
11
|
+
Inputs:
|
|
12
|
+
- exactly one of selector or element_id
|
|
13
|
+
- property (defaults to "value")
|
|
14
|
+
- targetValue
|
|
15
|
+
- tolerance (optional; discrete default is 0, continuous default is max(step / 2, 1% of range) when omitted)
|
|
16
|
+
- maxAttempts (optional; defaults to 5)
|
|
17
|
+
- platform/deviceId (optional)
|
|
18
|
+
|
|
19
|
+
Output Structure:
|
|
20
|
+
- action_id, timestamp (ISO 8601), action_type
|
|
21
|
+
- lifecycle_state: post-dispatch lifecycle state (pending_verification or failed)
|
|
22
|
+
- source_module: runtime source of the action envelope
|
|
23
|
+
- target_state / actual_state / within_tolerance / converged / attempts / adjustment_mode
|
|
24
|
+
- target.selector = original selector or element handle
|
|
25
|
+
- success = true when the control converges within tolerance
|
|
26
|
+
|
|
27
|
+
Verification Guidance:
|
|
28
|
+
- Prefer direct platform adjustment when the runtime exposes it; then verified increment/decrement actions; use coordinate fallback only as degraded mode
|
|
29
|
+
- Use expect_state for the control value readback
|
|
30
|
+
- Do not use derived semantic metadata as proof of success
|
|
31
|
+
|
|
32
|
+
Failure Handling:
|
|
33
|
+
- ELEMENT_NOT_FOUND → re-resolve the control
|
|
34
|
+
- ELEMENT_NOT_INTERACTABLE → the control cannot be adjusted through the current runtime
|
|
35
|
+
- CONTROL_CONVERGENCE_FAILED → the control did not converge within bounded retries or the requested value is out of range
|
|
36
|
+
- UNKNOWN → capture a snapshot and stop`,
|
|
37
|
+
inputSchema: {
|
|
38
|
+
type: 'object',
|
|
39
|
+
properties: {
|
|
40
|
+
selector: {
|
|
41
|
+
type: 'object',
|
|
42
|
+
properties: {
|
|
43
|
+
text: { type: 'string' },
|
|
44
|
+
resource_id: { type: 'string' },
|
|
45
|
+
accessibility_id: { type: 'string' },
|
|
46
|
+
contains: { type: 'boolean', default: false }
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
element_id: { type: 'string', description: 'Optional previously resolved element identifier.' },
|
|
50
|
+
property: { type: 'string', description: 'Readable numeric state property to adjust.', default: 'value' },
|
|
51
|
+
targetValue: { type: 'number', description: 'Target numeric value.' },
|
|
52
|
+
tolerance: { type: 'number', description: 'Accepted numeric tolerance around the target value. Defaults are derived from the readable control domain.' },
|
|
53
|
+
maxAttempts: { type: 'number', description: 'Maximum adjustment attempts.', default: 5 },
|
|
54
|
+
platform: { type: 'string', enum: ['android', 'ios'], description: 'Optional platform override' },
|
|
55
|
+
deviceId: { type: 'string', description: 'Optional device serial/udid' }
|
|
56
|
+
},
|
|
57
|
+
required: ['targetValue'],
|
|
58
|
+
oneOf: [
|
|
59
|
+
{ required: ['selector'] },
|
|
60
|
+
{ required: ['element_id'] }
|
|
61
|
+
]
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: 'find_element',
|
|
66
|
+
description: `Find a UI element by semantic query (text, content-desc, resource-id, class).
|
|
67
|
+
|
|
68
|
+
Returns the best match plus resolution metadata when available, including confidence, selection reason, and fallback alternates.`,
|
|
69
|
+
inputSchema: {
|
|
70
|
+
type: 'object',
|
|
71
|
+
properties: {
|
|
72
|
+
query: { type: 'string', description: 'Search query (text or label)' },
|
|
73
|
+
exact: { type: 'boolean', description: 'Require exact match (true/false)', default: false },
|
|
74
|
+
timeoutMs: { type: 'number', description: 'Timeout in ms to keep searching', default: 3000 },
|
|
75
|
+
platform: { type: 'string', enum: ['android', 'ios'], description: 'Optional platform override' },
|
|
76
|
+
deviceId: { type: 'string', description: 'Optional device serial/udid' }
|
|
77
|
+
},
|
|
78
|
+
required: ['query']
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
name: 'tap_element',
|
|
83
|
+
description: `Purpose:
|
|
84
|
+
Tap a previously resolved UI element using its elementId.
|
|
85
|
+
|
|
86
|
+
Inputs:
|
|
87
|
+
- elementId: a resolved UI element identifier returned by wait_for_ui
|
|
88
|
+
|
|
89
|
+
Output Structure:
|
|
90
|
+
- action_id: unique timestamp-based action identifier
|
|
91
|
+
- timestamp: ISO 8601 timestamp for the action attempt
|
|
92
|
+
- action_type: "tap_element"
|
|
93
|
+
- lifecycle_state: post-dispatch lifecycle state (pending_verification or failed)
|
|
94
|
+
- source_module: runtime source of the action envelope
|
|
95
|
+
- target.selector: original target handle ({ elementId })
|
|
96
|
+
- target.resolved: minimal resolved element info used for the tap
|
|
97
|
+
- success: true when the tap was dispatched
|
|
98
|
+
- failure_code: present when success=false
|
|
99
|
+
- retryable: present when failure_code exists
|
|
100
|
+
- ui_fingerprint_before/ui_fingerprint_after: optional fingerprints captured around the action
|
|
101
|
+
|
|
102
|
+
Recommended Usage:
|
|
103
|
+
1. Resolve the target with wait_for_ui or another deterministic resolver
|
|
104
|
+
2. Call tap_element
|
|
105
|
+
3. If needed, wait for transition using wait_for_*
|
|
106
|
+
4. Verify outcome using expect_*
|
|
107
|
+
- use expect_screen when navigation is expected
|
|
108
|
+
- use expect_element_visible when the UI change is local
|
|
109
|
+
5. If verification fails, inspect failure_code and follow the retry strategy below
|
|
110
|
+
|
|
111
|
+
Verification Guidance:
|
|
112
|
+
- Follow RESOLVE → ACT → WAIT (if needed) → EXPECT
|
|
113
|
+
- Prefer expect_screen for navigation or modal transitions
|
|
114
|
+
- Prefer expect_element_visible when the tap should reveal or update a specific element
|
|
115
|
+
- wait_for_* may be used for resolution and synchronization, but not as the final verification step when an applicable expect_* tool exists
|
|
116
|
+
- Do not treat tap_element.success as outcome success; it only means the tap was executed
|
|
117
|
+
|
|
118
|
+
Failure Handling:
|
|
119
|
+
- STALE_REFERENCE → re-resolve the element, then retry
|
|
120
|
+
- ELEMENT_NOT_INTERACTABLE → wait or refine the target, then retry
|
|
121
|
+
- UNKNOWN → capture a snapshot and stop
|
|
122
|
+
|
|
123
|
+
This tool reports execution success only. Verification must be done with a separate expect_* tool.`,
|
|
124
|
+
inputSchema: {
|
|
125
|
+
type: 'object',
|
|
126
|
+
properties: {
|
|
127
|
+
elementId: {
|
|
128
|
+
type: 'string',
|
|
129
|
+
description: 'A unique element identifier returned by wait_for_ui'
|
|
130
|
+
},
|
|
131
|
+
selector: { type: 'object', properties: { text: { type: 'string' }, resource_id: { type: 'string' }, accessibility_id: { type: 'string' }, contains: { type: 'boolean' } } },
|
|
132
|
+
waitFor: { type: 'object', properties: { condition: { type: 'string', enum: ['exists', 'visible', 'clickable'] }, timeoutMs: { type: 'number', minimum: 100, maximum: 10000 }, pollIntervalMs: { type: 'number', minimum: 50, maximum: 1000 }, match: { type: 'object', properties: { index: { type: 'number' } } } } },
|
|
133
|
+
platform: { type: 'string', enum: ['android', 'ios'] },
|
|
134
|
+
deviceId: { type: 'string' },
|
|
135
|
+
verificationMode: { type: 'string', enum: ['none', 'light', 'full'], default: 'full' },
|
|
136
|
+
responseMode: { type: 'string', enum: ['compact', 'debug'], default: 'debug' }
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
]
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type { Tool } from '@modelcontextprotocol/sdk/types.js'
|
|
2
|
+
|
|
3
|
+
export const waitTools: Tool[] = [
|
|
4
|
+
{
|
|
5
|
+
name: 'wait_for_screen_change',
|
|
6
|
+
description: `Purpose:
|
|
7
|
+
Detect that a screen transition has occurred by waiting for the current fingerprint to differ from a previous fingerprint.
|
|
8
|
+
|
|
9
|
+
Capabilities:
|
|
10
|
+
- Synchronization for uncertain navigation timing
|
|
11
|
+
- Detection that something changed on screen
|
|
12
|
+
|
|
13
|
+
Constraints:
|
|
14
|
+
- Does not verify correctness of the resulting state
|
|
15
|
+
- Must not be used alone to confirm action success when an applicable expect_* tool exists
|
|
16
|
+
- For backend/API activity without a visible UI change, pass the runtime action_type into classify_action_outcome and collect network evidence only if the result remains ambiguous
|
|
17
|
+
|
|
18
|
+
Recommended Usage:
|
|
19
|
+
1. Capture or define the expected outcome
|
|
20
|
+
2. Call an action tool
|
|
21
|
+
3. Use wait_for_screen_change when transition timing is uncertain
|
|
22
|
+
4. Follow with expect_screen when the expected destination is known`,
|
|
23
|
+
inputSchema: {
|
|
24
|
+
type: 'object',
|
|
25
|
+
properties: {
|
|
26
|
+
platform: { type: 'string', enum: ['android', 'ios'], description: 'Optional platform override (android|ios)' },
|
|
27
|
+
previousFingerprint: { type: 'string', description: 'The fingerprint to compare against (required)' },
|
|
28
|
+
timeoutMs: { type: 'number', description: 'Timeout in ms to wait for change (default 5000)', default: 5000 },
|
|
29
|
+
pollIntervalMs: { type: 'number', description: 'Polling interval in ms (default 300)', default: 300 },
|
|
30
|
+
deviceId: { type: 'string', description: 'Optional device id/udid to target' }
|
|
31
|
+
},
|
|
32
|
+
required: ['previousFingerprint']
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: 'wait_for_ui_change',
|
|
37
|
+
description: `Purpose:
|
|
38
|
+
Wait for a non-navigation UI mutation or in-place update to become stable.
|
|
39
|
+
|
|
40
|
+
Inputs:
|
|
41
|
+
- expected_change (optional): hierarchy_diff, text_change, or state_change
|
|
42
|
+
- timeout_ms (optional)
|
|
43
|
+
- stability_window_ms (optional)
|
|
44
|
+
- scope (optional): screen or subtree
|
|
45
|
+
- target (optional): element_id when scope=subtree
|
|
46
|
+
|
|
47
|
+
Guidance:
|
|
48
|
+
- Prefer wait_for_screen_change for navigation transitions.
|
|
49
|
+
- Prefer wait_for_ui_change for in-place mutations and non-navigation updates.
|
|
50
|
+
- Use the returned snapshot_revision as the observed synchronization point when available.
|
|
51
|
+
- Scoped waits return scope-aware stability metadata and a lightweight change summary.
|
|
52
|
+
|
|
53
|
+
Failure Handling:
|
|
54
|
+
- TIMEOUT means the UI did not change in a stable way within the allotted time.`,
|
|
55
|
+
inputSchema: {
|
|
56
|
+
type: 'object',
|
|
57
|
+
properties: {
|
|
58
|
+
platform: { type: 'string', enum: ['android', 'ios'], description: 'Optional platform override (android|ios)' },
|
|
59
|
+
deviceId: { type: 'string', description: 'Optional device id/udid to target' },
|
|
60
|
+
expected_change: { type: 'string', enum: ['hierarchy_diff', 'text_change', 'state_change'], description: 'Optional type of UI change to wait for' },
|
|
61
|
+
scope: { type: 'string', enum: ['screen', 'subtree'], default: 'screen', description: 'Synchronization scope for the wait' },
|
|
62
|
+
target: { type: 'string', description: 'Target element_id when scope is subtree' },
|
|
63
|
+
timeout_ms: { type: 'number', description: 'Timeout in ms to wait for change (default 60000)', default: 60000 },
|
|
64
|
+
stability_window_ms: { type: 'number', description: 'How long the change must remain stable before success (default 300)', default: 300 }
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: 'wait_for_ui',
|
|
70
|
+
description: `Purpose:
|
|
71
|
+
Resolve elements and/or detect that a UI transition or availability condition has occurred.
|
|
72
|
+
|
|
73
|
+
Capabilities:
|
|
74
|
+
- Deterministic element resolution
|
|
75
|
+
- Synchronization when element timing or availability is uncertain
|
|
76
|
+
|
|
77
|
+
Constraints:
|
|
78
|
+
- Does not verify correctness of the resulting state
|
|
79
|
+
- Must not be used alone to confirm action success when an applicable expect_* tool exists
|
|
80
|
+
|
|
81
|
+
Recommended Usage:
|
|
82
|
+
1. Use wait_for_ui to resolve an element before acting or to wait for UI readiness
|
|
83
|
+
2. Call the action tool
|
|
84
|
+
3. If the expected outcome is known, follow with expect_* as final verification`,
|
|
85
|
+
inputSchema: {
|
|
86
|
+
type: 'object',
|
|
87
|
+
properties: {
|
|
88
|
+
selector: {
|
|
89
|
+
type: 'object',
|
|
90
|
+
properties: {
|
|
91
|
+
text: { type: 'string' },
|
|
92
|
+
resource_id: { type: 'string' },
|
|
93
|
+
accessibility_id: { type: 'string' },
|
|
94
|
+
contains: { type: 'boolean', description: 'When true, perform substring matching', default: false }
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
condition: { type: 'string', enum: ['exists', 'not_exists', 'visible', 'clickable'], default: 'exists' },
|
|
98
|
+
timeout_ms: { type: 'number', default: 60000 },
|
|
99
|
+
poll_interval_ms: { type: 'number', default: 300 },
|
|
100
|
+
match: { type: 'object', properties: { index: { type: 'number' } } },
|
|
101
|
+
retry: { type: 'object', properties: { max_attempts: { type: 'number', default: 1 }, backoff_ms: { type: 'number', default: 0 } } },
|
|
102
|
+
platform: { type: 'string', enum: ['android', 'ios'], description: 'Optional platform override' },
|
|
103
|
+
deviceId: { type: 'string', description: 'Optional device serial/udid' }
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
]
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import type { ToolPayload } from './payload.js'
|
|
2
|
+
import { payloadOf } from './payload.js'
|
|
3
|
+
import { correlatedHandler } from './correlation.js'
|
|
4
|
+
import { interactionControls } from '../../contracts/execution-controls.js'
|
|
5
|
+
import { currentEvidenceActionId, markEvidenceVerification } from '../../observe/evidence.js'
|
|
6
|
+
import { measure, withTiming } from '../../utils/timing.js'
|
|
7
|
+
import { randomUUID } from 'node:crypto'
|
|
8
|
+
import { runWithBudget } from '../../utils/operation-budget.js'
|
|
9
|
+
import { validateExpectedState } from '../schemas/condition-schema.js'
|
|
10
|
+
import { conditionFailureCode, createConditionalAction, withConditionalAction } from '../../interact/conditional-action.js'
|
|
11
|
+
import { resolveTargetDevice, withResolvedDevice } from '../../utils/resolve-device.js'
|
|
12
|
+
|
|
13
|
+
import { ToolsObserve } from '../../observe/index.js'
|
|
14
|
+
import { recordObservationEvent, withObservationContext } from '../../observe/performance-metrics.js'
|
|
15
|
+
import {
|
|
16
|
+
buildActionExecutionResult,
|
|
17
|
+
ToolCallArgs,
|
|
18
|
+
ToolHandler,
|
|
19
|
+
wrapResponse,
|
|
20
|
+
wrapToolError
|
|
21
|
+
} from '../common.js'
|
|
22
|
+
import type { PlatformArg, VerificationMode } from './handler-types.js'
|
|
23
|
+
|
|
24
|
+
export function compactAction(result: ToolPayload, verificationMode: VerificationMode, started = true, stateDelta?: unknown, totalMs = 0) {
|
|
25
|
+
return {
|
|
26
|
+
action_id: result.action_id,
|
|
27
|
+
action_type: result.action_type,
|
|
28
|
+
success: !!result.success,
|
|
29
|
+
lifecycle_state: result.success ? (verificationMode === 'full' ? result.lifecycle_state : 'pending_verification') : 'failed',
|
|
30
|
+
...(result.failure_code ? { failure_code: result.failure_code } : {}),
|
|
31
|
+
...(typeof result.retryable === 'boolean' ? { retryable: result.retryable } : {}),
|
|
32
|
+
delivery_status: result.success ? 'delivered' : (started ? 'unknown' : 'not_delivered'),
|
|
33
|
+
dispatch_started: started,
|
|
34
|
+
verification: { mode: verificationMode, status: result.success ? (verificationMode === 'none' ? 'not_requested' : verificationMode === 'light' ? 'observed' : (result.lifecycle_state === 'verified' ? 'verified' : 'observed')) : 'failed' },
|
|
35
|
+
...(stateDelta ? { state_delta: stateDelta } : {}),
|
|
36
|
+
timing: { total_ms: totalMs }
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function createAction(type: string, args: ToolCallArgs, timing: Record<string, number>) {
|
|
41
|
+
const started = performance.now()
|
|
42
|
+
const controls = interactionControls(args)
|
|
43
|
+
const expected = validateExpectedState(type, args)
|
|
44
|
+
const condition = expected ? createConditionalAction(args.platform as PlatformArg, args.deviceId as string, expected) : undefined
|
|
45
|
+
const budgetMs = controls.actionTimeoutMs ?? ({ start_app: 10000, restart_app: 15000, scroll_to_element: 10000 }[type] ?? 5000)
|
|
46
|
+
const unbounded = args._journey !== true && controls.verificationMode === 'full' && controls.responseMode === 'debug' && controls.actionTimeoutMs === undefined
|
|
47
|
+
return {
|
|
48
|
+
type, args, timing, started, controls, condition, budgetMs, unbounded,
|
|
49
|
+
result: {} as ToolPayload, dispatchStarted: false, blocked: false,
|
|
50
|
+
delta: undefined as unknown, observationAvailable: false
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
type Action = ReturnType<typeof createAction>
|
|
54
|
+
async function dispatchAction(s: Action, execute: ToolHandler) {
|
|
55
|
+
const { type, args, controls, condition, budgetMs } = s
|
|
56
|
+
const dispatchWithBudget = (timeoutMs: number) => runWithBudget(timeoutMs, async (budget) => {
|
|
57
|
+
try {
|
|
58
|
+
if (!condition) return payloadOf(await execute(args))
|
|
59
|
+
return await withConditionalAction(condition, async () => {
|
|
60
|
+
const device = await resolveTargetDevice({ platform: condition.platform, deviceId: condition.deviceId })
|
|
61
|
+
return withResolvedDevice(device, async () => payloadOf(await execute(args)))
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
finally { s.dispatchStarted = budget.dispatchStarted }
|
|
65
|
+
})
|
|
66
|
+
try {
|
|
67
|
+
// Omitted controls retain the existing adapter budgets.
|
|
68
|
+
s.result = s.unbounded
|
|
69
|
+
? await dispatchWithBudget(Infinity) : await dispatchWithBudget(budgetMs)
|
|
70
|
+
if (s.result.success) s.dispatchStarted = true
|
|
71
|
+
} catch (error) {
|
|
72
|
+
if (!condition && controls.verificationMode === 'full' && controls.responseMode === 'debug' && controls.actionTimeoutMs === undefined && !/TIMEOUT|timed out/i.test(String(error))) return wrapToolError(type, error)
|
|
73
|
+
s.result = { success: false, failure_code: /TIMEOUT|timed out/i.test(String(error)) ? 'ACTION_TIMEOUT' : 'UNKNOWN', error: String(error) }
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function rejectCondition(s: Action) {
|
|
77
|
+
const { condition, type } = s
|
|
78
|
+
s.blocked = !!condition && ['mismatch', 'unavailable'].includes(condition.result.status)
|
|
79
|
+
if (s.blocked && condition) {
|
|
80
|
+
s.dispatchStarted = false
|
|
81
|
+
s.result = buildActionExecutionResult({
|
|
82
|
+
actionType: type, sourceModule: 'server', device: condition.result.observed?.device,
|
|
83
|
+
selector: s.result?.target?.selector ?? null, resolved: s.result?.target?.resolved,
|
|
84
|
+
success: false, uiFingerprintBefore: s.result?.ui_fingerprint_before ?? null, uiFingerprintAfter: null,
|
|
85
|
+
failure: { failureCode: conditionFailureCode(condition), retryable: false },
|
|
86
|
+
traceSteps: [{ stage: 'verify', timestamp: Date.now(), result: 'failure', attempt_index: 0, metadata: { phase: 'precondition', dispatch_started: false } }]
|
|
87
|
+
})
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function normalizeAction(s: Action) {
|
|
91
|
+
const { type, args, timing, controls } = s
|
|
92
|
+
rejectCondition(s)
|
|
93
|
+
if (s.result.failure_code === 'TIMEOUT' || /ACTION_TIMEOUT|timeout/i.test(String(s.result.error ?? s.result.reason ?? s.result.details?.error ?? ''))) s.result.failure_code = 'ACTION_TIMEOUT'
|
|
94
|
+
if (s.result.failure_code === 'ACTION_TIMEOUT') s.result.retryable = !s.dispatchStarted
|
|
95
|
+
if (!s.result.success && typeof s.result.retryable !== 'boolean') s.result.retryable = !s.dispatchStarted
|
|
96
|
+
s.result.action_id ??= currentEvidenceActionId() ?? randomUUID()
|
|
97
|
+
s.result.action_type ??= type
|
|
98
|
+
recordObservationEvent({
|
|
99
|
+
step_id: args._stepId as string | undefined,
|
|
100
|
+
action_type: type,
|
|
101
|
+
dispatch_ms: timing.dispatch_ms,
|
|
102
|
+
verification_mode: controls.verificationMode,
|
|
103
|
+
dispatch_started: s.dispatchStarted
|
|
104
|
+
})
|
|
105
|
+
}
|
|
106
|
+
async function verifyAction(s: Action) {
|
|
107
|
+
const { args, controls } = s
|
|
108
|
+
if (s.result.success && controls.verificationMode === 'light') {
|
|
109
|
+
const verificationStarted = performance.now()
|
|
110
|
+
const tree = await withObservationContext({ stepId: args._stepId as string | undefined, purpose: 'verification' }, () =>
|
|
111
|
+
measure('post_observation_ms', () => runWithBudget(controls.verificationTimeoutMs, () =>
|
|
112
|
+
ToolsObserve.getUITreeHandler({ platform: (args.platform as PlatformArg | undefined) ?? (s.result.device?.platform as PlatformArg | undefined), deviceId: (args.deviceId as string | undefined) ?? s.result.device?.id })))).catch(() => null)
|
|
113
|
+
markEvidenceVerification()
|
|
114
|
+
s.observationAvailable = !!tree && !tree.error
|
|
115
|
+
recordObservationEvent({
|
|
116
|
+
verification_budget_ms: controls.verificationTimeoutMs,
|
|
117
|
+
verification_elapsed_ms: performance.now() - verificationStarted,
|
|
118
|
+
verification_outcome: s.observationAvailable ? 'observed' : 'unavailable',
|
|
119
|
+
verification_budget_expired: !s.observationAvailable && performance.now() - verificationStarted >= controls.verificationTimeoutMs
|
|
120
|
+
})
|
|
121
|
+
if (s.observationAvailable && tree?.device) s.delta = ToolsObserve.getLatestStateDelta(tree.device.platform as PlatformArg, tree.device.id) ?? undefined
|
|
122
|
+
}
|
|
123
|
+
if (!s.blocked && controls.verificationMode === 'full' && s.dispatchStarted) markEvidenceVerification()
|
|
124
|
+
}
|
|
125
|
+
function actionResponse(s: Action) {
|
|
126
|
+
const { timing, started, controls, condition, budgetMs } = s
|
|
127
|
+
const compact = compactAction(s.result, controls.verificationMode, s.dispatchStarted, s.delta, performance.now() - started)
|
|
128
|
+
if (s.blocked) compact.verification.status = 'not_requested'
|
|
129
|
+
if (s.result.success && controls.verificationMode === 'light' && !s.observationAvailable) compact.verification.status = 'unavailable'
|
|
130
|
+
const evidence = {
|
|
131
|
+
...compact,
|
|
132
|
+
...(condition ? {
|
|
133
|
+
condition: controls.responseMode === 'compact' && condition.result.status === 'matched'
|
|
134
|
+
? {
|
|
135
|
+
...condition.result, observed: condition.result.observed ? {
|
|
136
|
+
snapshot_session_id: condition.result.observed.snapshot_session_id,
|
|
137
|
+
snapshot_revision: condition.result.observed.snapshot_revision,
|
|
138
|
+
captured_at_ms: condition.result.observed.captured_at_ms
|
|
139
|
+
} : null
|
|
140
|
+
} : condition.result
|
|
141
|
+
} : {}),
|
|
142
|
+
...(controls.verificationMode === 'light' ? { state_delta_available: !!s.delta } : {}),
|
|
143
|
+
...(s.result.success && controls.verificationMode === 'light' && !s.observationAvailable ? { verification_diagnostic: { code: 'VERIFICATION_UNAVAILABLE', retryable: true } } : {})
|
|
144
|
+
}
|
|
145
|
+
return wrapResponse(controls.responseMode === 'compact' ? evidence : {
|
|
146
|
+
...s.result, ...evidence, timing: { ...timing, total_ms: performance.now() - started },
|
|
147
|
+
effective_controls: { ...controls, actionTimeoutMs: s.unbounded ? null : budgetMs, timeout_bound: !(s.unbounded) }
|
|
148
|
+
}, controls.responseMode === 'debug')
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export function actionHandler(type: string, execute: ToolHandler): ToolHandler {
|
|
152
|
+
return correlatedHandler(type, async args => {
|
|
153
|
+
const timing: Record<string, number> = {}
|
|
154
|
+
return withTiming(timing, async () => {
|
|
155
|
+
const state = createAction(type, args, timing)
|
|
156
|
+
const error = await dispatchAction(state, execute)
|
|
157
|
+
if (error) return error
|
|
158
|
+
normalizeAction(state)
|
|
159
|
+
await verifyAction(state)
|
|
160
|
+
return actionResponse(state)
|
|
161
|
+
})
|
|
162
|
+
}, true)
|
|
163
|
+
}
|
|
164
|
+
export { interactionControls, correlatedHandler, payloadOf }
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { TraceError } from '../../observe/system-trace.js'
|
|
2
|
+
import { withEvidence, validateActionRef } from '../../observe/evidence.js'
|
|
3
|
+
import { wrapResponse, wrapToolError, type ToolHandler } from '../common.js'
|
|
4
|
+
export function correlatedHandler(name: string, handler: ToolHandler, action = false, journey = false): ToolHandler {
|
|
5
|
+
return async args => {
|
|
6
|
+
const ref = validateActionRef(args.actionRef)
|
|
7
|
+
const { result, evidence } = await withEvidence({ action, journey, ref }, async () => {
|
|
8
|
+
try { return await handler(args) }
|
|
9
|
+
catch (error) { return error instanceof TraceError ? { ...wrapResponse({ error: { tool: name, code: error.code, message: error.message } }), isError: true } : wrapToolError(name, error) }
|
|
10
|
+
})
|
|
11
|
+
const item = result.content.find(item => item.type === 'text')
|
|
12
|
+
if (item?.text) {
|
|
13
|
+
const payload = JSON.parse(item.text)
|
|
14
|
+
payload.evidence = evidence
|
|
15
|
+
item.text = JSON.stringify(payload)
|
|
16
|
+
}
|
|
17
|
+
return result
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { iosCapabilities } from '../../debugger/ios-worker.js'
|
|
2
|
+
import { debuggerResponse } from './debugger-response.js'
|
|
3
|
+
import { classify, type DebuggerDiagnostic } from '../../debugger/diagnostics.js'
|
|
4
|
+
import { debuggerContracts } from '../schemas/debugger-schema.js'
|
|
5
|
+
import { debuggerSessions, iosDebuggerSessions, debuggerCapabilities } from '../../debugger/sessions.js'
|
|
6
|
+
import { DebuggerError, withDebuggerBudget } from '../../debugger/worker.js'
|
|
7
|
+
import { wrapResponse, type ToolCallArgs } from '../common.js'
|
|
8
|
+
function failure(code: string, summary: Record<string, unknown> = {}, diagnostic?: DebuggerDiagnostic, command = '', mode: 'compact' | 'debug' = 'debug') {
|
|
9
|
+
return {
|
|
10
|
+
...wrapResponse(debuggerResponse(command, mode, {
|
|
11
|
+
debug_session_id: null, device: null, target: null, state: null,
|
|
12
|
+
captured_at_ms: Date.now(), capabilities: debuggerCapabilities, limitations: [], cleanup: null,
|
|
13
|
+
...summary, success: false, error: { code, message: code, retryable: false, ...(diagnostic ? { diagnostic } : {}) }
|
|
14
|
+
})), isError: true
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export async function handleDebugger(name: string, args: ToolCallArgs, signal?: AbortSignal) {
|
|
18
|
+
const parsed = debuggerContracts[name].schema.safeParse(args)
|
|
19
|
+
if (!parsed.success) return failure('INVALID_ARGUMENT')
|
|
20
|
+
const { responseMode, ...input } = parsed.data
|
|
21
|
+
const a = input as { platform?: 'android' | 'ios'; timeoutMs: number; deviceId?: string; appId?: string; processId?: number; debugSessionId?: string }
|
|
22
|
+
const command = debuggerContracts[name].command
|
|
23
|
+
const sessions = selectSessions(a)
|
|
24
|
+
try {
|
|
25
|
+
if (signal?.aborted) throw new DebuggerError('DEBUGGER_CANCELLED')
|
|
26
|
+
const result = await withDebuggerBudget(a.timeoutMs, signal, async () => command === 'capabilities' ? await sessions.capabilities(a.deviceId!, a.appId!, a.processId) :
|
|
27
|
+
command === 'attach' ? await sessions.attach(a.deviceId!, a.appId!, a.processId, a.timeoutMs) :
|
|
28
|
+
await sessions.command(a.debugSessionId!, command, { ...a, signal: command === 'events' ? signal : undefined }, a.timeoutMs))
|
|
29
|
+
if (signal?.aborted && command === 'capabilities') throw new DebuggerError('DEBUGGER_CANCELLED')
|
|
30
|
+
const payload = sessions === iosDebuggerSessions ? iosDiagnostics(result) : result
|
|
31
|
+
return { ...wrapResponse(debuggerResponse(command, responseMode, payload)), ...(!result.success ? { isError: true } : {}) }
|
|
32
|
+
} catch (e) {
|
|
33
|
+
const error = classify(e, 'unknown', 'DEBUGGER_WORKER_FAILED')
|
|
34
|
+
const code = error.code
|
|
35
|
+
let summary: Partial<ReturnType<typeof debuggerSessions.summary>> = {}
|
|
36
|
+
if (a.debugSessionId) { try { summary = sessions.summary(a.debugSessionId) } catch { /* Unknown session */ } }
|
|
37
|
+
const response = failure(code, {
|
|
38
|
+
...(sessions === iosDebuggerSessions ? { capabilities: iosCapabilities } : {}),
|
|
39
|
+
debug_session_id: a.debugSessionId ?? null,
|
|
40
|
+
device: a.deviceId ? { platform: a.platform ?? 'android', id: a.deviceId } : null, ...summary
|
|
41
|
+
}, code === 'DEBUGGER_CLEANUP_FAILED' ? summary.error?.diagnostic : error.diagnostic, command, responseMode)
|
|
42
|
+
if (sessions === iosDebuggerSessions) response.content[0].text = JSON.stringify(iosDiagnostics(JSON.parse(response.content[0].text)))
|
|
43
|
+
return response
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function selectSessions(a: { platform?: string; debugSessionId?: string }) {
|
|
48
|
+
return a.platform === 'ios' || (a.debugSessionId && iosDebuggerSessions.owns(a.debugSessionId)) ? iosDebuggerSessions : debuggerSessions
|
|
49
|
+
}
|
|
50
|
+
function iosRecovery(d: DebuggerDiagnostic) {
|
|
51
|
+
return { ...d, recovery: d.recovery.replace('JDK 17+ availability, including java, javac and jdk.jdi.', 'Xcode and its Swift-enabled LLDB/Python availability.').replace('JDK compiler and worker source/cache', 'LLDB worker source').replace('Java worker', 'LLDB worker').replace('ADB server', 'simulator') }
|
|
52
|
+
}
|
|
53
|
+
function iosDiagnostics<T extends Record<string, unknown>>(value: T) {
|
|
54
|
+
const result = { ...value }
|
|
55
|
+
const error = value.error as { diagnostic?: DebuggerDiagnostic } | undefined
|
|
56
|
+
return { ...result, ...(error?.diagnostic ? { error: { ...error, diagnostic: iosRecovery(error.diagnostic) } } : {}),
|
|
57
|
+
...(Array.isArray(value.diagnostics) ? { diagnostics: (value.diagnostics as DebuggerDiagnostic[]).map(iosRecovery) } : {}) }
|
|
58
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Omit only repeated target metadata; preserve all execution and failure evidence. */
|
|
2
|
+
export function debuggerResponse(command: string, mode: 'compact' | 'debug', payload: Record<string, unknown>) {
|
|
3
|
+
if (mode !== 'compact' || ['capabilities', 'attach', 'state'].includes(command) || payload.debug_session_id == null) return payload
|
|
4
|
+
const result = { ...payload }
|
|
5
|
+
for (const field of ['device', 'target', 'capabilities']) delete result[field]
|
|
6
|
+
return result
|
|
7
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { IosTemplate } from '../../observe/ios-trace/capabilities.js'
|
|
2
|
+
import { systemTraces, TraceError } from '../../observe/system-trace.js'
|
|
3
|
+
import { traceTargetSchema, traceStartSchema, traceControlSchema } from '../schemas/system-trace-schema.js'
|
|
4
|
+
import { resolveTargetDevice } from '../../utils/resolve-device.js'
|
|
5
|
+
|
|
6
|
+
import { ToolsManage } from '../../manage/index.js'
|
|
7
|
+
import { classifyActionOutcome } from '../../interact/classify.js'
|
|
8
|
+
import { ToolsNetwork } from '../../observe/network/index.js'
|
|
9
|
+
import { getSystemStatus } from '../../system/index.js'
|
|
10
|
+
import {
|
|
11
|
+
getArrayArg,
|
|
12
|
+
getBooleanArg,
|
|
13
|
+
getStringArg,
|
|
14
|
+
requireBooleanArg,
|
|
15
|
+
requireStringArg,
|
|
16
|
+
ToolCallArgs,
|
|
17
|
+
wrapResponse
|
|
18
|
+
} from '../common.js'
|
|
19
|
+
import type { PlatformArg, ClassifyNetworkRequestArg } from './handler-types.js'
|
|
20
|
+
|
|
21
|
+
export async function handleListDevices(args: ToolCallArgs) {
|
|
22
|
+
const platform = getStringArg(args, 'platform') as PlatformArg | undefined
|
|
23
|
+
const appId = getStringArg(args, 'appId')
|
|
24
|
+
const res = await ToolsManage.listDevicesHandler({ platform, appId })
|
|
25
|
+
return wrapResponse(res)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export async function handleGetSystemStatus() {
|
|
29
|
+
const result = await getSystemStatus()
|
|
30
|
+
return wrapResponse(result)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function handleClassifyActionOutcome(args: ToolCallArgs) {
|
|
34
|
+
const uiChanged = requireBooleanArg(args, 'uiChanged')
|
|
35
|
+
const expectedElementVisible = getBooleanArg(args, 'expectedElementVisible')
|
|
36
|
+
const actionType = getStringArg(args, 'actionType')
|
|
37
|
+
const networkRequests = getArrayArg<ClassifyNetworkRequestArg>(args, 'networkRequests')
|
|
38
|
+
const hasLogErrors = getBooleanArg(args, 'hasLogErrors')
|
|
39
|
+
const result = classifyActionOutcome({
|
|
40
|
+
uiChanged,
|
|
41
|
+
expectedElementVisible: expectedElementVisible ?? null,
|
|
42
|
+
actionType: actionType ?? null,
|
|
43
|
+
networkRequests: networkRequests ?? null,
|
|
44
|
+
hasLogErrors: hasLogErrors ?? null
|
|
45
|
+
})
|
|
46
|
+
return Promise.resolve(wrapResponse(result))
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export async function handleGetNetworkActivity(args: ToolCallArgs) {
|
|
50
|
+
const platform = requireStringArg(args, 'platform') as PlatformArg
|
|
51
|
+
const deviceId = getStringArg(args, 'deviceId')
|
|
52
|
+
const result = await ToolsNetwork.getNetworkActivity({ platform, deviceId })
|
|
53
|
+
return wrapResponse(result)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export async function handleSystemTrace(name: string, args: ToolCallArgs) {
|
|
57
|
+
const schema = name === 'start_system_trace' ? traceStartSchema : name === 'get_system_trace_capabilities' ? traceTargetSchema : traceControlSchema
|
|
58
|
+
const parsed = schema.safeParse(args)
|
|
59
|
+
if (!parsed.success) throw new TraceError('INVALID_ARGUMENT')
|
|
60
|
+
if (name === 'get_system_trace_capabilities' || name === 'start_system_trace') {
|
|
61
|
+
const target = parsed.data as { platform: PlatformArg; deviceId?: string; durationMs?: number; appId?: string; template?: IosTemplate }
|
|
62
|
+
if (target.platform === 'android' && (target.appId !== undefined || target.template !== undefined)) throw new TraceError('INVALID_ARGUMENT')
|
|
63
|
+
if (target.platform === 'ios') {
|
|
64
|
+
return handleIosTrace(name, target)
|
|
65
|
+
}
|
|
66
|
+
let device
|
|
67
|
+
try { device = await resolveTargetDevice(target) }
|
|
68
|
+
catch {
|
|
69
|
+
if (name === 'start_system_trace') throw new TraceError('TRACE_UNSUPPORTED')
|
|
70
|
+
return wrapResponse({ supported: false, backend: 'perfetto', device: null, prerequisites: { device: false }, reasons: ['DEVICE_UNAVAILABLE'], enabled_sources: [], unavailable_categories: [], limitations: ['An authorised Android device is required'] })
|
|
71
|
+
}
|
|
72
|
+
if (name === 'get_system_trace_capabilities') return wrapResponse(await systemTraces.capabilities(device.id))
|
|
73
|
+
const result = await systemTraces.start(device.id, target.durationMs)
|
|
74
|
+
return { ...wrapResponse(result), ...(result.state === 'failed' ? { isError: true } : {}) }
|
|
75
|
+
}
|
|
76
|
+
const operation = name === 'stop_system_trace' ? 'stop' : name === 'cancel_system_trace' ? 'cancel' : 'status'
|
|
77
|
+
const result = await systemTraces.control((parsed.data as { traceId: string }).traceId, operation)
|
|
78
|
+
return { ...wrapResponse(result), ...(['failed', 'cancelled'].includes(result.state) ? { isError: true } : {}) }
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function handleIosTrace(name: string, target: { deviceId?: string; appId?: string; durationMs?: number; template?: IosTemplate }) {
|
|
82
|
+
if (!target.deviceId || (name === 'start_system_trace' && !target.appId)) throw new TraceError('INVALID_ARGUMENT')
|
|
83
|
+
if (name === 'get_system_trace_capabilities') return wrapResponse(await systemTraces.iosCapabilities(target.deviceId, target.appId, target.template))
|
|
84
|
+
const result = await systemTraces.start(target.deviceId, target.durationMs, { appId: target.appId!, template: target.template })
|
|
85
|
+
return { ...wrapResponse(result), ...(result.state === 'failed' ? { isError: true } : {}) }
|
|
86
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type PlatformArg = 'android' | 'ios'
|
|
2
|
+
export type ProjectTypeArg = 'native' | 'kmp' | 'react-native' | 'flutter'
|
|
3
|
+
export type WaitForUiMatchArg = { index?: number }
|
|
4
|
+
export type WaitForUiRetryArg = { max_attempts?: number, backoff_ms?: number }
|
|
5
|
+
export type { ScrollSelector as ScrollSelectorArg } from '../../contracts/target.js'
|
|
6
|
+
export type ClassifyNetworkRequestArg = { endpoint: string, status: 'success' | 'failure' | 'retryable' }
|
|
7
|
+
export type { VerificationMode, ResponseMode } from '../../contracts/execution-controls.js'
|