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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// SWIPIUM Issue Log
|
|
1
|
+
// SWIPIUM Issue Log: report integration bridge.
|
|
2
2
|
//
|
|
3
3
|
// Converts a finished run's health findings + structured test outcomes into normalized issue
|
|
4
4
|
// observations, records them in the durable ledger (so recurrence works across runs), and returns
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
import { recordObservation } from './index.js';
|
|
11
11
|
import { getIndex } from './store.js';
|
|
12
12
|
import { buildReportIssuesSection } from './report.js';
|
|
13
|
-
import { isIssueCategory } from './schema.js';
|
|
13
|
+
import { isIssueCategory, } from './schema.js';
|
|
14
14
|
const BILLING_HINTS = [
|
|
15
15
|
['revenuecat', /revenuecat/i],
|
|
16
16
|
['storekit', /storekit/i],
|
|
@@ -47,7 +47,7 @@ function inferScreenPurpose(n) {
|
|
|
47
47
|
function noteToObservation(n) {
|
|
48
48
|
const subsystem = detectSubsystem(`${n.workflow} ${n.reason ?? ''}`);
|
|
49
49
|
return {
|
|
50
|
-
title: `${n.workflow}
|
|
50
|
+
title: `${n.workflow} > ${n.outcome}`,
|
|
51
51
|
summary: n.reason ? n.reason.slice(0, 200) : `${n.workflow} ${n.outcome}`,
|
|
52
52
|
failureCode: n.failureCode,
|
|
53
53
|
workflow: n.workflow,
|
|
@@ -56,7 +56,7 @@ function noteToObservation(n) {
|
|
|
56
56
|
subsystem,
|
|
57
57
|
};
|
|
58
58
|
}
|
|
59
|
-
// A blocked/failed note in any of these categories is a real
|
|
59
|
+
// A blocked/failed note in any of these categories is a real issue-ledger entry (not just
|
|
60
60
|
// app bugs): hard gates, store-compliance/privacy gaps, readiness improvements, missing data, etc.
|
|
61
61
|
// Intentional skips and not-applicable / passing outcomes are NOT recorded.
|
|
62
62
|
const RECORDED_NOTE_CATEGORIES = new Set([
|
|
@@ -77,7 +77,7 @@ function shouldRecordNote(n) {
|
|
|
77
77
|
if (n.category === 'intentionally_skipped')
|
|
78
78
|
return false;
|
|
79
79
|
// Record when it carries a recognized category, a failure code, or is an uncategorized failure
|
|
80
|
-
// (an uncategorized fail/blocked is still worth remembering
|
|
80
|
+
// (an uncategorized fail/blocked is still worth remembering; the classifier triages it).
|
|
81
81
|
return !n.category || RECORDED_NOTE_CATEGORIES.has(n.category) || Boolean(n.failureCode);
|
|
82
82
|
}
|
|
83
83
|
/**
|
|
@@ -94,9 +94,24 @@ verifiedFixedIssueIds) {
|
|
|
94
94
|
for (const f of findings) {
|
|
95
95
|
if (f.severity === 'info')
|
|
96
96
|
continue; // info findings are not issues
|
|
97
|
-
const res = recordObservation(root, findingToObservation(f), now, { environment: meta.environment }, {
|
|
97
|
+
const res = recordObservation(root, findingToObservation(f), now, { environment: meta.environment }, {
|
|
98
|
+
appId: meta.appId,
|
|
99
|
+
appName: meta.appName,
|
|
100
|
+
platform: meta.platform,
|
|
101
|
+
environment: meta.environment,
|
|
102
|
+
sourceRevision: meta.sourceRevision,
|
|
103
|
+
run,
|
|
104
|
+
});
|
|
98
105
|
recordedIssueIds.push(res.issueId);
|
|
99
|
-
recorded.push({
|
|
106
|
+
recorded.push({
|
|
107
|
+
issueId: res.issueId,
|
|
108
|
+
fingerprint: res.fingerprint,
|
|
109
|
+
source: 'finding',
|
|
110
|
+
category: res.record.category,
|
|
111
|
+
severity: res.record.severity,
|
|
112
|
+
state: res.record.state,
|
|
113
|
+
reopened: res.reopened,
|
|
114
|
+
});
|
|
100
115
|
if (res.recurrenceMessage)
|
|
101
116
|
recurrences.push(res.recurrenceMessage);
|
|
102
117
|
}
|
|
@@ -106,9 +121,25 @@ verifiedFixedIssueIds) {
|
|
|
106
121
|
// Trust an explicit, valid issue-category note as a classifier fallback (the text rules still
|
|
107
122
|
// win when they detect a stronger signal, e.g. an actual RedBox mentioned in the reason).
|
|
108
123
|
const categoryHint = n.category && isIssueCategory(n.category) ? n.category : undefined;
|
|
109
|
-
const res = recordObservation(root, noteToObservation(n), now, { environment: meta.environment, categoryHint }, {
|
|
124
|
+
const res = recordObservation(root, noteToObservation(n), now, { environment: meta.environment, categoryHint }, {
|
|
125
|
+
appId: meta.appId,
|
|
126
|
+
appName: meta.appName,
|
|
127
|
+
platform: meta.platform,
|
|
128
|
+
environment: meta.environment,
|
|
129
|
+
sourceRevision: meta.sourceRevision,
|
|
130
|
+
run: { ...run, testCaseId: n.workflow },
|
|
131
|
+
});
|
|
110
132
|
recordedIssueIds.push(res.issueId);
|
|
111
|
-
recorded.push({
|
|
133
|
+
recorded.push({
|
|
134
|
+
issueId: res.issueId,
|
|
135
|
+
fingerprint: res.fingerprint,
|
|
136
|
+
source: 'note',
|
|
137
|
+
workflow: n.workflow,
|
|
138
|
+
category: res.record.category,
|
|
139
|
+
severity: res.record.severity,
|
|
140
|
+
state: res.record.state,
|
|
141
|
+
reopened: res.reopened,
|
|
142
|
+
});
|
|
112
143
|
if (res.recurrenceMessage)
|
|
113
144
|
recurrences.push(res.recurrenceMessage);
|
|
114
145
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reportBridge.js","sourceRoot":"","sources":["../../src/issues/reportBridge.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"reportBridge.js","sourceRoot":"","sources":["../../src/issues/reportBridge.ts"],"names":[],"mappings":"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"}
|
package/dist/issues/schema.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
// SWIPIUM Issue Log / Error Tracking
|
|
1
|
+
// SWIPIUM Issue Log / Error Tracking. Type definitions, enums, and validation
|
|
2
2
|
// helpers for the durable, project-level issue ledger.
|
|
3
3
|
//
|
|
4
4
|
// The ledger is Swipium's mobile-QA memory: an append-only event log (`.swipium/issues-log.jsonl`)
|
|
5
5
|
// plus a derived index (`.swipium/issues/index.json`). Events are compact and never hold full
|
|
6
|
-
// screenshots / logs / stack traces / report JSON
|
|
6
|
+
// screenshots / logs / stack traces / report JSON. Only references to artifacts (Developer Notes).
|
|
7
7
|
// Every lifecycle mutation is append-only so a developer can audit WHY an issue is currently
|
|
8
8
|
// considered fixed / reopened / suppressed.
|
|
9
9
|
//
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/issues/schema.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/issues/schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
// SWIPIUM Issue Log
|
|
1
|
+
// SWIPIUM Issue Log: source revision resolution.
|
|
2
2
|
//
|
|
3
3
|
// Fix attribution is strongest when issues link to a commit/release. But Swipium intentionally does
|
|
4
4
|
// NOT execute Git in spawned providers. So we resolve a SourceRevision in priority order WITHOUT
|
|
5
|
-
// running Git: explicit input
|
|
5
|
+
// running Git: explicit input > CI environment variables > app build metadata > optional read-only
|
|
6
6
|
// `.git/HEAD` (only when policy sets allowGitMetadataRead). `unknown` is always an acceptable result.
|
|
7
7
|
//
|
|
8
8
|
// PURE w.r.t. process state except the optional read-only git read, which only touches `.git/HEAD`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sourceRevision.js","sourceRoot":"","sources":["../../src/issues/sourceRevision.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"sourceRevision.js","sourceRoot":"","sources":["../../src/issues/sourceRevision.ts"],"names":[],"mappings":"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"}
|
package/dist/issues/store.js
CHANGED
|
@@ -1,18 +1,24 @@
|
|
|
1
|
-
// SWIPIUM Issue Log
|
|
1
|
+
// SWIPIUM Issue Log: persistence.
|
|
2
2
|
//
|
|
3
|
-
// `.swipium/issues-log.jsonl`
|
|
4
|
-
// `.swipium/issues/index.json`
|
|
5
|
-
// `.swipium/issues/policy.json`
|
|
6
|
-
// `.swipium/issues/artifacts/`
|
|
3
|
+
// `.swipium/issues-log.jsonl` : canonical, append-only event ledger. NEVER pruned by default.
|
|
4
|
+
// `.swipium/issues/index.json` : derived cache, rebuildable from the log if deleted/corrupt.
|
|
5
|
+
// `.swipium/issues/policy.json` : classifier + retention + source-revision policy.
|
|
6
|
+
// `.swipium/issues/artifacts/` : large evidence files (may follow normal retention).
|
|
7
7
|
//
|
|
8
8
|
// The log is the source of truth: the index is always recomputable via rebuildRecords(). Writes are
|
|
9
|
-
// append-only for events and atomic (temp + rename) for the index. Best-effort I/O
|
|
10
|
-
// degrade to a rebuild, never throw on read.
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
// append-only for events and atomic (unique temp + rename) for the index. Best-effort I/O: corrupt
|
|
10
|
+
// files degrade to a rebuild, never throw on read.
|
|
11
|
+
//
|
|
12
|
+
// Concurrency: several MCP server instances (and the CI CLI) can share one project. Every
|
|
13
|
+
// read-modify-write of the ledger runs under withLedgerLock(), and the cached index records the
|
|
14
|
+
// log's size/mtime it was derived from. A cache whose stamp no longer matches the log (another
|
|
15
|
+
// process appended) is rebuilt instead of trusted.
|
|
16
|
+
import { randomUUID } from 'node:crypto';
|
|
17
|
+
import { appendFileSync, existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync } from 'node:fs';
|
|
13
18
|
import { join } from 'node:path';
|
|
14
19
|
import { ensureGitignored } from '../lib/gitignore.js';
|
|
15
|
-
import {
|
|
20
|
+
import { withFileLock } from '../lib/lockfile.js';
|
|
21
|
+
import { liftSuppression, rebuildRecords, suppressionExpired } from './recurrence.js';
|
|
16
22
|
import { ISSUE_SCHEMA_VERSION, emptyIndex, validateEvent } from './schema.js';
|
|
17
23
|
const SWIPIUM = '.swipium';
|
|
18
24
|
export function issuesLogPath(root) {
|
|
@@ -30,18 +36,12 @@ export function issuesPolicyPath(root) {
|
|
|
30
36
|
export function issuesArtifactsDir(root) {
|
|
31
37
|
return join(issuesDir(root), 'artifacts');
|
|
32
38
|
}
|
|
33
|
-
export function issuesProjectId(root) {
|
|
34
|
-
return createHash('sha256').update(root).digest('hex').slice(0, 16);
|
|
35
|
-
}
|
|
36
|
-
export function issuesResourceUri(root) {
|
|
37
|
-
return `swipium://project/${issuesProjectId(root)}/issues`;
|
|
38
|
-
}
|
|
39
39
|
export const DEFAULT_POLICY = {
|
|
40
40
|
schemaVersion: 1,
|
|
41
41
|
allowGitMetadataRead: false,
|
|
42
42
|
retention: { keepIssueEvents: 'forever', pruneEvidenceAfterDays: 90 },
|
|
43
43
|
};
|
|
44
|
-
/** Load the policy file, merged over defaults. Best-effort
|
|
44
|
+
/** Load the policy file, merged over defaults. Best-effort: corrupt file > defaults. */
|
|
45
45
|
export function loadPolicy(root) {
|
|
46
46
|
try {
|
|
47
47
|
const path = issuesPolicyPath(root);
|
|
@@ -77,7 +77,7 @@ export function readEvents(root) {
|
|
|
77
77
|
out.push(ev);
|
|
78
78
|
}
|
|
79
79
|
catch {
|
|
80
|
-
/* skip a corrupt line
|
|
80
|
+
/* skip a corrupt line; the log stays usable */
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
83
|
return out;
|
|
@@ -91,19 +91,85 @@ export function appendEvents(root, events) {
|
|
|
91
91
|
const path = issuesLogPath(root);
|
|
92
92
|
const payload = events.map((e) => JSON.stringify(e)).join('\n') + '\n';
|
|
93
93
|
appendFileSync(path, payload);
|
|
94
|
+
// Retention (policy.retention.pruneEvidenceAfterDays, default 90): large evidence files under
|
|
95
|
+
// .swipium/issues/artifacts/ older than N days are pruned on ledger write. The append-only event
|
|
96
|
+
// log itself is never pruned here (keepIssueEvents).
|
|
97
|
+
pruneEvidence(root, loadPolicy(root).retention?.pruneEvidenceAfterDays);
|
|
94
98
|
return { path, count: events.length };
|
|
95
99
|
}
|
|
96
|
-
/**
|
|
97
|
-
|
|
100
|
+
/** Delete evidence files under `.swipium/issues/artifacts/` whose mtime is older than `days`
|
|
101
|
+
* (recursively; emptied sub-dirs removed). `days` ≤ 0 / non-finite = disabled. Best-effort: returns
|
|
102
|
+
* the number of files deleted and never throws. */
|
|
103
|
+
export function pruneEvidence(root, days, now = Date.now()) {
|
|
104
|
+
if (typeof days !== 'number' || !Number.isFinite(days) || days <= 0)
|
|
105
|
+
return 0;
|
|
106
|
+
const cutoff = now - days * 24 * 60 * 60 * 1000;
|
|
107
|
+
let deleted = 0;
|
|
108
|
+
const walk = (dir) => {
|
|
109
|
+
let entries;
|
|
110
|
+
try {
|
|
111
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
let remaining = entries.length;
|
|
117
|
+
for (const e of entries) {
|
|
118
|
+
const p = join(dir, e.name);
|
|
119
|
+
try {
|
|
120
|
+
if (e.isDirectory()) {
|
|
121
|
+
if (walk(p)) {
|
|
122
|
+
rmSync(p, { recursive: true, force: true });
|
|
123
|
+
remaining--;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
else if (statSync(p).mtimeMs < cutoff) {
|
|
127
|
+
rmSync(p, { force: true });
|
|
128
|
+
deleted++;
|
|
129
|
+
remaining--;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
/* vanished / unreadable, skip */
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return remaining === 0; // caller may remove an emptied sub-dir
|
|
137
|
+
};
|
|
138
|
+
walk(issuesArtifactsDir(root));
|
|
139
|
+
return deleted;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Run a ledger read-modify-write under the project's cross-process issue lock
|
|
143
|
+
* (`.swipium/issues/.lock`). NOT re-entrant: call it once at the outermost mutation.
|
|
144
|
+
*/
|
|
145
|
+
export function withLedgerLock(root, fn) {
|
|
146
|
+
mkdirSync(issuesDir(root), { recursive: true });
|
|
147
|
+
return withFileLock(join(issuesDir(root), '.lock'), fn);
|
|
148
|
+
}
|
|
149
|
+
/** Size + mtime of the canonical log, or null when absent. */
|
|
150
|
+
function logStamp(root) {
|
|
151
|
+
try {
|
|
152
|
+
const st = statSync(issuesLogPath(root));
|
|
153
|
+
return { logSize: st.size, logMtimeMs: st.mtimeMs };
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/** Atomically write the derived index (unique temp + rename), stamped with the log's size/mtime. */
|
|
160
|
+
export function saveIndex(root, index, stamp = logStamp(root)) {
|
|
98
161
|
mkdirSync(issuesDir(root), { recursive: true });
|
|
99
162
|
ensureGitignored(root);
|
|
100
163
|
const path = issuesIndexPath(root);
|
|
101
|
-
|
|
164
|
+
if (stamp)
|
|
165
|
+
Object.assign(index, stamp);
|
|
166
|
+
// Unique per writer: two processes sharing `index.json.tmp` could rename each other's half-file.
|
|
167
|
+
const tmp = `${path}.${process.pid}.${randomUUID().slice(0, 8)}.tmp`;
|
|
102
168
|
writeFileSync(tmp, JSON.stringify(index, null, 2));
|
|
103
169
|
renameSync(tmp, path);
|
|
104
|
-
return { path
|
|
170
|
+
return { path };
|
|
105
171
|
}
|
|
106
|
-
/** Load the index from disk; null when absent/corrupt (caller should rebuild). */
|
|
172
|
+
/** Load the index from disk; null when absent/corrupt/stale versus the log (caller should rebuild). */
|
|
107
173
|
export function loadIndex(root) {
|
|
108
174
|
try {
|
|
109
175
|
const path = issuesIndexPath(root);
|
|
@@ -112,6 +178,10 @@ export function loadIndex(root) {
|
|
|
112
178
|
const raw = JSON.parse(readFileSync(path, 'utf8'));
|
|
113
179
|
if (raw.schemaVersion !== ISSUE_SCHEMA_VERSION || !Array.isArray(raw.records))
|
|
114
180
|
return null;
|
|
181
|
+
// Stale check: another process appended since this cache was written (or it predates stamps).
|
|
182
|
+
const stamp = logStamp(root);
|
|
183
|
+
if (stamp && (raw.logSize !== stamp.logSize || raw.logMtimeMs !== stamp.logMtimeMs))
|
|
184
|
+
return null;
|
|
115
185
|
return raw;
|
|
116
186
|
}
|
|
117
187
|
catch {
|
|
@@ -120,22 +190,30 @@ export function loadIndex(root) {
|
|
|
120
190
|
}
|
|
121
191
|
/** Rebuild the index from the canonical log and persist it. The log is always authoritative. */
|
|
122
192
|
export function rebuildIndex(root, now, appId) {
|
|
193
|
+
// Stamp BEFORE reading: this may run outside the ledger lock (read paths), and a stamp taken after
|
|
194
|
+
// a concurrent append would bless records that don't include it. An early stamp only ever makes
|
|
195
|
+
// the cache look stale (one extra rebuild), never fresher than it is.
|
|
196
|
+
const stamp = logStamp(root);
|
|
123
197
|
const events = readEvents(root);
|
|
124
198
|
const records = rebuildRecords(events);
|
|
125
199
|
const index = { schemaVersion: ISSUE_SCHEMA_VERSION, updatedAt: now, appId, records };
|
|
126
|
-
if (events.length > 0)
|
|
127
|
-
|
|
200
|
+
if (events.length > 0) {
|
|
201
|
+
try {
|
|
202
|
+
saveIndex(root, index, stamp);
|
|
203
|
+
}
|
|
204
|
+
catch {
|
|
205
|
+
/* cache write is best-effort; the log stays authoritative */
|
|
206
|
+
}
|
|
207
|
+
}
|
|
128
208
|
return index;
|
|
129
209
|
}
|
|
130
210
|
/** Get the current index, rebuilding from the log when the cache is missing/stale/corrupt. */
|
|
131
211
|
export function getIndex(root, now, appId) {
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
return emptyIndex(now, appId);
|
|
138
|
-
return rebuildIndex(root, now, appId);
|
|
212
|
+
const index = loadIndex(root) ?? (readEvents(root).length === 0 ? emptyIndex(now, appId) : rebuildIndex(root, now, appId));
|
|
213
|
+
// Enforce `suppressedUntil`: an expired suppression is shown in its pre-suppression lane from
|
|
214
|
+
// `now` on (the next event on the issue makes that durable in the log, see foldEvent).
|
|
215
|
+
index.records = index.records.map((r) => (suppressionExpired(r, now) ? liftSuppression(r) : r));
|
|
216
|
+
return index;
|
|
139
217
|
}
|
|
140
218
|
/**
|
|
141
219
|
* Count events already in the log for an issue. Used to allocate a monotonic per-issue sequence so
|
package/dist/issues/store.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/issues/store.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/issues/store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// Per-call cancellation scope. The session driver is shared between a background job and the
|
|
2
|
+
// interactive tool calls made while it runs, so a cancellation signal must travel with the CALL,
|
|
3
|
+
// not live in a mutable slot on the driver: AsyncLocalStorage carries it through every await.
|
|
4
|
+
// Jobs run their work inside runWithSignal(jobSignal); interactive tools inside
|
|
5
|
+
// runWithSignal(extra.signal). Drivers read currentSignal() when they spawn adb or fetch WDA.
|
|
6
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
7
|
+
const scope = new AsyncLocalStorage();
|
|
8
|
+
/** Run `fn` with `signal` as the current cancellation signal (replacing any outer one: a job's
|
|
9
|
+
* signal never leaks into an interactive call made from its context, and vice versa). */
|
|
10
|
+
export function runWithSignal(signal, fn) {
|
|
11
|
+
return scope.run(signal, fn);
|
|
12
|
+
}
|
|
13
|
+
/** The cancellation signal of the call currently executing, if any. */
|
|
14
|
+
export function currentSignal() {
|
|
15
|
+
return scope.getStore();
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Is `e` the result of a CANCELLATION rather than a real failure? True when the error (or any
|
|
19
|
+
* error in its `cause` chain) is an AbortError / has code ABORT_ERR, or when the current call's
|
|
20
|
+
* cancellation signal (abortScope) has fired. Drivers wrap aborted adb/WDA calls in their own
|
|
21
|
+
* messages ("uiautomator dump failed … AbortError", "WDA GET /source aborted (cancelled)"), so the
|
|
22
|
+
* signal is the authoritative check.
|
|
23
|
+
*
|
|
24
|
+
* Every place that converts an error into a finding, toolError, snapshotFailure, health verdict or
|
|
25
|
+
* mode switch must check this first and return a CANCELLED result instead: cancelled work is not
|
|
26
|
+
* evidence about the app or the tool.
|
|
27
|
+
*/
|
|
28
|
+
export function isAbortError(e, signal = currentSignal()) {
|
|
29
|
+
if (signal?.aborted)
|
|
30
|
+
return true;
|
|
31
|
+
let cur = e;
|
|
32
|
+
for (let depth = 0; cur && depth < 6; depth++) {
|
|
33
|
+
const err = cur;
|
|
34
|
+
if (err.name === 'AbortError' || err.name === 'CancelledError' || err.code === 'ABORT_ERR')
|
|
35
|
+
return true;
|
|
36
|
+
cur = err.cause;
|
|
37
|
+
}
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
/** Thrown by long-running work (e.g. the explore runner) to unwind a cancelled step without
|
|
41
|
+
* recording it as a failure. */
|
|
42
|
+
export class CancelledError extends Error {
|
|
43
|
+
constructor(message = 'cancelled') {
|
|
44
|
+
super(message);
|
|
45
|
+
this.name = 'CancelledError';
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=abortScope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"abortScope.js","sourceRoot":"","sources":["../../src/lib/abortScope.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,iGAAiG;AACjG,8FAA8F;AAC9F,gFAAgF;AAChF,8FAA8F;AAE9F,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD,MAAM,KAAK,GAAG,IAAI,iBAAiB,EAA2B,CAAC;AAE/D;0FAC0F;AAC1F,MAAM,UAAU,aAAa,CAAI,MAA+B,EAAE,EAAW;IAC3E,OAAO,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAC/B,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,aAAa;IAC3B,OAAO,KAAK,CAAC,QAAQ,EAAE,CAAC;AAC1B,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,YAAY,CAAC,CAAU,EAAE,SAAkC,aAAa,EAAE;IACxF,IAAI,MAAM,EAAE,OAAO;QAAE,OAAO,IAAI,CAAC;IACjC,IAAI,GAAG,GAAY,CAAC,CAAC;IACrB,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,GAAG,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC;QAC9C,MAAM,GAAG,GAAG,GAA0D,CAAC;QACvE,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,IAAI,GAAG,CAAC,IAAI,KAAK,gBAAgB,IAAI,GAAG,CAAC,IAAI,KAAK,WAAW;YAAE,OAAO,IAAI,CAAC;QACxG,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC;IAClB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;iCACiC;AACjC,MAAM,OAAO,cAAe,SAAQ,KAAK;IACvC,YAAY,OAAO,GAAG,WAAW;QAC/B,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF"}
|
package/dist/lib/android.js
CHANGED
|
@@ -2,11 +2,80 @@
|
|
|
2
2
|
import { spawn } from 'node:child_process';
|
|
3
3
|
import { existsSync, readdirSync, statSync } from 'node:fs';
|
|
4
4
|
import { homedir } from 'node:os';
|
|
5
|
-
import { join } from 'node:path';
|
|
5
|
+
import { delimiter, join } from 'node:path';
|
|
6
6
|
import { run } from './spawn.js';
|
|
7
|
+
import { registerManagedProcess } from '../session/processRegistry.js';
|
|
7
8
|
const MIN_APK_BYTES = 1024 * 1024;
|
|
9
|
+
/** Android Studio's default SDK location for a host OS (used when no env var points at an SDK). */
|
|
10
|
+
export function defaultAndroidSdkDir(platform = process.platform, home = homedir(), env = process.env) {
|
|
11
|
+
if (platform === 'darwin')
|
|
12
|
+
return join(home, 'Library', 'Android', 'sdk');
|
|
13
|
+
if (platform === 'win32')
|
|
14
|
+
return join(env.LOCALAPPDATA || join(home, 'AppData', 'Local'), 'Android', 'Sdk');
|
|
15
|
+
return join(home, 'Android', 'Sdk'); // Linux and other unixes
|
|
16
|
+
}
|
|
17
|
+
/** Candidate SDK roots in priority order: $ANDROID_HOME, $ANDROID_SDK_ROOT, then the OS default. */
|
|
18
|
+
export function androidSdkCandidates(env = process.env, platform = process.platform, home = homedir()) {
|
|
19
|
+
const out = [];
|
|
20
|
+
for (const p of [env.ANDROID_HOME, env.ANDROID_SDK_ROOT, defaultAndroidSdkDir(platform, home, env)]) {
|
|
21
|
+
if (p && p.trim() && !out.includes(p.trim()))
|
|
22
|
+
out.push(p.trim());
|
|
23
|
+
}
|
|
24
|
+
return out;
|
|
25
|
+
}
|
|
8
26
|
export function androidHome() {
|
|
9
|
-
|
|
27
|
+
const candidates = androidSdkCandidates();
|
|
28
|
+
return candidates.find((d) => existsSync(d)) ?? candidates[0];
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Resolve an Android SDK tool (`adb` > platform-tools/adb, `emulator` > emulator/emulator)
|
|
32
|
+
* from the SDK candidates BEFORE falling back to PATH. GUI MCP clients (Claude Desktop,
|
|
33
|
+
* Cursor launched from the Dock) don't inherit the shell PATH, so a bare `adb` often fails
|
|
34
|
+
* there even though Android Studio installed it. Returns the absolute path, or the bare name
|
|
35
|
+
* (PATH lookup) when no SDK copy exists.
|
|
36
|
+
*/
|
|
37
|
+
export function resolveAndroidTool(tool, env = process.env, platform = process.platform, home = homedir(), exists = existsSync) {
|
|
38
|
+
const sub = tool === 'adb' ? 'platform-tools' : 'emulator';
|
|
39
|
+
const file = platform === 'win32' ? `${tool}.exe` : tool;
|
|
40
|
+
for (const sdk of androidSdkCandidates(env, platform, home)) {
|
|
41
|
+
const p = join(sdk, sub, file);
|
|
42
|
+
if (exists(p))
|
|
43
|
+
return p;
|
|
44
|
+
}
|
|
45
|
+
return tool;
|
|
46
|
+
}
|
|
47
|
+
/** Whether an executable named `file` exists in one of the PATH `dirs`. */
|
|
48
|
+
function onPath(file, dirs, exists) {
|
|
49
|
+
return dirs.some((d) => exists(join(d, file)));
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* APPEND existing SDK tool dirs (platform-tools, emulator) to this process's PATH (only for a
|
|
53
|
+
* tool that is NOT already resolvable on PATH), so every `run('adb', …)` /
|
|
54
|
+
* `spawn('emulator', …)` call site, and `which`, can find the SDK copy in GUI clients whose
|
|
55
|
+
* PATH lacks it, without ever shadowing the user's own adb/emulator (a different adb version
|
|
56
|
+
* than the one the user's adb server runs would kill that server). Idempotent. Returns the dirs
|
|
57
|
+
* added. Called once at CLI/server startup (src/index.ts, src/server.ts).
|
|
58
|
+
*/
|
|
59
|
+
export function ensureAndroidToolsOnPath(env = process.env, platform = process.platform, home = homedir(), exists = existsSync) {
|
|
60
|
+
const sep = platform === 'win32' ? ';' : platform === process.platform ? delimiter : ':';
|
|
61
|
+
// Windows env keys are case-insensitive but Node exposes the original casing (often "Path").
|
|
62
|
+
const key = Object.keys(env).find((k) => k.toUpperCase() === 'PATH') ?? 'PATH';
|
|
63
|
+
const current = (env[key] ?? '').split(sep).filter(Boolean);
|
|
64
|
+
const add = [];
|
|
65
|
+
for (const tool of ['adb', 'emulator']) {
|
|
66
|
+
const file = platform === 'win32' ? `${tool}.exe` : tool;
|
|
67
|
+
if (onPath(file, current, exists))
|
|
68
|
+
continue; // the user's own copy wins
|
|
69
|
+
const resolved = resolveAndroidTool(tool, env, platform, home, exists);
|
|
70
|
+
if (resolved === tool)
|
|
71
|
+
continue;
|
|
72
|
+
const dir = join(resolved, '..');
|
|
73
|
+
if (!current.includes(dir) && !add.includes(dir))
|
|
74
|
+
add.push(dir);
|
|
75
|
+
}
|
|
76
|
+
if (add.length)
|
|
77
|
+
env[key] = [...current, ...add].join(sep);
|
|
78
|
+
return add;
|
|
10
79
|
}
|
|
11
80
|
export function findAapt2() {
|
|
12
81
|
const bt = join(androidHome(), 'build-tools');
|
|
@@ -60,7 +129,7 @@ export function resolveApk(projectRoot, explicit) {
|
|
|
60
129
|
/**
|
|
61
130
|
* Boot an AVD headless. Returns the ChildProcess so the caller can `kill()` it on cancel.
|
|
62
131
|
* We `unref()` it so a running emulator does NOT keep the MCP process alive after the
|
|
63
|
-
* client disconnects (unref does not prevent kill
|
|
132
|
+
* client disconnects (unref does not prevent kill; the caller still holds the handle).
|
|
64
133
|
* `detached:true` + `stdio:'ignore'` so it survives an intentional server exit as an
|
|
65
134
|
* orphan rather than being torn down mid-run. NOTE: deliberate session/shutdown teardown
|
|
66
135
|
* (track + kill booted emulators on session-close) is a follow-up lifecycle pass.
|
|
@@ -69,8 +138,11 @@ export function bootEmulator(avd, headless = true) {
|
|
|
69
138
|
const args = ['-avd', avd, '-no-audio', '-no-snapshot', '-no-boot-anim', '-gpu', 'swiftshader_indirect'];
|
|
70
139
|
if (headless)
|
|
71
140
|
args.push('-no-window'); // omit for a visible window (local supervised QA)
|
|
72
|
-
const child = spawn('emulator', args, { detached: true, stdio: 'ignore' });
|
|
141
|
+
const child = spawn(resolveAndroidTool('emulator'), args, { detached: true, stdio: 'ignore' });
|
|
73
142
|
child.unref();
|
|
143
|
+
// Tracked for crash visibility only: the orphan reaper ADOPTS emulators (never kills them),
|
|
144
|
+
// since an orphaned emulator stays booted and remains usable via adb for the next run.
|
|
145
|
+
registerManagedProcess(child.pid, 'emulator');
|
|
74
146
|
return child;
|
|
75
147
|
}
|
|
76
148
|
/** Free bytes on the device /data partition (parsed from `df`), or null. */
|
|
@@ -80,7 +152,7 @@ export async function deviceFreeDataBytes(serial) {
|
|
|
80
152
|
const lines = r.stdout.trim().split('\n').filter(Boolean);
|
|
81
153
|
const data = lines[lines.length - 1]; // the mount row
|
|
82
154
|
const cols = data.trim().split(/\s+/);
|
|
83
|
-
// Filesystem 1K-blocks Used Available Use% Mounted
|
|
155
|
+
// Filesystem 1K-blocks Used Available Use% Mounted > Available is index 3
|
|
84
156
|
const availKb = Number(cols[3]);
|
|
85
157
|
return Number.isFinite(availKb) ? availKb * 1024 : null;
|
|
86
158
|
}
|
|
@@ -92,7 +164,11 @@ export async function deviceFreeDataBytes(serial) {
|
|
|
92
164
|
export async function deviceAbis(serial) {
|
|
93
165
|
try {
|
|
94
166
|
const r = await run('adb', ['-s', serial, 'shell', 'getprop', 'ro.product.cpu.abilist'], { timeoutMs: 5000 });
|
|
95
|
-
return r.stdout
|
|
167
|
+
return r.stdout
|
|
168
|
+
.trim()
|
|
169
|
+
.split(',')
|
|
170
|
+
.map((s) => s.trim())
|
|
171
|
+
.filter(Boolean);
|
|
96
172
|
}
|
|
97
173
|
catch {
|
|
98
174
|
return [];
|
|
@@ -152,7 +228,7 @@ export async function deviceSdk(serial) {
|
|
|
152
228
|
return null;
|
|
153
229
|
}
|
|
154
230
|
}
|
|
155
|
-
/** PURE: is an APK's minSdk satisfied by a device API level? Unknown values
|
|
231
|
+
/** PURE: is an APK's minSdk satisfied by a device API level? Unknown values > compatible (don't block on missing info). */
|
|
156
232
|
export function minSdkCompatible(apkMinSdk, deviceApiLevel) {
|
|
157
233
|
if (apkMinSdk == null || deviceApiLevel == null)
|
|
158
234
|
return true;
|
|
@@ -175,7 +251,7 @@ export function classifyAndroidInstallError(message) {
|
|
|
175
251
|
return 'INSTALL_FAILED';
|
|
176
252
|
return 'INSTALL_FAILED';
|
|
177
253
|
}
|
|
178
|
-
/** Native ABIs an APK ships (empty = pure/no native code
|
|
254
|
+
/** Native ABIs an APK ships (empty = pure/no native code > installs on any ABI). */
|
|
179
255
|
export async function apkNativeAbis(apk) {
|
|
180
256
|
const aapt2 = findAapt2();
|
|
181
257
|
if (!aapt2)
|