mobile-debug-mcp 0.33.0 → 0.35.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/.github/copilot-instructions.md +14 -36
- package/.github/workflows/ci.yml +23 -2
- package/AGENTS.md +12 -3
- package/CONTRIBUTING.md +79 -0
- package/README.md +158 -124
- 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 +20 -6
- package/agent-plugin/mcp.json +1 -1
- package/agent-plugin/plugin.json +1 -1
- package/agent-plugin/skills/mobile-debug-mcp/SKILL.md +113 -4
- 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 +79 -0
- package/dist/debugger/diagnostics.js +54 -0
- package/dist/debugger/guard.js +30 -0
- package/dist/debugger/protocol.js +33 -0
- package/dist/debugger/sessions.js +304 -0
- package/dist/debugger/worker.js +176 -0
- 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 +65 -3074
- 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 +42 -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 +122 -76
- 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.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 +13 -2
- package/dist/observe/readiness.js +44 -18
- 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-android.js +135 -0
- package/dist/observe/system-trace.js +294 -0
- 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 +48 -0
- package/dist/server/handlers/debugger-response.js +9 -0
- package/dist/server/handlers/diagnostic.js +69 -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 +160 -0
- package/dist/server/schemas/condition-schema.js +2 -0
- package/dist/server/schemas/debugger-schema.js +47 -0
- package/dist/server/{journey-schema.js → schemas/journey-schema.js} +8 -22
- package/dist/server/schemas/system-trace-schema.js +17 -0
- package/dist/server/tool-definitions.js +62 -1134
- package/dist/server-core.js +4 -4
- package/dist/server.js +34 -0
- package/dist/system/android-status.js +101 -0
- package/dist/system/android.js +37 -27
- package/dist/system/index.js +13 -438
- 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/exec.js +2 -0
- package/dist/utils/ios/utils.js +45 -46
- package/dist/utils/java.js +75 -57
- package/dist/utils/operation-budget.js +2 -0
- package/dist/utils/resolve-device.js +6 -2
- package/dist/utils/ui/index.js +26 -26
- package/docs/CHANGELOG.md +48 -0
- package/docs/README.md +38 -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 +118 -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/device-evidence.json +38 -0
- package/docs/specs/023-android-system-traces/emulator-recheck.json +38 -0
- package/docs/specs/023-android-system-traces/intent.md +41 -0
- package/docs/specs/023-android-system-traces/plan.md +115 -0
- package/docs/specs/023-android-system-traces/spec.md +122 -0
- package/docs/specs/024-android-heap-dump-capture/intent.md +41 -0
- package/docs/specs/025-android-runtime-debugger/intent.md +41 -0
- package/docs/specs/025-android-runtime-debugger/plan.md +106 -0
- package/docs/specs/025-android-runtime-debugger/spec.md +183 -0
- 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/tools/TOOLS.md +31 -16
- package/docs/tools/{evidence.md → correlated-evidence.md} +14 -3
- package/docs/tools/debugger.md +180 -0
- package/docs/tools/interact.md +42 -20
- package/docs/tools/manage.md +25 -44
- package/docs/tools/observe.md +64 -25
- package/docs/tools/system-traces.md +134 -0
- package/docs/tools/system.md +12 -5
- package/package.json +11 -8
- 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 +66 -0
- package/src/debugger/diagnostics.ts +43 -0
- package/src/debugger/guard.ts +31 -0
- package/src/debugger/java/DebuggerWorker.java +166 -0
- package/src/debugger/protocol.ts +37 -0
- package/src/debugger/sessions.ts +327 -0
- package/src/debugger/worker.ts +135 -0
- 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 +76 -3491
- 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 +65 -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 +130 -71
- 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.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 +10 -3
- package/src/observe/readiness.ts +49 -22
- 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-android.ts +133 -0
- package/src/observe/system-trace.ts +227 -0
- 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 +39 -0
- package/src/server/handlers/debugger-response.ts +7 -0
- package/src/server/handlers/diagnostic.ts +79 -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 +159 -0
- package/src/server/schemas/condition-schema.ts +2 -0
- package/src/server/schemas/debugger-schema.ts +43 -0
- package/src/server/{journey-schema.ts → schemas/journey-schema.ts} +8 -22
- package/src/server/schemas/system-trace-schema.ts +17 -0
- package/src/server/tool-definitions.ts +69 -1140
- package/src/server-core.ts +4 -4
- package/src/server.ts +25 -1
- package/src/system/android-status.ts +124 -0
- package/src/system/android.ts +33 -21
- package/src/system/index.ts +21 -523
- 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/exec.ts +2 -0
- package/src/utils/ios/utils.ts +57 -61
- package/src/utils/java.ts +71 -51
- package/src/utils/operation-budget.ts +2 -0
- package/src/utils/resolve-device.ts +11 -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 +219 -0
- package/test/device/automated/interact/interaction.android.test.ts +56 -0
- package/test/device/automated/observe/system-trace.smoke.ts +104 -0
- package/test/device/manual/interact/modul8_selector_tap.manual.ts +1 -1
- package/test/fixtures/contracts/tool-definitions.json +3536 -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 +67 -0
- package/test/fixtures/debugger-app/MainActivity.kt +32 -0
- package/test/fixtures/debugger-app/NoLocals.java +7 -0
- package/test/fixtures/debugger-app/README.md +65 -0
- package/test/fixtures/debugger-app/build.ts +39 -0
- package/test/fixtures/latency-journey-app/README.md +2 -0
- package/test/fixtures/readiness-app/README.md +2 -0
- package/test/helpers/perfetto.ts +59 -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 +50 -0
- package/test/unit/debugger/native.test.ts +33 -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 +83 -0
- 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/readiness.test.ts +3 -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-android.test.ts +52 -0
- package/test/unit/observe/system-trace.test.ts +166 -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 +64 -0
- package/test/unit/server/tool_definitions_parity.test.ts +8 -0
- package/dist/server/tool-handlers.js +0 -893
- 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/tool-handlers.ts +0 -923
- /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,230 @@
|
|
|
1
|
+
import { promises as fs } from "fs"
|
|
2
|
+
import { spawn } from "child_process"
|
|
3
|
+
import { getIOSDeviceMetadata, findAppBundle } from "../../utils/ios/utils.js"
|
|
4
|
+
import path from "path"
|
|
5
|
+
import type { IOSBuildOptions, BuildEnv } from './build-types.js'
|
|
6
|
+
import { findProject } from './project-discovery.js'
|
|
7
|
+
import { detectScheme } from './scheme.js'
|
|
8
|
+
export async function buildIOS(projectPath: string, optsOrVariant?: string | IOSBuildOptions) {
|
|
9
|
+
|
|
10
|
+
// Support legacy variant string as second arg
|
|
11
|
+
const opts: IOSBuildOptions = typeof optsOrVariant === 'string' ? {} : (optsOrVariant || {})
|
|
12
|
+
const env = { ...process.env, ...(opts.env || {}) }
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
// Look for an Xcode workspace or project at the provided path. If not present, scan subdirectories (limited depth)
|
|
16
|
+
|
|
17
|
+
const project = await resolveBuildProject(projectPath, opts)
|
|
18
|
+
if ('error' in project) return project
|
|
19
|
+
const { projectRootDir } = project
|
|
20
|
+
const command = await prepareBuild(projectPath, opts, env, project)
|
|
21
|
+
const failure = await executeBuild(command, projectRootDir, env)
|
|
22
|
+
if (failure) return failure
|
|
23
|
+
// Try to locate built .app. First search project tree, then DerivedData if necessary
|
|
24
|
+
const built = await findAppBundle(projectPath)
|
|
25
|
+
if (built) return { artifactPath: built }
|
|
26
|
+
|
|
27
|
+
// Fallback: search DerivedData for matching product
|
|
28
|
+
const dd = path.join(process.env.HOME || '', 'Library', 'Developer', 'Xcode', 'DerivedData')
|
|
29
|
+
try {
|
|
30
|
+
const entries = await fs.readdir(dd).catch(() => [])
|
|
31
|
+
for (const e of entries) {
|
|
32
|
+
const candidate = path.join(dd, e)
|
|
33
|
+
const found = await findAppBundle(candidate).catch(() => undefined)
|
|
34
|
+
if (found) return { artifactPath: found }
|
|
35
|
+
}
|
|
36
|
+
} catch { }
|
|
37
|
+
|
|
38
|
+
return { error: 'Could not find .app after build' }
|
|
39
|
+
} catch (e) {
|
|
40
|
+
return { error: e instanceof Error ? e.message : String(e) }
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function resolveBuildProject(projectPath: string, opts: IOSBuildOptions): Promise<{ projectRootDir: string; workspace?: string; proj?: string } | { error: string }> {
|
|
46
|
+
// Resolve projectPath to an absolute path to avoid cwd-relative resolution issues
|
|
47
|
+
const absProjectPath = path.resolve(projectPath)
|
|
48
|
+
|
|
49
|
+
// If caller supplied explicit workspace/project, prefer those and set projectRootDir accordingly
|
|
50
|
+
let projectRootDir = absProjectPath
|
|
51
|
+
let workspace: string | undefined = opts.workspace
|
|
52
|
+
let proj: string | undefined = opts.project
|
|
53
|
+
|
|
54
|
+
if (workspace) {
|
|
55
|
+
// normalize workspace path and set root to its parent
|
|
56
|
+
workspace = path.isAbsolute(workspace) ? workspace : path.join(absProjectPath, workspace)
|
|
57
|
+
projectRootDir = path.dirname(workspace)
|
|
58
|
+
workspace = path.basename(workspace)
|
|
59
|
+
} else if (proj) {
|
|
60
|
+
proj = path.isAbsolute(proj) ? proj : path.join(absProjectPath, proj)
|
|
61
|
+
projectRootDir = path.dirname(proj)
|
|
62
|
+
proj = path.basename(proj)
|
|
63
|
+
} else {
|
|
64
|
+
const projectInfo = await findProject(absProjectPath, 4)
|
|
65
|
+
if (!projectInfo) return { error: 'No Xcode project or workspace found' }
|
|
66
|
+
projectRootDir = projectInfo.dir || absProjectPath
|
|
67
|
+
workspace = projectInfo.workspace
|
|
68
|
+
proj = projectInfo.proj
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return { projectRootDir, workspace, proj }
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async function prepareBuild(projectPath: string, opts: IOSBuildOptions, env: BuildEnv, project: { projectRootDir: string; workspace?: string; proj?: string }) {
|
|
75
|
+
const { projectRootDir, workspace, proj } = project
|
|
76
|
+
const destinationUDID = await destination(opts, env)
|
|
77
|
+
// Determine xcode command early so it can be used when detecting schemes
|
|
78
|
+
const xcodeCmd = opts.xcodeCmd || env.XCODEBUILD_PATH || 'xcodebuild'
|
|
79
|
+
|
|
80
|
+
// Determine available schemes by querying xcodebuild -list rather than guessing
|
|
81
|
+
|
|
82
|
+
// Prepare build flags and paths (support incremental builds)
|
|
83
|
+
let buildArgs: string[]
|
|
84
|
+
let chosenScheme: string | null = opts.scheme || null
|
|
85
|
+
|
|
86
|
+
// Derived data and result bundle (agent-configurable)
|
|
87
|
+
const derivedDataPath = opts.derivedDataPath || env.MCP_DERIVED_DATA || path.join(projectRootDir, 'build', 'DerivedData')
|
|
88
|
+
// Use unique result bundle path by default to avoid collisions
|
|
89
|
+
const resultBundlePath = env.MCP_XCODE_RESULTBUNDLE_PATH || path.join(projectRootDir, 'build', 'xcresults', `ResultBundle-${Date.now()}-${Math.random().toString(36).slice(2)}.xcresult`)
|
|
90
|
+
const xcodeJobs = typeof opts.buildJobs === 'number' ? opts.buildJobs : (parseInt(env.MCP_XCODE_JOBS || '', 10) || 4)
|
|
91
|
+
const forceClean = typeof opts.forceClean === 'boolean' ? opts.forceClean : env.MCP_FORCE_CLEAN === '1'
|
|
92
|
+
|
|
93
|
+
// ensure result dirs exist
|
|
94
|
+
await fs.mkdir(path.dirname(resultBundlePath), { recursive: true }).catch(() => { })
|
|
95
|
+
await fs.mkdir(derivedDataPath, { recursive: true }).catch(() => { })
|
|
96
|
+
// remove any pre-existing result bundle path to avoid xcodebuild complaining
|
|
97
|
+
await fs.rm(resultBundlePath, { recursive: true, force: true }).catch(() => { })
|
|
98
|
+
|
|
99
|
+
if (workspace) {
|
|
100
|
+
const workspacePath = path.join(projectRootDir, workspace)
|
|
101
|
+
if (!chosenScheme) chosenScheme = await detectScheme(projectRootDir, xcodeCmd, workspacePath, undefined, projectRootDir)
|
|
102
|
+
const scheme = chosenScheme || workspace.replace(/\.xcworkspace$/, '')
|
|
103
|
+
buildArgs = ['-workspace', workspacePath, '-scheme', scheme, '-configuration', 'Debug', '-sdk', 'iphonesimulator', 'build']
|
|
104
|
+
} else {
|
|
105
|
+
const projectPathFull = path.join(projectRootDir, proj!)
|
|
106
|
+
if (!chosenScheme) chosenScheme = await detectScheme(projectRootDir, xcodeCmd, undefined, projectPathFull, projectRootDir)
|
|
107
|
+
const scheme = chosenScheme || proj!.replace(/\.xcodeproj$/, '')
|
|
108
|
+
buildArgs = ['-project', projectPathFull, '-scheme', scheme, '-configuration', 'Debug', '-sdk', 'iphonesimulator', 'build']
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Insert clean if explicitly requested via env or opts
|
|
112
|
+
if (forceClean) {
|
|
113
|
+
const idx = buildArgs.indexOf('build')
|
|
114
|
+
if (idx >= 0) buildArgs.splice(idx, 0, 'clean')
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// If we have a destination UDID, add an explicit destination to avoid xcodebuild picking an ambiguous target
|
|
118
|
+
if (destinationUDID) {
|
|
119
|
+
buildArgs.push('-destination', `platform=iOS Simulator,id=${destinationUDID}`)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Add derived data and result bundle for diagnostics and faster incremental builds
|
|
123
|
+
buildArgs.push('-derivedDataPath', derivedDataPath)
|
|
124
|
+
buildArgs.push('-resultBundlePath', resultBundlePath)
|
|
125
|
+
// parallelisation and jobs
|
|
126
|
+
buildArgs.push('-parallelizeTargets')
|
|
127
|
+
buildArgs.push('-jobs', String(xcodeJobs))
|
|
128
|
+
|
|
129
|
+
// Prepare results directory for backwards-compatible logs
|
|
130
|
+
const resultsDir = path.join(projectPath, 'build-results')
|
|
131
|
+
// Remove any stale results to avoid xcodebuild complaining about existing result bundles
|
|
132
|
+
await fs.rm(resultsDir, { recursive: true, force: true }).catch(() => { })
|
|
133
|
+
await fs.mkdir(resultsDir, { recursive: true }).catch(() => { })
|
|
134
|
+
|
|
135
|
+
return { xcodeCmd, buildArgs, resultsDir }
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async function runAttempt(xcodeCmd: string, buildArgs: string[], projectRootDir: string, env: BuildEnv, timeoutMs: number) {
|
|
139
|
+
return new Promise<{ code: number | null, stdout: string, stderr: string, killedByWatchdog?: boolean }>((resolve) => {
|
|
140
|
+
const proc = spawn(xcodeCmd, buildArgs, { cwd: projectRootDir, env })
|
|
141
|
+
let stdout = ''
|
|
142
|
+
let stderr = ''
|
|
143
|
+
|
|
144
|
+
proc.stdout?.on('data', d => stdout += d.toString())
|
|
145
|
+
proc.stderr?.on('data', d => stderr += d.toString())
|
|
146
|
+
|
|
147
|
+
let killed = false
|
|
148
|
+
const to = setTimeout(() => {
|
|
149
|
+
killed = true
|
|
150
|
+
try { proc.kill('SIGKILL') } catch { }
|
|
151
|
+
}, timeoutMs)
|
|
152
|
+
|
|
153
|
+
proc.on('close', (code) => {
|
|
154
|
+
clearTimeout(to)
|
|
155
|
+
resolve({ code, stdout, stderr, killedByWatchdog: killed })
|
|
156
|
+
})
|
|
157
|
+
proc.on('error', (err) => {
|
|
158
|
+
clearTimeout(to)
|
|
159
|
+
resolve({ code: null, stdout, stderr: String(err), killedByWatchdog: killed })
|
|
160
|
+
})
|
|
161
|
+
})
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async function executeBuild(command: { xcodeCmd: string; buildArgs: string[]; resultsDir: string }, projectRootDir: string, env: BuildEnv) {
|
|
165
|
+
const { xcodeCmd, buildArgs, resultsDir } = command
|
|
166
|
+
const XCODEBUILD_TIMEOUT = parseInt(env.MCP_XCODEBUILD_TIMEOUT || '', 10) || 180000 // default 3 minutes
|
|
167
|
+
const MAX_RETRIES = parseInt(env.MCP_XCODEBUILD_RETRIES || '', 10) || 1
|
|
168
|
+
|
|
169
|
+
const tries = MAX_RETRIES + 1
|
|
170
|
+
let lastStdout = ''
|
|
171
|
+
let lastStderr = ''
|
|
172
|
+
let lastErr: (Error & { code?: number | null; exitCode?: number | null; killedByWatchdog?: boolean }) | null = null
|
|
173
|
+
|
|
174
|
+
for (let attempt = 1; attempt <= tries; attempt++) {
|
|
175
|
+
// Run xcodebuild with a watchdog
|
|
176
|
+
const res = await runAttempt(xcodeCmd, buildArgs, projectRootDir, env, XCODEBUILD_TIMEOUT)
|
|
177
|
+
|
|
178
|
+
lastStdout = res.stdout
|
|
179
|
+
lastStderr = res.stderr
|
|
180
|
+
|
|
181
|
+
if (res.code === 0) {
|
|
182
|
+
// success — clear any previous error and stop retrying
|
|
183
|
+
lastErr = null
|
|
184
|
+
break
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// record the failure for reporting
|
|
188
|
+
lastErr = new Error(res.stderr || `xcodebuild failed with code ${res.code}`)
|
|
189
|
+
// Attach exit code and watchdog info so diagnostics can include them
|
|
190
|
+
; lastErr.code = res.code
|
|
191
|
+
; lastErr.exitCode = res.code
|
|
192
|
+
; lastErr.killedByWatchdog = !!res.killedByWatchdog
|
|
193
|
+
|
|
194
|
+
// write logs for diagnostics (helpful whether killed or not)
|
|
195
|
+
try {
|
|
196
|
+
await fs.writeFile(path.join(resultsDir, `xcodebuild-${attempt}.stdout.log`), res.stdout).catch(() => { })
|
|
197
|
+
await fs.writeFile(path.join(resultsDir, `xcodebuild-${attempt}.stderr.log`), res.stderr).catch(() => { })
|
|
198
|
+
} catch { }
|
|
199
|
+
|
|
200
|
+
// If killed by watchdog and there are remaining attempts, continue to retry
|
|
201
|
+
if (res.killedByWatchdog && attempt < tries) {
|
|
202
|
+
continue
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// no more retries or not a watchdog kill — break to report lastErr
|
|
206
|
+
if (attempt >= tries) break
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (lastErr) {
|
|
210
|
+
// Include diagnostics and result bundle path when available; provide structured info useful for agents
|
|
211
|
+
const invokedCommand = `${xcodeCmd} ${buildArgs.map(a => a.includes(' ') ? `"${a}"` : a).join(' ')}`
|
|
212
|
+
const envSnapshot = { PATH: env.PATH }
|
|
213
|
+
return { error: `xcodebuild failed: ${lastErr.message}. See build-results for logs.`, output: `stdout:\n${lastStdout}\nstderr:\n${lastStderr}`, diagnostics: { exitCode: lastErr.code || null, invokedCommand, cwd: projectRootDir, envSnapshot } }
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return null
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
async function destination(opts: IOSBuildOptions, env: BuildEnv) {
|
|
220
|
+
// Determine destination: prefer explicit option, then env var, otherwise use booted simulator UDID
|
|
221
|
+
let destinationUDID = opts.destinationUDID || env.MCP_XCODE_DESTINATION_UDID || env.MCP_XCODE_DESTINATION || ''
|
|
222
|
+
if (!destinationUDID) {
|
|
223
|
+
try {
|
|
224
|
+
const meta = await getIOSDeviceMetadata('booted')
|
|
225
|
+
if (meta && meta.id) destinationUDID = meta.id
|
|
226
|
+
} catch { }
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return destinationUDID
|
|
230
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { promises as fs } from "fs"
|
|
2
|
+
import path from "path"
|
|
3
|
+
export async function findProject(root: string, maxDepth = 4): Promise<{ dir: string, workspace?: string, proj?: string } | null> {
|
|
4
|
+
try {
|
|
5
|
+
const ents = await fs.readdir(root, { withFileTypes: true }).catch(() => [])
|
|
6
|
+
for (const e of ents) {
|
|
7
|
+
// .xcworkspace and .xcodeproj are directories on disk (bundles), not regular files
|
|
8
|
+
if (e.name.endsWith('.xcworkspace')) return { dir: root, workspace: e.name }
|
|
9
|
+
if (e.name.endsWith('.xcodeproj')) return { dir: root, proj: e.name }
|
|
10
|
+
}
|
|
11
|
+
} catch { }
|
|
12
|
+
|
|
13
|
+
if (maxDepth <= 0) return null
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
const ents = await fs.readdir(root, { withFileTypes: true }).catch(() => [])
|
|
17
|
+
for (const e of ents) {
|
|
18
|
+
if (e.isDirectory()) {
|
|
19
|
+
const candidate = await findProject(path.join(root, e.name), maxDepth - 1)
|
|
20
|
+
if (candidate) return candidate
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
} catch { }
|
|
24
|
+
|
|
25
|
+
return null
|
|
26
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { spawnSync } from "child_process"
|
|
2
|
+
export async function detectScheme(projectRootDir: string, xcodeCmdInner: string, workspacePath?: string, projectPathFull?: string, cwd?: string): Promise<string | null> {
|
|
3
|
+
try {
|
|
4
|
+
const args = workspacePath ? ['-list', '-workspace', workspacePath] : ['-list', '-project', projectPathFull!]
|
|
5
|
+
// Run xcodebuild directly to list schemes
|
|
6
|
+
const res = spawnSync(xcodeCmdInner, args, { cwd: cwd || projectRootDir, encoding: 'utf8', timeout: 20000 })
|
|
7
|
+
const out = res.stdout || ''
|
|
8
|
+
const schemesMatch = out.match(/Schemes:\s*\n([\s\S]*?)(?:\n\n|$)/m)
|
|
9
|
+
if (schemesMatch) {
|
|
10
|
+
const block = schemesMatch[1]
|
|
11
|
+
const schemes = block.split(/\n/).map(s => s.trim()).filter(Boolean)
|
|
12
|
+
if (schemes.length) return schemes[0]
|
|
13
|
+
}
|
|
14
|
+
} catch { }
|
|
15
|
+
return null
|
|
16
|
+
}
|