swipium 1.4.0 → 2.0.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/CHANGELOG.md +313 -0
- package/README.md +175 -219
- package/THREAT_MODEL.md +223 -47
- package/dist/appMap/automationLink.js +39 -26
- package/dist/appMap/automationLink.js.map +1 -1
- package/dist/appMap/build.js +68 -20
- package/dist/appMap/build.js.map +1 -1
- package/dist/appMap/codeIndex.js +31 -5
- package/dist/appMap/codeIndex.js.map +1 -1
- package/dist/appMap/featureIndex.js +23 -5
- package/dist/appMap/featureIndex.js.map +1 -1
- package/dist/appMap/featureModel.js +44 -8
- package/dist/appMap/featureModel.js.map +1 -1
- package/dist/appMap/firstRunApply.js +24 -6
- package/dist/appMap/firstRunApply.js.map +1 -1
- package/dist/appMap/fsWalk.js +19 -2
- package/dist/appMap/fsWalk.js.map +1 -1
- package/dist/appMap/issues.js +10 -30
- package/dist/appMap/issues.js.map +1 -1
- package/dist/appMap/migrations.js +6 -6
- package/dist/appMap/migrations.js.map +1 -1
- package/dist/appMap/prelaunch.js +2 -2
- package/dist/appMap/prelaunch.js.map +1 -1
- package/dist/appMap/projectRegistry.js +83 -11
- package/dist/appMap/projectRegistry.js.map +1 -1
- package/dist/appMap/provenance.js +2 -2
- package/dist/appMap/provenance.js.map +1 -1
- package/dist/appMap/query.js +21 -5
- package/dist/appMap/query.js.map +1 -1
- package/dist/appMap/runtimeMerge.js +12 -5
- package/dist/appMap/runtimeMerge.js.map +1 -1
- package/dist/appMap/schema.js +1 -1
- package/dist/appMap/schema.js.map +1 -1
- package/dist/appMap/screenMatch.js +6 -2
- package/dist/appMap/screenMatch.js.map +1 -1
- package/dist/appMap/staticScan.js +151 -39
- package/dist/appMap/staticScan.js.map +1 -1
- package/dist/appMap/store.js +58 -85
- package/dist/appMap/store.js.map +1 -1
- package/dist/appMap/tsAstScan.js +34 -12
- package/dist/appMap/tsAstScan.js.map +1 -1
- package/dist/artifacts/bundletool.js +49 -12
- package/dist/artifacts/bundletool.js.map +1 -1
- package/dist/artifacts/resolve.js +41 -14
- package/dist/artifacts/resolve.js.map +1 -1
- package/dist/automation/capabilities.js +112 -30
- package/dist/automation/capabilities.js.map +1 -1
- package/dist/automation/gestures.js +6 -2
- package/dist/automation/gestures.js.map +1 -1
- package/dist/automation/plan.js +71 -23
- package/dist/automation/plan.js.map +1 -1
- package/dist/automation/report.js +15 -5
- package/dist/automation/report.js.map +1 -1
- package/dist/automation/selectors.js +22 -28
- package/dist/automation/selectors.js.map +1 -1
- package/dist/automation/types.js +1 -1
- package/dist/automation/types.js.map +1 -1
- package/dist/automation/waits.js +14 -8
- package/dist/automation/waits.js.map +1 -1
- package/dist/automation/webview.js +9 -3
- package/dist/automation/webview.js.map +1 -1
- package/dist/automationGen/appiumModel.js +16 -8
- package/dist/automationGen/appiumModel.js.map +1 -1
- package/dist/automationGen/ciEmitter.js +6 -6
- package/dist/automationGen/ciEmitter.js.map +1 -1
- package/dist/automationGen/identifiers.js +224 -0
- package/dist/automationGen/identifiers.js.map +1 -0
- package/dist/automationGen/jsEmitter.js +288 -121
- package/dist/automationGen/jsEmitter.js.map +1 -1
- package/dist/automationGen/packagePatch.js +2 -2
- package/dist/automationGen/packagePatch.js.map +1 -1
- package/dist/automationGen/platformResolve.js +36 -0
- package/dist/automationGen/platformResolve.js.map +1 -0
- package/dist/automationGen/projectProfile.js +76 -27
- package/dist/automationGen/projectProfile.js.map +1 -1
- package/dist/automationGen/pythonEmitter.js +278 -107
- package/dist/automationGen/pythonEmitter.js.map +1 -1
- package/dist/automationGen/readmeEmitter.js +7 -6
- package/dist/automationGen/readmeEmitter.js.map +1 -1
- package/dist/automationGen/run.js +388 -0
- package/dist/automationGen/run.js.map +1 -0
- package/dist/automationGen/suitePlan.js +17 -10
- package/dist/automationGen/suitePlan.js.map +1 -1
- package/dist/automationGen/validation.js +52 -12
- package/dist/automationGen/validation.js.map +1 -1
- package/dist/build/parseBuildLog.js +235 -31
- package/dist/build/parseBuildLog.js.map +1 -1
- package/dist/build/plan.js +39 -18
- package/dist/build/plan.js.map +1 -1
- package/dist/ci/preflight.js +13 -4
- package/dist/ci/preflight.js.map +1 -1
- package/dist/cli/gc.js +74 -0
- package/dist/cli/gc.js.map +1 -0
- package/dist/cli/init.js +217 -26
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/main.js +50 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/report.js +218 -0
- package/dist/cli/report.js.map +1 -0
- package/dist/cli/scan.js +36 -15
- package/dist/cli/scan.js.map +1 -1
- package/dist/cli/suite.js +7 -7
- package/dist/cli/suite.js.map +1 -1
- package/dist/cli/verify.js +7 -7
- package/dist/cli/verify.js.map +1 -1
- package/dist/consent/consent.js +162 -5
- package/dist/consent/consent.js.map +1 -1
- package/dist/context/detect.js +55 -18
- package/dist/context/detect.js.map +1 -1
- package/dist/context/findApps.js +22 -8
- package/dist/context/findApps.js.map +1 -1
- package/dist/context/projectRoot.js +174 -19
- package/dist/context/projectRoot.js.map +1 -1
- package/dist/context/scan.js +1 -1
- package/dist/context/scan.js.map +1 -1
- package/dist/core/capabilityGroups.js +90 -0
- package/dist/core/capabilityGroups.js.map +1 -0
- package/dist/core/target.js +10 -8
- package/dist/core/target.js.map +1 -1
- package/dist/core/targetPlan.js +160 -39
- package/dist/core/targetPlan.js.map +1 -1
- package/dist/drivers/DirectDriver.js +317 -43
- package/dist/drivers/DirectDriver.js.map +1 -1
- package/dist/drivers/SimctlDriver.js +124 -8
- package/dist/drivers/SimctlDriver.js.map +1 -1
- package/dist/drivers/WdaDriver.js +365 -55
- package/dist/drivers/WdaDriver.js.map +1 -1
- package/dist/explore/candidates.js +7 -3
- package/dist/explore/candidates.js.map +1 -1
- package/dist/explore/graph.js +15 -6
- package/dist/explore/graph.js.map +1 -1
- package/dist/explore/memory.js +4 -1
- package/dist/explore/memory.js.map +1 -1
- package/dist/explore/planner.js +54 -9
- package/dist/explore/planner.js.map +1 -1
- package/dist/explore/policy.js +11 -6
- package/dist/explore/policy.js.map +1 -1
- package/dist/explore/runner.js +363 -190
- package/dist/explore/runner.js.map +1 -1
- package/dist/explore/signatures.js +4 -2
- package/dist/explore/signatures.js.map +1 -1
- package/dist/explore/suite.js +3 -1
- package/dist/explore/suite.js.map +1 -1
- package/dist/featureTesting/executionBootstrap.js +137 -29
- package/dist/featureTesting/executionBootstrap.js.map +1 -1
- package/dist/featureTesting/featureMap.js +6 -3
- package/dist/featureTesting/featureMap.js.map +1 -1
- package/dist/featureTesting/featureScope.js +101 -20
- package/dist/featureTesting/featureScope.js.map +1 -1
- package/dist/featureTesting/mapFeatureScope.js +44 -15
- package/dist/featureTesting/mapFeatureScope.js.map +1 -1
- package/dist/featureTesting/objectiveModel.js +15 -11
- package/dist/featureTesting/objectiveModel.js.map +1 -1
- package/dist/featureTesting/resultMerge.js +16 -8
- package/dist/featureTesting/resultMerge.js.map +1 -1
- package/dist/featureTesting/sources.js +8 -5
- package/dist/featureTesting/sources.js.map +1 -1
- package/dist/featureTesting/suiteBridge.js +8 -2
- package/dist/featureTesting/suiteBridge.js.map +1 -1
- package/dist/featureTesting/synonyms.js +32 -4
- package/dist/featureTesting/synonyms.js.map +1 -1
- package/dist/featureTesting/testCaseFactory.js +27 -15
- package/dist/featureTesting/testCaseFactory.js.map +1 -1
- package/dist/featureTesting/testPlan.js +34 -12
- package/dist/featureTesting/testPlan.js.map +1 -1
- package/dist/firstRun/authStateMachine.js +1 -1
- package/dist/firstRun/authStateMachine.js.map +1 -1
- package/dist/firstRun/classifyScreen.js +9 -6
- package/dist/firstRun/classifyScreen.js.map +1 -1
- package/dist/firstRun/firstRunPlanner.js +16 -13
- package/dist/firstRun/firstRunPlanner.js.map +1 -1
- package/dist/firstRun/firstRunRunner.js +92 -31
- package/dist/firstRun/firstRunRunner.js.map +1 -1
- package/dist/firstRun/generatedDataPolicy.js +25 -15
- package/dist/firstRun/generatedDataPolicy.js.map +1 -1
- package/dist/firstRun/inputPlanner.js +45 -11
- package/dist/firstRun/inputPlanner.js.map +1 -1
- package/dist/firstRun/onboardingStateMachine.js +1 -1
- package/dist/firstRun/onboardingStateMachine.js.map +1 -1
- package/dist/firstRun/paywallPolicy.js +3 -3
- package/dist/firstRun/paywallPolicy.js.map +1 -1
- package/dist/firstRun/types.js +1 -1
- package/dist/firstRun/types.js.map +1 -1
- package/dist/fixtures/catalog.js +72 -9
- package/dist/fixtures/catalog.js.map +1 -1
- package/dist/fixtures/load.js +50 -0
- package/dist/fixtures/load.js.map +1 -0
- package/dist/flows/discover.js +2 -2
- package/dist/flows/discover.js.map +1 -1
- package/dist/flows/generate.js +68 -17
- package/dist/flows/generate.js.map +1 -1
- package/dist/flows/lint.js +88 -14
- package/dist/flows/lint.js.map +1 -1
- package/dist/flows/pack.js +21 -5
- package/dist/flows/pack.js.map +1 -1
- package/dist/flows/paths.js +57 -0
- package/dist/flows/paths.js.map +1 -0
- package/dist/flows/repair.js +176 -37
- package/dist/flows/repair.js.map +1 -1
- package/dist/flows/run.js +308 -99
- package/dist/flows/run.js.map +1 -1
- package/dist/flows/schema.js +107 -25
- package/dist/flows/schema.js.map +1 -1
- package/dist/flows/seedExec.js +8 -4
- package/dist/flows/seedExec.js.map +1 -1
- package/dist/flows/templates.js +5 -5
- package/dist/index.js +50 -8
- package/dist/index.js.map +1 -1
- package/dist/ios/signing.js +32 -3
- package/dist/ios/signing.js.map +1 -1
- package/dist/issues/classify.js +28 -20
- package/dist/issues/classify.js.map +1 -1
- package/dist/issues/fingerprint.js +35 -9
- package/dist/issues/fingerprint.js.map +1 -1
- package/dist/issues/index.js +93 -46
- package/dist/issues/index.js.map +1 -1
- package/dist/issues/metrics.js +6 -5
- package/dist/issues/metrics.js.map +1 -1
- package/dist/issues/recurrence.js +35 -8
- package/dist/issues/recurrence.js.map +1 -1
- package/dist/issues/report.js +12 -8
- package/dist/issues/report.js.map +1 -1
- package/dist/issues/reportBridge.js +40 -9
- package/dist/issues/reportBridge.js.map +1 -1
- package/dist/issues/schema.js +2 -2
- package/dist/issues/schema.js.map +1 -1
- package/dist/issues/sourceRevision.js +2 -2
- package/dist/issues/sourceRevision.js.map +1 -1
- package/dist/issues/store.js +110 -32
- package/dist/issues/store.js.map +1 -1
- package/dist/lib/abortScope.js +48 -0
- package/dist/lib/abortScope.js.map +1 -0
- package/dist/lib/android.js +84 -8
- package/dist/lib/android.js.map +1 -1
- package/dist/lib/coordSpace.js +1 -1
- package/dist/lib/coordSpace.js.map +1 -1
- package/dist/lib/device.js +53 -12
- package/dist/lib/device.js.map +1 -1
- package/dist/lib/gestures.js +141 -0
- package/dist/lib/gestures.js.map +1 -0
- package/dist/lib/gitignore.js +4 -3
- package/dist/lib/gitignore.js.map +1 -1
- package/dist/lib/image.js +12 -3
- package/dist/lib/image.js.map +1 -1
- package/dist/lib/lockfile.js +399 -0
- package/dist/lib/lockfile.js.map +1 -0
- package/dist/lib/needsInput.js +9 -6
- package/dist/lib/needsInput.js.map +1 -1
- package/dist/lib/png.js +4 -3
- package/dist/lib/png.js.map +1 -1
- package/dist/lib/redact.js +170 -9
- package/dist/lib/redact.js.map +1 -1
- package/dist/lib/result.js +94 -10
- package/dist/lib/result.js.map +1 -1
- package/dist/lib/schemaHash.js +7 -5
- package/dist/lib/schemaHash.js.map +1 -1
- package/dist/lib/sensitive.js +6 -3
- package/dist/lib/sensitive.js.map +1 -1
- package/dist/lib/simctl.js +3 -3
- package/dist/lib/simctl.js.map +1 -1
- package/dist/lib/spawn.js +78 -17
- package/dist/lib/spawn.js.map +1 -1
- package/dist/lib/toolAnnotations.js +114 -0
- package/dist/lib/toolAnnotations.js.map +1 -0
- package/dist/lib/wda.js +321 -25
- package/dist/lib/wda.js.map +1 -1
- package/dist/lib/wdaConfig.js +12 -5
- package/dist/lib/wdaConfig.js.map +1 -1
- package/dist/lib/wdaTune.js +52 -23
- package/dist/lib/wdaTune.js.map +1 -1
- package/dist/mobileAudit/checks.js +150 -28
- package/dist/mobileAudit/checks.js.map +1 -1
- package/dist/mobileAudit/evidence.js +4 -4
- package/dist/mobileAudit/evidence.js.map +1 -1
- package/dist/mobileAudit/profiles.js +121 -20
- package/dist/mobileAudit/profiles.js.map +1 -1
- package/dist/mobileAudit/results.js +9 -4
- package/dist/mobileAudit/results.js.map +1 -1
- package/dist/mobileAudit/runner.js +214 -35
- package/dist/mobileAudit/runner.js.map +1 -1
- package/dist/oracle/auth.js +1 -1
- package/dist/oracle/auth.js.map +1 -1
- package/dist/oracle/failures.js +1085 -145
- package/dist/oracle/failures.js.map +1 -1
- package/dist/oracle/health.js +148 -26
- package/dist/oracle/health.js.map +1 -1
- package/dist/oracle/locator.js +148 -19
- package/dist/oracle/locator.js.map +1 -1
- package/dist/oracle/record.js +3 -3
- package/dist/oracle/record.js.map +1 -1
- package/dist/orchestration/envelope.js +2 -2
- package/dist/orchestration/envelope.js.map +1 -1
- package/dist/orchestration/goal.js +7 -13
- package/dist/orchestration/goal.js.map +1 -1
- package/dist/orchestration/testThis/execute.js +167 -0
- package/dist/orchestration/testThis/execute.js.map +1 -0
- package/dist/orchestration/testThis/pipeline.js +413 -0
- package/dist/orchestration/testThis/pipeline.js.map +1 -0
- package/dist/orchestration/testThis/plan.js +519 -0
- package/dist/orchestration/testThis/plan.js.map +1 -0
- package/dist/orchestration/testThis/sessionIntent.js +72 -0
- package/dist/orchestration/testThis/sessionIntent.js.map +1 -0
- package/dist/orchestration/testThis/terminal.js +136 -0
- package/dist/orchestration/testThis/terminal.js.map +1 -0
- package/dist/orchestration/testThis/types.js +12 -0
- package/dist/orchestration/testThis/types.js.map +1 -0
- package/dist/plan/plan.js +9 -9
- package/dist/plan/plan.js.map +1 -1
- package/dist/prompts/index.js +24 -24
- package/dist/prompts/index.js.map +1 -1
- package/dist/report/coverage.js +0 -1
- package/dist/report/coverage.js.map +1 -1
- package/dist/report/evidence.js.map +1 -1
- package/dist/report/export.js +449 -72
- package/dist/report/export.js.map +1 -1
- package/dist/report/findingsDedupe.js +41 -0
- package/dist/report/findingsDedupe.js.map +1 -0
- package/dist/report/flake.js +13 -14
- package/dist/report/flake.js.map +1 -1
- package/dist/report/history.js +72 -38
- package/dist/report/history.js.map +1 -1
- package/dist/report/policy.js +18 -7
- package/dist/report/policy.js.map +1 -1
- package/dist/report/qaLevel.js +10 -16
- package/dist/report/qaLevel.js.map +1 -1
- package/dist/report/readiness.js +42 -12
- package/dist/report/readiness.js.map +1 -1
- package/dist/report/sarifSources.js +160 -0
- package/dist/report/sarifSources.js.map +1 -0
- package/dist/report/summary.js +2 -2
- package/dist/report/summary.js.map +1 -1
- package/dist/report/testCatalog.js +4 -4
- package/dist/report/testCatalog.js.map +1 -1
- package/dist/report/timing.js +23 -23
- package/dist/report/timing.js.map +1 -1
- package/dist/report/toolHealth.js +124 -0
- package/dist/report/toolHealth.js.map +1 -0
- package/dist/server.js +501 -69
- package/dist/server.js.map +1 -1
- package/dist/services/automationGenerate.js +8 -2
- package/dist/services/automationGenerate.js.map +1 -1
- package/dist/services/build.js +10 -4
- package/dist/services/build.js.map +1 -1
- package/dist/services/flowGenerate.js +75 -0
- package/dist/services/flowGenerate.js.map +1 -0
- package/dist/services/preflight.js +40 -8
- package/dist/services/preflight.js.map +1 -1
- package/dist/services/prepareAndroid.js +92 -18
- package/dist/services/prepareAndroid.js.map +1 -1
- package/dist/services/prepareIos.js +94 -17
- package/dist/services/prepareIos.js.map +1 -1
- package/dist/services/report.js +271 -80
- package/dist/services/report.js.map +1 -1
- package/dist/services/smoke.js +68 -22
- package/dist/services/smoke.js.map +1 -1
- package/dist/services/suiteGenerate.js +43 -6
- package/dist/services/suiteGenerate.js.map +1 -1
- package/dist/services/testSuiteKnowledge.js +78 -33
- package/dist/services/testSuiteKnowledge.js.map +1 -1
- package/dist/session/attach.js +284 -4
- package/dist/session/attach.js.map +1 -1
- package/dist/session/processRegistry.js +433 -0
- package/dist/session/processRegistry.js.map +1 -0
- package/dist/session/progress.js +1 -1
- package/dist/session/progress.js.map +1 -1
- package/dist/session/retention.js +201 -0
- package/dist/session/retention.js.map +1 -0
- package/dist/session/store.js +459 -59
- package/dist/session/store.js.map +1 -1
- package/dist/snapshot/overlays.js +60 -10
- package/dist/snapshot/overlays.js.map +1 -1
- package/dist/snapshot/parse.js +30 -12
- package/dist/snapshot/parse.js.map +1 -1
- package/dist/snapshot/present.js +36 -6
- package/dist/snapshot/present.js.map +1 -1
- package/dist/snapshot/settle.js +39 -9
- package/dist/snapshot/settle.js.map +1 -1
- package/dist/state/consent.js +99 -0
- package/dist/state/consent.js.map +1 -0
- package/dist/state/profile.js +82 -11
- package/dist/state/profile.js.map +1 -1
- package/dist/suite/compile.js +15 -6
- package/dist/suite/compile.js.map +1 -1
- package/dist/suite/lint.js +22 -4
- package/dist/suite/lint.js.map +1 -1
- package/dist/suite/pom.js +75 -44
- package/dist/suite/pom.js.map +1 -1
- package/dist/suite/secretGuard.js +266 -0
- package/dist/suite/secretGuard.js.map +1 -0
- package/dist/suite/testcase.js +15 -11
- package/dist/suite/testcase.js.map +1 -1
- package/dist/testSuite/exporter.js +7 -3
- package/dist/testSuite/exporter.js.map +1 -1
- package/dist/testSuite/generator.js +43 -14
- package/dist/testSuite/generator.js.map +1 -1
- package/dist/testSuite/history.js +1 -1
- package/dist/testSuite/history.js.map +1 -1
- package/dist/testSuite/issueLinks.js +3 -3
- package/dist/testSuite/issueLinks.js.map +1 -1
- package/dist/testSuite/lint.js +4 -4
- package/dist/testSuite/lint.js.map +1 -1
- package/dist/testSuite/merge.js +13 -7
- package/dist/testSuite/merge.js.map +1 -1
- package/dist/testSuite/schema.js +21 -16
- package/dist/testSuite/schema.js.map +1 -1
- package/dist/testSuite/store.js +12 -4
- package/dist/testSuite/store.js.map +1 -1
- package/dist/testSuite/traceability.js +2 -2
- package/dist/testSuite/traceability.js.map +1 -1
- package/dist/tools/act.js +868 -174
- package/dist/tools/act.js.map +1 -1
- package/dist/tools/agent.js +521 -112
- package/dist/tools/agent.js.map +1 -1
- package/dist/tools/appControl.js +82 -19
- package/dist/tools/appControl.js.map +1 -1
- package/dist/tools/appMap.js +393 -189
- package/dist/tools/appMap.js.map +1 -1
- package/dist/tools/build.js +92 -51
- package/dist/tools/build.js.map +1 -1
- package/dist/tools/bundletool.js +141 -40
- package/dist/tools/bundletool.js.map +1 -1
- package/dist/tools/clearOverlay.js +98 -18
- package/dist/tools/clearOverlay.js.map +1 -1
- package/dist/tools/device.js +108 -19
- package/dist/tools/device.js.map +1 -1
- package/dist/tools/doctor.js +98 -35
- package/dist/tools/doctor.js.map +1 -1
- package/dist/tools/explore.js +110 -42
- package/dist/tools/explore.js.map +1 -1
- package/dist/tools/featureTesting.js +152 -130
- package/dist/tools/featureTesting.js.map +1 -1
- package/dist/tools/firstRun.js +94 -66
- package/dist/tools/firstRun.js.map +1 -1
- package/dist/tools/flow.js +347 -132
- package/dist/tools/flow.js.map +1 -1
- package/dist/tools/flowRepair.js +42 -10
- package/dist/tools/flowRepair.js.map +1 -1
- package/dist/tools/generate.js +199 -0
- package/dist/tools/generate.js.map +1 -0
- package/dist/tools/getArtifact.js +37 -8
- package/dist/tools/getArtifact.js.map +1 -1
- package/dist/tools/health.js +17 -12
- package/dist/tools/health.js.map +1 -1
- package/dist/tools/ios.js +148 -194
- package/dist/tools/ios.js.map +1 -1
- package/dist/tools/issues.js +256 -171
- package/dist/tools/issues.js.map +1 -1
- package/dist/tools/jobs.js +55 -11
- package/dist/tools/jobs.js.map +1 -1
- package/dist/tools/metro.js +84 -38
- package/dist/tools/metro.js.map +1 -1
- package/dist/tools/mobileAudit.js +83 -26
- package/dist/tools/mobileAudit.js.map +1 -1
- package/dist/tools/network.js +36 -14
- package/dist/tools/network.js.map +1 -1
- package/dist/tools/note.js +31 -17
- package/dist/tools/note.js.map +1 -1
- package/dist/tools/prepareIosTarget.js +31 -14
- package/dist/tools/prepareIosTarget.js.map +1 -1
- package/dist/tools/prepareTarget.js +193 -47
- package/dist/tools/prepareTarget.js.map +1 -1
- package/dist/tools/report.js +16 -8
- package/dist/tools/report.js.map +1 -1
- package/dist/tools/resolveArtifact.js +12 -12
- package/dist/tools/resolveArtifact.js.map +1 -1
- package/dist/tools/resolveTarget.js +81 -18
- package/dist/tools/resolveTarget.js.map +1 -1
- package/dist/tools/screenRecord.js +85 -20
- package/dist/tools/screenRecord.js.map +1 -1
- package/dist/tools/screenshot.js +42 -18
- package/dist/tools/screenshot.js.map +1 -1
- package/dist/tools/smoke.js +29 -12
- package/dist/tools/smoke.js.map +1 -1
- package/dist/tools/snapshot.js +157 -107
- package/dist/tools/snapshot.js.map +1 -1
- package/dist/tools/startSession.js +117 -84
- package/dist/tools/startSession.js.map +1 -1
- package/dist/tools/suite.js +391 -310
- package/dist/tools/suite.js.map +1 -1
- package/dist/tools/testSuite.js +112 -36
- package/dist/tools/testSuite.js.map +1 -1
- package/dist/tools/testThis.js +35 -802
- package/dist/tools/testThis.js.map +1 -1
- package/dist/tools/visual.js +698 -116
- package/dist/tools/visual.js.map +1 -1
- package/dist/tools/wait.js +9 -23
- package/dist/tools/wait.js.map +1 -1
- package/dist/tools/wda.js +312 -54
- package/dist/tools/wda.js.map +1 -1
- package/dist/version.js +37 -64
- package/dist/version.js.map +1 -1
- package/dist/visual/ocr.js +65 -8
- package/dist/visual/ocr.js.map +1 -1
- package/dist/visual/provider.js +87 -15
- package/dist/visual/provider.js.map +1 -1
- package/docs/README.md +24 -10
- package/docs/ci-reports.md +328 -0
- package/docs/concepts.md +227 -0
- package/docs/flows.md +153 -0
- package/docs/mcp-server.md +210 -104
- package/docs/physical-devices.md +84 -0
- package/docs/tools.md +808 -217
- package/package.json +16 -6
- package/dist/appMap/diff.js +0 -60
- package/dist/appMap/diff.js.map +0 -1
- package/dist/automation/maestroIr.js +0 -282
- package/dist/automation/maestroIr.js.map +0 -1
- package/dist/interop/maestro.js +0 -151
- package/dist/interop/maestro.js.map +0 -1
- package/dist/tools/assertVisual.js +0 -74
- package/dist/tools/assertVisual.js.map +0 -1
- package/dist/tools/automationGenerate.js +0 -394
- package/dist/tools/automationGenerate.js.map +0 -1
- package/dist/tools/capabilities.js +0 -209
- package/dist/tools/capabilities.js.map +0 -1
- package/dist/tools/detectContext.js +0 -41
- package/dist/tools/detectContext.js.map +0 -1
- package/dist/tools/flowGenerate.js +0 -55
- package/dist/tools/flowGenerate.js.map +0 -1
- package/dist/tools/history.js +0 -56
- package/dist/tools/history.js.map +0 -1
- package/dist/tools/idling.js +0 -104
- package/dist/tools/idling.js.map +0 -1
- package/dist/tools/inputCapabilities.js +0 -30
- package/dist/tools/inputCapabilities.js.map +0 -1
- package/dist/tools/locator.js +0 -57
- package/dist/tools/locator.js.map +0 -1
- package/dist/tools/maestro.js +0 -78
- package/dist/tools/maestro.js.map +0 -1
- package/dist/tools/permissions.js +0 -149
- package/dist/tools/permissions.js.map +0 -1
- package/dist/tools/plan.js +0 -49
- package/dist/tools/plan.js.map +0 -1
- package/dist/tools/screenInfo.js +0 -70
- package/dist/tools/screenInfo.js.map +0 -1
- package/dist/tools/seed.js +0 -101
- package/dist/tools/seed.js.map +0 -1
- package/dist/tools/state.js +0 -170
- package/dist/tools/state.js.map +0 -1
- package/dist/tools/visualText.js +0 -61
- package/dist/tools/visualText.js.map +0 -1
package/dist/tools/wda.js
CHANGED
|
@@ -1,26 +1,70 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { spawn } from 'node:child_process';
|
|
3
|
-
import { existsSync, openSync, readFileSync, readdirSync, statSync } from 'node:fs';
|
|
3
|
+
import { closeSync, existsSync, openSync, readFileSync, readdirSync, statSync } from 'node:fs';
|
|
4
4
|
import { isAbsolute, join } from 'node:path';
|
|
5
|
-
import { qaError, qaOk } from '../lib/result.js';
|
|
5
|
+
import { qaError, qaOk, unknownSessionError } from '../lib/result.js';
|
|
6
6
|
import { consumeConsent, requireConsent } from '../consent/consent.js';
|
|
7
7
|
import { sensitiveRefusal } from '../lib/sensitive.js';
|
|
8
8
|
import { run } from '../lib/spawn.js';
|
|
9
|
-
import { checkWda, classifyWdaBuildFailure, classifyWdaConnectionFailure, createWdaSession, discoverWdaProjects, managedWdaBuildArgs, managedWdaStartArgs, waitForWdaReady, wdaSessionUdidMismatch, xcodeAvailable } from '../lib/wda.js';
|
|
9
|
+
import { checkWda, classifyWdaBuildFailure, classifyWdaConnectionFailure, createWdaSession, discoverAppiumWdaProjects, discoverWdaProjects, managedWdaBuildArgs, managedWdaStartArgs, waitForWdaReady, wdaSessionUdidMismatch, xcodeAvailable, isLoopbackWdaUrl, remoteWdaAllowedByUser, REMOTE_WDA_ENV, } from '../lib/wda.js';
|
|
10
10
|
import { loadWdaConfig, wdaSigningStatus, wdaUrlAllowedByConfig } from '../lib/wdaConfig.js';
|
|
11
11
|
import { recordWdaTiming, wdaRecommendations, wdaTimingSummary } from '../lib/wdaTune.js';
|
|
12
12
|
import { WdaDriver } from '../drivers/WdaDriver.js';
|
|
13
13
|
import * as sim from '../lib/simctl.js';
|
|
14
|
+
import { findManagedWdaProcesses, killManagedWda, reclaimPid, registerManagedProcess, registeredWdaForSession, unregisterManagedProcess, } from '../session/processRegistry.js';
|
|
14
15
|
const managedProcesses = new Map();
|
|
15
|
-
function
|
|
16
|
+
function pidIsAlive(pid) {
|
|
17
|
+
if (!(pid > 0))
|
|
18
|
+
return false;
|
|
16
19
|
try {
|
|
17
|
-
|
|
18
|
-
return
|
|
20
|
+
process.kill(pid, 0);
|
|
21
|
+
return true;
|
|
19
22
|
}
|
|
20
23
|
catch {
|
|
21
24
|
return false;
|
|
22
25
|
}
|
|
23
26
|
}
|
|
27
|
+
/** A managed WDA this server still runs for the session (started here, or adopted at startup).
|
|
28
|
+
* A dead in-memory entry is dropped. */
|
|
29
|
+
function liveManagedWda(sessionId) {
|
|
30
|
+
const own = managedProcesses.get(sessionId);
|
|
31
|
+
if (own) {
|
|
32
|
+
if (pidIsAlive(own.pid))
|
|
33
|
+
return { pid: own.pid, adopted: false };
|
|
34
|
+
managedProcesses.delete(sessionId);
|
|
35
|
+
unregisterManagedProcess(own.pid);
|
|
36
|
+
}
|
|
37
|
+
const adopted = registeredWdaForSession(sessionId);
|
|
38
|
+
return adopted && pidIsAlive(adopted.pid) ? { pid: adopted.pid, adopted: true } : undefined;
|
|
39
|
+
}
|
|
40
|
+
/** The managed-WDA signature of this session's latest successful `qa_wda start` (from the
|
|
41
|
+
* mutation ledger, which survives a server restart). Lets `qa_wda stop` find the xcodebuild
|
|
42
|
+
* even when its process-registry entry was lost. Exported for tests. */
|
|
43
|
+
export function lastManagedWdaStart(session) {
|
|
44
|
+
const m = [...(session.mutations ?? [])]
|
|
45
|
+
.reverse()
|
|
46
|
+
.find((r) => r.tool === 'qa_wda' && r.action === 'wda_start' && r.status === 'executed' && typeof r.target?.projectPath === 'string');
|
|
47
|
+
if (!m)
|
|
48
|
+
return undefined;
|
|
49
|
+
const t = m.target;
|
|
50
|
+
if (typeof t.udid !== 'string' || !t.udid)
|
|
51
|
+
return undefined;
|
|
52
|
+
let port;
|
|
53
|
+
try {
|
|
54
|
+
const u = new URL(String(t.webDriverAgentUrl ?? ''));
|
|
55
|
+
port = Number(u.port) || undefined;
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
port = undefined;
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
projectPath: t.projectPath,
|
|
62
|
+
udid: t.udid,
|
|
63
|
+
...(typeof t.derivedDataPath === 'string' && t.derivedDataPath ? { derivedDataPath: t.derivedDataPath } : {}),
|
|
64
|
+
...(port ? { port } : {}),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
const isLoopback = isLoopbackWdaUrl;
|
|
24
68
|
function latestWdaArtifacts(session) {
|
|
25
69
|
const logs = [...session.artifacts].reverse().filter((a) => a.kind === 'wda');
|
|
26
70
|
const latestBuildLog = logs.find((a) => /build/i.test(a.label ?? a.path)) ?? null;
|
|
@@ -76,38 +120,58 @@ function managedWdaBuildProductStatus(derivedDataPath) {
|
|
|
76
120
|
export function registerWda(server, sessions) {
|
|
77
121
|
server.registerTool('qa_wda', {
|
|
78
122
|
title: 'WebDriverAgent diagnostics and attach',
|
|
79
|
-
description: 'Diagnose, attach, or manage an iOS WebDriverAgent backend
|
|
123
|
+
description: 'Diagnose, attach, or manage an iOS WebDriverAgent backend for structured iOS tap/type/snapshot. External WDA: ' +
|
|
124
|
+
'action:"attach" with webDriverAgentUrl (default http://127.0.0.1:8100). Managed WDA: build/start (consent-gated) from ' +
|
|
125
|
+
'wdaProjectPath or an installed Appium WDA; stop ends it. status/doctor/diagnose/logs/tune inspect a setup.',
|
|
80
126
|
inputSchema: {
|
|
81
127
|
sessionId: z.string(),
|
|
82
128
|
action: z.enum(['status', 'doctor', 'build', 'start', 'stop', 'attach', 'diagnose', 'logs', 'tune']),
|
|
83
|
-
webDriverAgentUrl: z.string().optional().describe('
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
129
|
+
webDriverAgentUrl: z.string().optional().describe('Default http://127.0.0.1:8100; non-loopback needs allowNonLoopback + consent.'),
|
|
130
|
+
device: z.string().optional().describe('Simulator UDID behind this WDA (default: the session device).'),
|
|
131
|
+
udid: z.string().optional().describe('Deprecated alias of device.'),
|
|
132
|
+
bundleId: z.string().optional().describe('Default: the session appId.'),
|
|
133
|
+
wdaProjectPath: z.string().optional().describe('WebDriverAgent.xcodeproj (default: Appium WDA if found).'),
|
|
134
|
+
derivedDataPath: z.string().optional().describe('xcodebuild -derivedDataPath for reuse.'),
|
|
88
135
|
scheme: z.string().optional().describe('WDA xcodebuild scheme. Defaults to WebDriverAgentRunner.'),
|
|
89
136
|
allowNonLoopback: z.boolean().optional().describe('Required to use a non-loopback external WDA URL.'),
|
|
90
137
|
consentId: z.string().optional(),
|
|
91
138
|
approve: z.boolean().optional(),
|
|
92
139
|
},
|
|
93
|
-
}, async ({ sessionId, action, webDriverAgentUrl, udid, bundleId, wdaProjectPath, derivedDataPath, scheme, allowNonLoopback, consentId, approve }) => {
|
|
140
|
+
}, async ({ sessionId, action, webDriverAgentUrl, device, udid: udidAlias, bundleId, wdaProjectPath, derivedDataPath, scheme, allowNonLoopback, consentId, approve, }) => {
|
|
94
141
|
const session = sessions.get(sessionId);
|
|
95
142
|
if (!session)
|
|
96
|
-
return
|
|
143
|
+
return unknownSessionError(sessionId);
|
|
144
|
+
// `device` is canonical (as on every other tool); `udid` is the deprecated alias.
|
|
145
|
+
if (device && udidAlias && device !== udidAlias)
|
|
146
|
+
return qaError({
|
|
147
|
+
what: `Conflicting device "${device}" and udid "${udidAlias}"; udid is a deprecated alias of device`,
|
|
148
|
+
changedState: false,
|
|
149
|
+
retrySafe: true,
|
|
150
|
+
failureCode: 'INVALID_ARGUMENT',
|
|
151
|
+
nextSteps: ['Pass only device.'],
|
|
152
|
+
});
|
|
153
|
+
const udid = device ?? udidAlias;
|
|
97
154
|
const configured = loadWdaConfig(session.root);
|
|
98
155
|
const url = webDriverAgentUrl ?? configured.url;
|
|
99
156
|
const loopback = isLoopback(url);
|
|
100
|
-
|
|
101
|
-
|
|
157
|
+
// Only the USER can pre-approve a remote WDA (env var in the MCP client config). The repo's
|
|
158
|
+
// .swipium/config.json (ios.wda.url / allowNonLoopbackUrls) arrives with the checkout, so it
|
|
159
|
+
// can never skip the per-call consent.
|
|
160
|
+
const userAllowed = !loopback && remoteWdaAllowedByUser(url);
|
|
161
|
+
const repoListed = !loopback && wdaUrlAllowedByConfig(configured, url);
|
|
162
|
+
if (!loopback && !allowNonLoopback && !userAllowed) {
|
|
102
163
|
return qaError({
|
|
103
|
-
what:
|
|
164
|
+
what: `Refused non-loopback WDA URL ${url}${webDriverAgentUrl ? '' : ' (from the repository config .swipium/config.json)'}`,
|
|
104
165
|
changedState: false,
|
|
105
166
|
retrySafe: false,
|
|
106
167
|
failureCode: 'DESTRUCTIVE_REFUSED',
|
|
107
|
-
nextSteps: [
|
|
168
|
+
nextSteps: [
|
|
169
|
+
`Use a localhost WDA URL, pass allowNonLoopback:true and approve the consent prompt, or (user-level, trusted isolated network only) set ${REMOTE_WDA_ENV}=<exact url> in the MCP server environment.`,
|
|
170
|
+
...(repoListed ? ['ios.wda.allowNonLoopbackUrls in the repository config no longer pre-approves a remote WDA.'] : []),
|
|
171
|
+
],
|
|
108
172
|
});
|
|
109
173
|
}
|
|
110
|
-
if (!loopback && !
|
|
174
|
+
if (!loopback && !userAllowed) {
|
|
111
175
|
const gate = consumeConsent(consentId, approve, { action: 'wda_non_loopback', affects: { url } });
|
|
112
176
|
if (!gate.approved) {
|
|
113
177
|
return requireConsent({
|
|
@@ -115,13 +179,21 @@ export function registerWda(server, sessions) {
|
|
|
115
179
|
risk: 'medium',
|
|
116
180
|
exactCommand: `connect to WebDriverAgent at ${url}`,
|
|
117
181
|
affects: { url },
|
|
118
|
-
explain: `Use non-loopback WebDriverAgent URL ${url}? WDA is an automation server; only approve this on a trusted, isolated network.`,
|
|
182
|
+
explain: `Use non-loopback WebDriverAgent URL ${url}${webDriverAgentUrl ? '' : ' (configured by the repository (.swipium/config.json), unreviewed)'}? WDA is an automation server that receives app screens and typed text; only approve this on a trusted, isolated network.`,
|
|
119
183
|
});
|
|
120
184
|
}
|
|
121
185
|
}
|
|
122
|
-
const resolvePath = (p) => p ? (isAbsolute(p) ? p : join(session.root, p)) : undefined;
|
|
123
|
-
const
|
|
186
|
+
const resolvePath = (p) => (p ? (isAbsolute(p) ? p : join(session.root, p)) : undefined);
|
|
187
|
+
const explicitProjectPath = resolvePath(wdaProjectPath);
|
|
188
|
+
// Managed build/start without wdaProjectPath: use a user-installed Appium WebDriverAgent
|
|
189
|
+
// (~/.appium/…/appium-webdriveragent, global npm), reported as wdaProjectSource.
|
|
190
|
+
const discoveredAppiumProject = !explicitProjectPath && (action === 'build' || action === 'start') ? discoverAppiumWdaProjects()[0] : undefined;
|
|
191
|
+
const projectPath = explicitProjectPath ?? discoveredAppiumProject;
|
|
192
|
+
const wdaProjectSource = explicitProjectPath ? 'argument' : discoveredAppiumProject ? 'appium-discovered' : null;
|
|
124
193
|
const ddPath = resolvePath(derivedDataPath) ?? configured.derivedDataPath;
|
|
194
|
+
// What this call actually uses (args over config), echoed as `wdaConfig` so a passed
|
|
195
|
+
// derivedDataPath / webDriverAgentUrl is not misreported as the configured default.
|
|
196
|
+
const effectiveConfig = { ...configured, url, derivedDataPath: ddPath };
|
|
125
197
|
const targetUdid = udid ?? session.device;
|
|
126
198
|
if (udid && session.device && udid !== session.device) {
|
|
127
199
|
return qaError({
|
|
@@ -148,20 +220,60 @@ export function registerWda(server, sessions) {
|
|
|
148
220
|
if (action === 'tune') {
|
|
149
221
|
const recommendations = wdaRecommendations(configured, session);
|
|
150
222
|
const timings = wdaTimingSummary(session);
|
|
151
|
-
return qaOk({ webDriverAgentUrl: url, wdaConfig:
|
|
223
|
+
return qaOk({ webDriverAgentUrl: url, wdaConfig: effectiveConfig, timings, recommendations }, recommendations.length
|
|
152
224
|
? `WDA tuning recommendations:\n${recommendations.map((r) => ` - ${r.setting}=${JSON.stringify(r.value)}: ${r.reason}`).join('\n')}`
|
|
153
225
|
: 'WDA tuning: no recommendations from current session evidence.');
|
|
154
226
|
}
|
|
155
227
|
if (action === 'stop') {
|
|
156
228
|
const proc = managedProcesses.get(session.id);
|
|
157
|
-
if (!proc)
|
|
158
|
-
|
|
229
|
+
if (!proc) {
|
|
230
|
+
// A WDA started by a previous server run and adopted at startup (processRegistry).
|
|
231
|
+
const adopted = registeredWdaForSession(session.id);
|
|
232
|
+
const outcome = adopted ? reclaimPid(adopted.pid, 'wda', undefined, adopted) : undefined; // fingerprint-checked
|
|
233
|
+
if (adopted)
|
|
234
|
+
unregisterManagedProcess(adopted.pid);
|
|
235
|
+
if (adopted && outcome === 'killed') {
|
|
236
|
+
sessions.addEnvChange(session, `wda stop pid ${adopted.pid} (adopted)`);
|
|
237
|
+
sessions.recordMutation(session, {
|
|
238
|
+
tool: 'qa_wda',
|
|
239
|
+
action: 'wda_stop',
|
|
240
|
+
risk: 'low',
|
|
241
|
+
target: { pid: adopted.pid, adopted: true, webDriverAgentUrl: adopted.endpoint ?? null },
|
|
242
|
+
consent: { required: false, approved: true },
|
|
243
|
+
status: 'restored',
|
|
244
|
+
detail: `adopted WDA ${outcome}`,
|
|
245
|
+
});
|
|
246
|
+
return qaOk({ stopped: true, pid: adopted.pid, adopted: true, outcome }, `stopped adopted managed WDA pid ${adopted.pid}`);
|
|
247
|
+
}
|
|
248
|
+
// Registry entry lost (or unverifiable): find the managed xcodebuild this session started
|
|
249
|
+
// by its exact signature (project + destination + derived data), never by pid alone.
|
|
250
|
+
const sig = lastManagedWdaStart(session);
|
|
251
|
+
const pids = sig ? findManagedWdaProcesses(sig) : [];
|
|
252
|
+
const killed = pids.filter((pid) => killManagedWda(pid));
|
|
253
|
+
if (!killed.length) {
|
|
254
|
+
if (adopted)
|
|
255
|
+
return qaOk({ stopped: false, pid: adopted.pid, adopted: true, outcome }, `adopted WDA pid ${adopted.pid} was already ${outcome}`);
|
|
256
|
+
return qaOk({ stopped: false }, 'no managed WDA process recorded for this session');
|
|
257
|
+
}
|
|
258
|
+
sessions.addEnvChange(session, `wda stop pid ${killed.join(',')} (recovered by signature)`);
|
|
259
|
+
sessions.recordMutation(session, {
|
|
260
|
+
tool: 'qa_wda',
|
|
261
|
+
action: 'wda_stop',
|
|
262
|
+
risk: 'low',
|
|
263
|
+
target: { pids: killed, recovered: true, projectPath: sig.projectPath, udid: sig.udid },
|
|
264
|
+
consent: { required: false, approved: true },
|
|
265
|
+
status: 'restored',
|
|
266
|
+
detail: 'managed WDA located by command signature (registry entry missing)',
|
|
267
|
+
});
|
|
268
|
+
return qaOk({ stopped: true, pid: killed[0], pids: killed, recovered: true }, `stopped managed WDA pid ${killed.join(', ')} (located by its xcodebuild signature; registry entry was missing)`);
|
|
269
|
+
}
|
|
159
270
|
try {
|
|
160
271
|
process.kill(proc.pid, 'SIGTERM');
|
|
161
272
|
}
|
|
162
273
|
catch {
|
|
163
274
|
/* already gone */
|
|
164
275
|
}
|
|
276
|
+
unregisterManagedProcess(proc.pid);
|
|
165
277
|
managedProcesses.delete(session.id);
|
|
166
278
|
sessions.addEnvChange(session, `wda stop pid ${proc.pid}`);
|
|
167
279
|
sessions.recordMutation(session, {
|
|
@@ -176,7 +288,13 @@ export function registerWda(server, sessions) {
|
|
|
176
288
|
}
|
|
177
289
|
if (action === 'build' || action === 'start') {
|
|
178
290
|
if (!targetUdid) {
|
|
179
|
-
return qaError({
|
|
291
|
+
return qaError({
|
|
292
|
+
what: `qa_wda ${action} requires a simulator/device UDID`,
|
|
293
|
+
changedState: false,
|
|
294
|
+
retrySafe: true,
|
|
295
|
+
failureCode: 'NO_DEVICE',
|
|
296
|
+
nextSteps: ['Boot/select a simulator with qa_ios boot, or pass device explicitly.'],
|
|
297
|
+
});
|
|
180
298
|
}
|
|
181
299
|
if (action === 'start' && configured.reuse) {
|
|
182
300
|
const reuseStartedAt = Date.now();
|
|
@@ -184,19 +302,66 @@ export function registerWda(server, sessions) {
|
|
|
184
302
|
const reuseCheckMs = Date.now() - reuseStartedAt;
|
|
185
303
|
sessions.addMilestoneDuration(session, 'wda_reuse_check_ms', reuseCheckMs);
|
|
186
304
|
if (existing.reachable && existing.ready) {
|
|
187
|
-
return qaOk({
|
|
305
|
+
return qaOk({
|
|
306
|
+
started: false,
|
|
307
|
+
reused: true,
|
|
308
|
+
ready: true,
|
|
309
|
+
webDriverAgentUrl: url,
|
|
310
|
+
udid: targetUdid,
|
|
311
|
+
wda: existing,
|
|
312
|
+
wdaConfig: effectiveConfig,
|
|
313
|
+
reuseCheckMs,
|
|
314
|
+
}, `reused existing WDA at ${url}; /status is ready\nNext: qa_wda attach.`);
|
|
188
315
|
}
|
|
189
316
|
}
|
|
317
|
+
// Never start a second managed xcodebuild over a live one: the new runner would fight it
|
|
318
|
+
// for the port and the old one would be orphaned (managedProcesses would be overwritten).
|
|
319
|
+
const running = action === 'start' ? liveManagedWda(session.id) : undefined;
|
|
320
|
+
if (running) {
|
|
321
|
+
return qaError({
|
|
322
|
+
what: `A managed WDA (pid ${running.pid}${running.adopted ? ', adopted from a previous server run' : ''}) is already running for this session`,
|
|
323
|
+
changedState: false,
|
|
324
|
+
retrySafe: true,
|
|
325
|
+
failureCode: 'WDA_START_FAILED',
|
|
326
|
+
nextSteps: ['Use it (qa_wda attach), or stop it first with qa_wda { action:"stop" } and retry start.'],
|
|
327
|
+
}, { managedPid: running.pid, adopted: running.adopted, webDriverAgentUrl: url });
|
|
328
|
+
}
|
|
190
329
|
const xcode = await xcodeAvailable();
|
|
191
330
|
if (!xcode.available) {
|
|
192
|
-
return qaError({
|
|
331
|
+
return qaError({
|
|
332
|
+
what: 'Xcode command line tools are unavailable',
|
|
333
|
+
changedState: false,
|
|
334
|
+
retrySafe: true,
|
|
335
|
+
failureCode: 'BACKEND_UNSUPPORTED',
|
|
336
|
+
nextSteps: [xcode.error ?? 'Install Xcode and select it with xcode-select.'],
|
|
337
|
+
}, { xcode });
|
|
193
338
|
}
|
|
194
339
|
if (!projectPath || !existsSync(projectPath)) {
|
|
195
|
-
return qaError({
|
|
340
|
+
return qaError({
|
|
341
|
+
what: `qa_wda ${action} requires wdaProjectPath pointing to WebDriverAgent.xcodeproj`,
|
|
342
|
+
changedState: false,
|
|
343
|
+
retrySafe: true,
|
|
344
|
+
failureCode: 'NO_ARTIFACT',
|
|
345
|
+
nextSteps: [
|
|
346
|
+
"Pass wdaProjectPath, for example path/to/WebDriverAgent.xcodeproj, or install Appium's WebDriverAgent (appium driver install xcuitest) so it is auto-discovered under ~/.appium.",
|
|
347
|
+
],
|
|
348
|
+
}, { xcode, wdaProjectPath: projectPath ?? null, wdaProjectSource });
|
|
196
349
|
}
|
|
197
350
|
const args = action === 'build'
|
|
198
|
-
? managedWdaBuildArgs({
|
|
199
|
-
|
|
351
|
+
? managedWdaBuildArgs({
|
|
352
|
+
projectPath,
|
|
353
|
+
udid: targetUdid,
|
|
354
|
+
derivedDataPath: ddPath,
|
|
355
|
+
scheme,
|
|
356
|
+
developmentTeam: configured.developmentTeam,
|
|
357
|
+
})
|
|
358
|
+
: managedWdaStartArgs({
|
|
359
|
+
projectPath,
|
|
360
|
+
udid: targetUdid,
|
|
361
|
+
derivedDataPath: ddPath,
|
|
362
|
+
scheme,
|
|
363
|
+
developmentTeam: configured.developmentTeam,
|
|
364
|
+
});
|
|
200
365
|
const gate = consumeConsent(consentId, approve, { action: `wda_${action}`, affects: { udid: targetUdid, projectPath } });
|
|
201
366
|
if (!gate.approved) {
|
|
202
367
|
sessions.recordMutation(session, {
|
|
@@ -207,7 +372,13 @@ export function registerWda(server, sessions) {
|
|
|
207
372
|
consent: { required: true, approved: false },
|
|
208
373
|
status: 'requested',
|
|
209
374
|
});
|
|
210
|
-
return requireConsent({
|
|
375
|
+
return requireConsent({
|
|
376
|
+
action: `wda_${action}`,
|
|
377
|
+
risk: 'medium',
|
|
378
|
+
exactCommand: `xcodebuild ${args.join(' ')}`,
|
|
379
|
+
affects: { udid: targetUdid, projectPath },
|
|
380
|
+
explain: `${action === 'build' ? 'Build' : 'Start'} WebDriverAgent with xcodebuild? This can use local signing context and run for a while.`,
|
|
381
|
+
});
|
|
211
382
|
}
|
|
212
383
|
sessions.recordMutation(session, {
|
|
213
384
|
tool: 'qa_wda',
|
|
@@ -237,13 +408,17 @@ export function registerWda(server, sessions) {
|
|
|
237
408
|
detail: `${failureCode}: exit ${r.code}`,
|
|
238
409
|
});
|
|
239
410
|
return qaError({
|
|
240
|
-
what: failureCode === 'WDA_SIGNING_FAILED'
|
|
411
|
+
what: failureCode === 'WDA_SIGNING_FAILED'
|
|
412
|
+
? `WDA signing/provisioning failed with exit ${r.code}`
|
|
413
|
+
: `WDA build failed with exit ${r.code}`,
|
|
241
414
|
changedState: true,
|
|
242
415
|
retrySafe: failureCode !== 'WDA_SIGNING_FAILED',
|
|
243
416
|
failureCode,
|
|
244
417
|
artifactUri: logUri,
|
|
245
418
|
nextSteps: failureCode === 'WDA_SIGNING_FAILED'
|
|
246
|
-
? [
|
|
419
|
+
? [
|
|
420
|
+
'Open the WDA build log artifact, configure a valid development team/certificate/provisioning profile for the device, then retry.',
|
|
421
|
+
]
|
|
247
422
|
: ['Open the WDA build log artifact, fix the Xcode build error, then retry.'],
|
|
248
423
|
}, { xcode, logUri, timedOut: r.timedOut });
|
|
249
424
|
}
|
|
@@ -256,22 +431,49 @@ export function registerWda(server, sessions) {
|
|
|
256
431
|
status: 'executed',
|
|
257
432
|
ledgerUri: logUri,
|
|
258
433
|
});
|
|
259
|
-
|
|
434
|
+
const wdaBuildProduct = managedWdaBuildProductStatus(ddPath);
|
|
435
|
+
return qaOk({
|
|
436
|
+
built: true,
|
|
437
|
+
logUri,
|
|
438
|
+
xcode,
|
|
439
|
+
command: ['xcodebuild', ...args],
|
|
440
|
+
wdaConfig: effectiveConfig,
|
|
441
|
+
wdaProjectPath: projectPath,
|
|
442
|
+
wdaProjectSource,
|
|
443
|
+
derivedDataPath: ddPath,
|
|
444
|
+
wdaBuildProduct,
|
|
445
|
+
}, `WDA build completed (${wdaProjectSource === 'appium-discovered' ? 'auto-discovered Appium WDA ' : ''}${projectPath}) > ${logUri}`);
|
|
260
446
|
}
|
|
261
447
|
const logUri = sessions.saveArtifact(session, 'wda', `wda-start-${Date.now()}.log`, '', 'text/plain', 'WDA start log');
|
|
262
448
|
const rec = sessions.findArtifact(logUri);
|
|
263
449
|
const fd = openSync(rec.rec.path, 'a');
|
|
264
450
|
sessions.milestone(session, 'wda_start_start');
|
|
265
|
-
|
|
451
|
+
let child;
|
|
452
|
+
try {
|
|
453
|
+
child = spawn('xcodebuild', args, { detached: true, stdio: ['ignore', fd, fd] });
|
|
454
|
+
}
|
|
455
|
+
finally {
|
|
456
|
+
closeSync(fd); // the child holds its own duplicate; ours would leak one fd per start
|
|
457
|
+
}
|
|
266
458
|
sessions.milestone(session, 'wda_start_end');
|
|
459
|
+
child.on('error', () => undefined); // spawn failure surfaces as WDA_START_FAILED below, not a crash
|
|
267
460
|
child.unref();
|
|
268
461
|
managedProcesses.set(session.id, { pid: child.pid ?? -1, logUri });
|
|
462
|
+
// Reapable if this server crashes; `endpoint` lets the next server adopt it when healthy.
|
|
463
|
+
registerManagedProcess(child.pid, 'wda', session.id, { endpoint: url });
|
|
269
464
|
sessions.addEnvChange(session, `wda start pid ${child.pid ?? 'unknown'} ${projectPath} ${targetUdid}`);
|
|
270
465
|
sessions.recordMutation(session, {
|
|
271
466
|
tool: 'qa_wda',
|
|
272
467
|
action: 'wda_start',
|
|
273
468
|
risk: 'medium',
|
|
274
|
-
target: {
|
|
469
|
+
target: {
|
|
470
|
+
udid: targetUdid,
|
|
471
|
+
projectPath,
|
|
472
|
+
derivedDataPath: ddPath,
|
|
473
|
+
scheme: scheme ?? null,
|
|
474
|
+
pid: child.pid ?? null,
|
|
475
|
+
webDriverAgentUrl: url,
|
|
476
|
+
},
|
|
275
477
|
consent: { required: true, consentId, approved: true },
|
|
276
478
|
status: 'executed',
|
|
277
479
|
ledgerUri: logUri,
|
|
@@ -284,7 +486,14 @@ export function registerWda(server, sessions) {
|
|
|
284
486
|
tool: 'qa_wda',
|
|
285
487
|
action: 'wda_start',
|
|
286
488
|
risk: 'medium',
|
|
287
|
-
target: {
|
|
489
|
+
target: {
|
|
490
|
+
udid: targetUdid,
|
|
491
|
+
projectPath,
|
|
492
|
+
derivedDataPath: ddPath,
|
|
493
|
+
scheme: scheme ?? null,
|
|
494
|
+
pid: child.pid ?? null,
|
|
495
|
+
webDriverAgentUrl: url,
|
|
496
|
+
},
|
|
288
497
|
consent: { required: true, consentId, approved: true },
|
|
289
498
|
status: 'blocked',
|
|
290
499
|
ledgerUri: logUri,
|
|
@@ -296,10 +505,34 @@ export function registerWda(server, sessions) {
|
|
|
296
505
|
retrySafe: true,
|
|
297
506
|
failureCode: 'WDA_START_FAILED',
|
|
298
507
|
artifactUri: logUri,
|
|
299
|
-
nextSteps: [
|
|
300
|
-
|
|
508
|
+
nextSteps: [
|
|
509
|
+
'Open the WDA start log artifact, fix the launch/signing/device issue, then retry qa_wda start. If WDA eventually becomes ready, qa_wda attach can still use this managed process.',
|
|
510
|
+
],
|
|
511
|
+
}, {
|
|
512
|
+
started: true,
|
|
513
|
+
ready: false,
|
|
514
|
+
pid: child.pid ?? null,
|
|
515
|
+
logUri,
|
|
516
|
+
webDriverAgentUrl: url,
|
|
517
|
+
command: ['xcodebuild', ...args],
|
|
518
|
+
wdaConfig: effectiveConfig,
|
|
519
|
+
wda: waited.status,
|
|
520
|
+
startupWaitMs: waited.durationMs,
|
|
521
|
+
});
|
|
301
522
|
}
|
|
302
|
-
return qaOk({
|
|
523
|
+
return qaOk({
|
|
524
|
+
started: true,
|
|
525
|
+
ready: true,
|
|
526
|
+
pid: child.pid ?? null,
|
|
527
|
+
logUri,
|
|
528
|
+
webDriverAgentUrl: url,
|
|
529
|
+
wdaProjectPath: projectPath,
|
|
530
|
+
wdaProjectSource,
|
|
531
|
+
command: ['xcodebuild', ...args],
|
|
532
|
+
wdaConfig: effectiveConfig,
|
|
533
|
+
wda: waited.status,
|
|
534
|
+
startupWaitMs: waited.durationMs,
|
|
535
|
+
}, `started managed WDA pid ${child.pid ?? 'unknown'} and /status is ready > ${logUri}\nNext: qa_wda attach.`);
|
|
303
536
|
}
|
|
304
537
|
const status = await checkWda(url);
|
|
305
538
|
const xcode = await xcodeAvailable();
|
|
@@ -307,7 +540,9 @@ export function registerWda(server, sessions) {
|
|
|
307
540
|
const appId = bundleId ?? session.appId ?? null;
|
|
308
541
|
const artifactSummary = latestWdaArtifacts(session);
|
|
309
542
|
const wdaProjectDiscovery = discoverWdaProjects(session.root, projectPath ? [projectPath] : []);
|
|
310
|
-
|
|
543
|
+
// Reported whenever managed WDA is in play OR a derived-data cache exists (e.g. after a
|
|
544
|
+
// qa_wda build that used an auto-discovered Appium project and no explicit path).
|
|
545
|
+
const wdaBuildProduct = configured.mode === 'managed' || !!projectPath || existsSync(ddPath) ? managedWdaBuildProductStatus(ddPath) : null;
|
|
311
546
|
const simctlOk = await sim.simctlAvailable().catch(() => false);
|
|
312
547
|
const simulators = simctlOk ? await sim.listSimulators().catch(() => []) : [];
|
|
313
548
|
const bootedSimulators = simulators.filter((s) => s.state === 'Booted');
|
|
@@ -322,7 +557,7 @@ export function registerWda(server, sessions) {
|
|
|
322
557
|
bundleId: appId,
|
|
323
558
|
webDriverAgentUrl: url,
|
|
324
559
|
wda: status,
|
|
325
|
-
wdaConfig:
|
|
560
|
+
wdaConfig: effectiveConfig,
|
|
326
561
|
wdaProjectDiscovery,
|
|
327
562
|
signing: wdaSigningStatus(configured),
|
|
328
563
|
wdaBuildProduct,
|
|
@@ -351,13 +586,19 @@ export function registerWda(server, sessions) {
|
|
|
351
586
|
issues.push(issue('IOS_SIMULATOR_RUNTIME_MISSING', 'xcrun simctl is available, but no iOS simulators were found', 'Install an iOS simulator runtime in Xcode, create an iPhone simulator, then retry qa_wda doctor.', 'blocker', 'SIMULATOR_RUNTIME_MISSING'));
|
|
352
587
|
}
|
|
353
588
|
else if (!bootedUdid && simctlOk && bootedSimulators.length === 0) {
|
|
354
|
-
issues.push(issue('NO_BOOTED_SIMULATOR', 'no booted iOS simulator was detected', 'Boot/select a simulator with qa_ios boot, or pass
|
|
589
|
+
issues.push(issue('NO_BOOTED_SIMULATOR', 'no booted iOS simulator was detected', 'Boot/select a simulator with qa_ios boot, or pass device for an already-running WDA target.'));
|
|
355
590
|
}
|
|
356
591
|
if (!bootedUdid)
|
|
357
|
-
issues.push(issue('NO_UDID', 'no simulator/device UDID is bound to this session', 'Boot/select a simulator with qa_ios boot, or pass
|
|
358
|
-
|
|
592
|
+
issues.push(issue('NO_UDID', 'no simulator/device UDID is bound to this session', 'Boot/select a simulator with qa_ios boot, or pass device explicitly.'));
|
|
593
|
+
// No path given but a user-installed Appium WDA exists: build/start will auto-use it.
|
|
594
|
+
const appiumAuto = wantsManaged && !projectPath ? discoverAppiumWdaProjects()[0] : undefined;
|
|
595
|
+
if (wantsManaged && (!projectPath || !existsSync(projectPath)) && !appiumAuto) {
|
|
359
596
|
const discovered = wdaProjectDiscovery.candidates[0];
|
|
360
|
-
issues.push(issue('WDA_PROJECT_MISSING', discovered
|
|
597
|
+
issues.push(issue('WDA_PROJECT_MISSING', discovered
|
|
598
|
+
? `managed WDA needs wdaProjectPath; discovered candidate ${discovered}`
|
|
599
|
+
: 'managed WDA needs a WebDriverAgent.xcodeproj path; no local candidate was discovered', discovered
|
|
600
|
+
? `Pass wdaProjectPath: "${discovered}", or configure ios.wda for that checked-out WebDriverAgent project.`
|
|
601
|
+
: 'Check out WebDriverAgent/Appium WDA, pass wdaProjectPath, or provide an external WDA URL.'));
|
|
361
602
|
}
|
|
362
603
|
if (wantsManaged && projectPath && existsSync(projectPath) && wdaBuildProduct && !wdaBuildProduct.built)
|
|
363
604
|
issues.push(issue('WDA_NOT_BUILT', `no WebDriverAgentRunner .app was found under derivedDataPath ${wdaBuildProduct.checkedPath}`, 'Run qa_wda build first, or point ios.wda.derivedDataPath at a cache containing a built WebDriverAgentRunner product.'));
|
|
@@ -395,7 +636,9 @@ export function registerWda(server, sessions) {
|
|
|
395
636
|
changedState: false,
|
|
396
637
|
retrySafe: true,
|
|
397
638
|
failureCode: 'MULTIPLE_DEVICES',
|
|
398
|
-
nextSteps: [
|
|
639
|
+
nextSteps: [
|
|
640
|
+
'Pass device explicitly, or bind the session to a device first. This prevents attaching to a stale WDA for the wrong device.',
|
|
641
|
+
],
|
|
399
642
|
}, base);
|
|
400
643
|
}
|
|
401
644
|
if (!status.reachable) {
|
|
@@ -408,7 +651,12 @@ export function registerWda(server, sessions) {
|
|
|
408
651
|
}, base);
|
|
409
652
|
}
|
|
410
653
|
try {
|
|
411
|
-
const sessionOptions = {
|
|
654
|
+
const sessionOptions = {
|
|
655
|
+
bundleId: appId ?? undefined,
|
|
656
|
+
udid: targetUdid,
|
|
657
|
+
capabilities: configured.capabilities,
|
|
658
|
+
settings: configured.settings,
|
|
659
|
+
};
|
|
412
660
|
const createStarted = Date.now();
|
|
413
661
|
let created;
|
|
414
662
|
try {
|
|
@@ -424,7 +672,7 @@ export function registerWda(server, sessions) {
|
|
|
424
672
|
action: 'wda_attach',
|
|
425
673
|
risk: 'medium',
|
|
426
674
|
target: { webDriverAgentUrl: url, udid: targetUdid, bundleId: appId ?? null, reportedDevice: mismatchedUdid },
|
|
427
|
-
consent: { required: !loopback && !
|
|
675
|
+
consent: { required: !loopback && !userAllowed, consentId, approved: loopback || userAllowed || !!approve },
|
|
428
676
|
status: 'blocked',
|
|
429
677
|
detail: 'WDA reported a different device',
|
|
430
678
|
});
|
|
@@ -436,7 +684,11 @@ export function registerWda(server, sessions) {
|
|
|
436
684
|
nextSteps: ['Stop the stale WDA process or start a new WDA session for the intended UDID.'],
|
|
437
685
|
}, { ...base, capabilities: created.capabilities ?? null, wdaSessionId: created.sessionId });
|
|
438
686
|
}
|
|
439
|
-
const driver = new WdaDriver(url, {
|
|
687
|
+
const driver = new WdaDriver(url, {
|
|
688
|
+
...sessionOptions,
|
|
689
|
+
sessionId: created.sessionId,
|
|
690
|
+
onTiming: (kind, ms) => recordWdaTiming(session, kind, ms, sessions),
|
|
691
|
+
});
|
|
440
692
|
session.driver = driver;
|
|
441
693
|
session.device = targetUdid;
|
|
442
694
|
if (appId)
|
|
@@ -447,8 +699,14 @@ export function registerWda(server, sessions) {
|
|
|
447
699
|
tool: 'qa_wda',
|
|
448
700
|
action: 'wda_attach',
|
|
449
701
|
risk: 'medium',
|
|
450
|
-
target: {
|
|
451
|
-
|
|
702
|
+
target: {
|
|
703
|
+
webDriverAgentUrl: url,
|
|
704
|
+
udid: targetUdid,
|
|
705
|
+
bundleId: appId ?? null,
|
|
706
|
+
wdaSessionId: created.sessionId,
|
|
707
|
+
capabilities: created.capabilities ?? null,
|
|
708
|
+
},
|
|
709
|
+
consent: { required: !loopback && !userAllowed, consentId, approved: true },
|
|
452
710
|
status: 'executed',
|
|
453
711
|
});
|
|
454
712
|
return qaOk({ ...base, sessionActive: true, wdaSessionId: created.sessionId, capabilities: created.capabilities ?? null }, `attached WDA structured iOS backend at ${url}\nNext: qa_snapshot / qa_act / qa_flow_run can use WDA-backed structured operations.`);
|
|
@@ -460,7 +718,7 @@ export function registerWda(server, sessions) {
|
|
|
460
718
|
action: 'wda_attach',
|
|
461
719
|
risk: 'medium',
|
|
462
720
|
target: { webDriverAgentUrl: url, udid: targetUdid, bundleId: appId ?? null },
|
|
463
|
-
consent: { required: !loopback && !
|
|
721
|
+
consent: { required: !loopback && !userAllowed, consentId, approved: loopback || userAllowed || !!approve },
|
|
464
722
|
status: 'blocked',
|
|
465
723
|
detail: String(e.message ?? e),
|
|
466
724
|
});
|