swipium 1.5.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 +171 -0
- package/README.md +173 -280
- package/THREAT_MODEL.md +223 -47
- package/dist/appMap/automationLink.js +30 -27
- package/dist/appMap/automationLink.js.map +1 -1
- package/dist/appMap/build.js +47 -21
- package/dist/appMap/build.js.map +1 -1
- package/dist/appMap/codeIndex.js +2 -2
- package/dist/appMap/codeIndex.js.map +1 -1
- package/dist/appMap/featureIndex.js +3 -3
- package/dist/appMap/featureIndex.js.map +1 -1
- package/dist/appMap/featureModel.js +2 -2
- package/dist/appMap/featureModel.js.map +1 -1
- package/dist/appMap/firstRunApply.js +2 -2
- package/dist/appMap/firstRunApply.js.map +1 -1
- package/dist/appMap/issues.js +10 -10
- package/dist/appMap/issues.js.map +1 -1
- package/dist/appMap/migrations.js +5 -5
- 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 +77 -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 +2 -2
- package/dist/appMap/query.js.map +1 -1
- package/dist/appMap/runtimeMerge.js +3 -3
- 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 +1 -1
- package/dist/appMap/screenMatch.js.map +1 -1
- package/dist/appMap/staticScan.js +17 -17
- package/dist/appMap/staticScan.js.map +1 -1
- package/dist/appMap/store.js +55 -7
- package/dist/appMap/store.js.map +1 -1
- package/dist/appMap/tsAstScan.js +3 -3
- package/dist/appMap/tsAstScan.js.map +1 -1
- package/dist/artifacts/bundletool.js +5 -5
- package/dist/artifacts/bundletool.js.map +1 -1
- package/dist/artifacts/resolve.js +10 -10
- package/dist/artifacts/resolve.js.map +1 -1
- package/dist/automation/capabilities.js +3 -3
- package/dist/automation/capabilities.js.map +1 -1
- package/dist/automation/gestures.js +1 -1
- package/dist/automation/gestures.js.map +1 -1
- package/dist/automation/plan.js +7 -7
- package/dist/automation/plan.js.map +1 -1
- package/dist/automation/report.js +3 -3
- package/dist/automation/report.js.map +1 -1
- package/dist/automation/selectors.js +14 -25
- 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 +5 -5
- package/dist/automation/waits.js.map +1 -1
- package/dist/automation/webview.js +2 -2
- package/dist/automation/webview.js.map +1 -1
- package/dist/automationGen/appiumModel.js +13 -7
- package/dist/automationGen/appiumModel.js.map +1 -1
- package/dist/automationGen/ciEmitter.js +5 -5
- 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 +265 -106
- 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 +71 -26
- package/dist/automationGen/projectProfile.js.map +1 -1
- package/dist/automationGen/pythonEmitter.js +276 -105
- 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/{tools/automationGenerate.js → automationGen/run.js} +72 -113
- package/dist/automationGen/run.js.map +1 -0
- package/dist/automationGen/suitePlan.js +6 -4
- package/dist/automationGen/suitePlan.js.map +1 -1
- package/dist/automationGen/validation.js +20 -8
- package/dist/automationGen/validation.js.map +1 -1
- package/dist/build/parseBuildLog.js +2 -2
- package/dist/build/parseBuildLog.js.map +1 -1
- package/dist/build/plan.js +7 -7
- 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 +35 -14
- package/dist/cli/scan.js.map +1 -1
- package/dist/cli/suite.js +6 -6
- 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 +45 -14
- package/dist/context/detect.js.map +1 -1
- package/dist/context/findApps.js +6 -6
- 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 +3 -3
- package/dist/core/target.js.map +1 -1
- package/dist/core/targetPlan.js +65 -62
- package/dist/core/targetPlan.js.map +1 -1
- package/dist/drivers/DirectDriver.js +300 -36
- package/dist/drivers/DirectDriver.js.map +1 -1
- package/dist/drivers/SimctlDriver.js +120 -7
- package/dist/drivers/SimctlDriver.js.map +1 -1
- package/dist/drivers/WdaDriver.js +350 -50
- package/dist/drivers/WdaDriver.js.map +1 -1
- package/dist/explore/candidates.js +2 -2
- package/dist/explore/candidates.js.map +1 -1
- package/dist/explore/graph.js +5 -5
- package/dist/explore/graph.js.map +1 -1
- package/dist/explore/policy.js +5 -5
- package/dist/explore/policy.js.map +1 -1
- package/dist/explore/runner.js +301 -284
- package/dist/explore/runner.js.map +1 -1
- package/dist/explore/signatures.js +1 -1
- package/dist/featureTesting/executionBootstrap.js +29 -30
- package/dist/featureTesting/executionBootstrap.js.map +1 -1
- package/dist/featureTesting/featureMap.js +2 -2
- package/dist/featureTesting/featureMap.js.map +1 -1
- package/dist/featureTesting/featureScope.js +12 -12
- package/dist/featureTesting/featureScope.js.map +1 -1
- package/dist/featureTesting/mapFeatureScope.js +7 -7
- package/dist/featureTesting/mapFeatureScope.js.map +1 -1
- package/dist/featureTesting/objectiveModel.js +10 -10
- package/dist/featureTesting/objectiveModel.js.map +1 -1
- package/dist/featureTesting/resultMerge.js +6 -6
- package/dist/featureTesting/resultMerge.js.map +1 -1
- package/dist/featureTesting/sources.js +4 -4
- package/dist/featureTesting/sources.js.map +1 -1
- package/dist/featureTesting/suiteBridge.js +1 -1
- package/dist/featureTesting/suiteBridge.js.map +1 -1
- package/dist/featureTesting/synonyms.js +1 -1
- package/dist/featureTesting/synonyms.js.map +1 -1
- package/dist/featureTesting/testCaseFactory.js +11 -11
- package/dist/featureTesting/testCaseFactory.js.map +1 -1
- package/dist/featureTesting/testPlan.js +3 -3
- 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 +5 -5
- package/dist/firstRun/classifyScreen.js.map +1 -1
- package/dist/firstRun/firstRunPlanner.js +11 -11
- package/dist/firstRun/firstRunPlanner.js.map +1 -1
- package/dist/firstRun/firstRunRunner.js +8 -8
- package/dist/firstRun/firstRunRunner.js.map +1 -1
- package/dist/firstRun/generatedDataPolicy.js +9 -9
- package/dist/firstRun/generatedDataPolicy.js.map +1 -1
- package/dist/firstRun/inputPlanner.js +5 -5
- 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 +33 -3
- 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 +20 -10
- package/dist/flows/generate.js.map +1 -1
- package/dist/flows/pack.js +3 -3
- 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 +111 -23
- package/dist/flows/repair.js.map +1 -1
- package/dist/flows/run.js +153 -57
- package/dist/flows/run.js.map +1 -1
- package/dist/flows/schema.js +50 -5
- package/dist/flows/schema.js.map +1 -1
- package/dist/flows/seedExec.js +4 -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/issues/classify.js +16 -16
- package/dist/issues/classify.js.map +1 -1
- package/dist/issues/fingerprint.js +24 -4
- package/dist/issues/fingerprint.js.map +1 -1
- package/dist/issues/index.js +94 -31
- package/dist/issues/index.js.map +1 -1
- package/dist/issues/metrics.js +4 -4
- 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 +4 -4
- package/dist/issues/report.js.map +1 -1
- package/dist/issues/reportBridge.js +4 -4
- 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 +75 -7
- 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 +32 -7
- 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 +1 -1
- package/dist/lib/image.js.map +1 -1
- package/dist/lib/lockfile.js +370 -31
- package/dist/lib/lockfile.js.map +1 -1
- package/dist/lib/needsInput.js +3 -3
- package/dist/lib/needsInput.js.map +1 -1
- package/dist/lib/png.js +2 -2
- 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 +79 -10
- package/dist/lib/result.js.map +1 -1
- package/dist/lib/schemaHash.js +3 -3
- package/dist/lib/schemaHash.js.map +1 -1
- package/dist/lib/sensitive.js +3 -2
- 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 +52 -10
- 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 +294 -15
- package/dist/lib/wda.js.map +1 -1
- package/dist/mobileAudit/checks.js +12 -12
- 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 +1 -1
- package/dist/mobileAudit/profiles.js.map +1 -1
- package/dist/mobileAudit/results.js +3 -3
- package/dist/mobileAudit/results.js.map +1 -1
- package/dist/mobileAudit/runner.js +72 -18
- 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 +219 -36
- package/dist/oracle/failures.js.map +1 -1
- package/dist/oracle/health.js +63 -17
- package/dist/oracle/health.js.map +1 -1
- package/dist/oracle/locator.js +13 -13
- 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 +4 -4
- package/dist/orchestration/goal.js.map +1 -1
- package/dist/orchestration/testThis/execute.js +62 -21
- package/dist/orchestration/testThis/execute.js.map +1 -1
- package/dist/orchestration/testThis/pipeline.js +119 -30
- package/dist/orchestration/testThis/pipeline.js.map +1 -1
- package/dist/orchestration/testThis/plan.js +162 -73
- package/dist/orchestration/testThis/plan.js.map +1 -1
- package/dist/orchestration/testThis/sessionIntent.js +72 -0
- package/dist/orchestration/testThis/sessionIntent.js.map +1 -0
- package/dist/orchestration/testThis/terminal.js +34 -16
- package/dist/orchestration/testThis/terminal.js.map +1 -1
- package/dist/orchestration/testThis/types.js +1 -1
- package/dist/orchestration/testThis/types.js.map +1 -1
- package/dist/plan/plan.js +9 -9
- package/dist/plan/plan.js.map +1 -1
- package/dist/prompts/index.js +22 -22
- package/dist/prompts/index.js.map +1 -1
- package/dist/report/export.js +392 -37
- 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/policy.js +7 -4
- package/dist/report/policy.js.map +1 -1
- package/dist/report/qaLevel.js +8 -8
- package/dist/report/qaLevel.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/toolHealth.js +124 -0
- package/dist/report/toolHealth.js.map +1 -0
- package/dist/server.js +472 -45
- 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 +2 -2
- package/dist/services/build.js.map +1 -1
- package/dist/{tools → services}/flowGenerate.js +29 -13
- package/dist/services/flowGenerate.js.map +1 -0
- package/dist/services/preflight.js +4 -4
- package/dist/services/preflight.js.map +1 -1
- package/dist/services/prepareAndroid.js +46 -8
- package/dist/services/prepareAndroid.js.map +1 -1
- package/dist/services/prepareIos.js +24 -9
- package/dist/services/prepareIos.js.map +1 -1
- package/dist/services/report.js +100 -45
- package/dist/services/report.js.map +1 -1
- package/dist/services/smoke.js +32 -16
- package/dist/services/smoke.js.map +1 -1
- package/dist/services/suiteGenerate.js +28 -3
- package/dist/services/suiteGenerate.js.map +1 -1
- package/dist/services/testSuiteKnowledge.js +40 -27
- package/dist/services/testSuiteKnowledge.js.map +1 -1
- package/dist/session/attach.js +270 -6
- package/dist/session/attach.js.map +1 -1
- package/dist/session/processRegistry.js +317 -48
- package/dist/session/processRegistry.js.map +1 -1
- package/dist/session/progress.js +1 -1
- package/dist/session/retention.js +201 -0
- package/dist/session/retention.js.map +1 -0
- package/dist/session/store.js +275 -48
- package/dist/session/store.js.map +1 -1
- package/dist/snapshot/overlays.js +53 -8
- package/dist/snapshot/overlays.js.map +1 -1
- package/dist/snapshot/parse.js +28 -4
- package/dist/snapshot/parse.js.map +1 -1
- package/dist/snapshot/present.js +11 -5
- 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 +46 -2
- package/dist/state/profile.js.map +1 -1
- package/dist/suite/compile.js +9 -5
- package/dist/suite/compile.js.map +1 -1
- package/dist/suite/lint.js +4 -4
- package/dist/suite/lint.js.map +1 -1
- package/dist/suite/pom.js +50 -41
- 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 +9 -7
- package/dist/suite/testcase.js.map +1 -1
- package/dist/testSuite/exporter.js +4 -4
- package/dist/testSuite/exporter.js.map +1 -1
- package/dist/testSuite/generator.js +13 -9
- 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 +5 -5
- package/dist/testSuite/merge.js.map +1 -1
- package/dist/testSuite/schema.js +5 -5
- package/dist/testSuite/schema.js.map +1 -1
- package/dist/testSuite/store.js +3 -3
- 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 +794 -164
- package/dist/tools/act.js.map +1 -1
- package/dist/tools/agent.js +451 -128
- package/dist/tools/agent.js.map +1 -1
- package/dist/tools/appControl.js +69 -19
- package/dist/tools/appControl.js.map +1 -1
- package/dist/tools/appMap.js +188 -130
- package/dist/tools/appMap.js.map +1 -1
- package/dist/tools/build.js +32 -42
- package/dist/tools/build.js.map +1 -1
- package/dist/tools/bundletool.js +21 -31
- package/dist/tools/bundletool.js.map +1 -1
- package/dist/tools/clearOverlay.js +55 -12
- package/dist/tools/clearOverlay.js.map +1 -1
- package/dist/tools/device.js +76 -24
- package/dist/tools/device.js.map +1 -1
- package/dist/tools/doctor.js +68 -28
- package/dist/tools/doctor.js.map +1 -1
- package/dist/tools/explore.js +41 -47
- package/dist/tools/explore.js.map +1 -1
- package/dist/tools/featureTesting.js +31 -48
- package/dist/tools/featureTesting.js.map +1 -1
- package/dist/tools/firstRun.js +34 -41
- package/dist/tools/firstRun.js.map +1 -1
- package/dist/tools/flow.js +183 -103
- package/dist/tools/flow.js.map +1 -1
- package/dist/tools/flowRepair.js +25 -13
- package/dist/tools/flowRepair.js.map +1 -1
- package/dist/tools/generate.js +52 -89
- package/dist/tools/generate.js.map +1 -1
- package/dist/tools/getArtifact.js +16 -5
- package/dist/tools/getArtifact.js.map +1 -1
- package/dist/tools/health.js +15 -12
- package/dist/tools/health.js.map +1 -1
- package/dist/tools/ios.js +45 -223
- package/dist/tools/ios.js.map +1 -1
- package/dist/tools/issues.js +251 -35
- package/dist/tools/issues.js.map +1 -1
- package/dist/tools/jobs.js +41 -16
- package/dist/tools/jobs.js.map +1 -1
- package/dist/tools/metro.js +36 -35
- package/dist/tools/metro.js.map +1 -1
- package/dist/tools/mobileAudit.js +50 -45
- package/dist/tools/mobileAudit.js.map +1 -1
- package/dist/tools/network.js +31 -14
- package/dist/tools/network.js.map +1 -1
- package/dist/tools/note.js +26 -26
- package/dist/tools/note.js.map +1 -1
- package/dist/tools/prepareIosTarget.js +10 -16
- package/dist/tools/prepareIosTarget.js.map +1 -1
- package/dist/tools/prepareTarget.js +117 -50
- package/dist/tools/prepareTarget.js.map +1 -1
- package/dist/tools/report.js +11 -22
- package/dist/tools/report.js.map +1 -1
- package/dist/tools/resolveArtifact.js +11 -15
- package/dist/tools/resolveArtifact.js.map +1 -1
- package/dist/tools/resolveTarget.js +78 -24
- package/dist/tools/resolveTarget.js.map +1 -1
- package/dist/tools/screenRecord.js +23 -21
- package/dist/tools/screenRecord.js.map +1 -1
- package/dist/tools/screenshot.js +23 -16
- package/dist/tools/screenshot.js.map +1 -1
- package/dist/tools/smoke.js +20 -16
- package/dist/tools/smoke.js.map +1 -1
- package/dist/tools/snapshot.js +155 -118
- package/dist/tools/snapshot.js.map +1 -1
- package/dist/tools/startSession.js +104 -116
- package/dist/tools/startSession.js.map +1 -1
- package/dist/tools/suite.js +72 -43
- package/dist/tools/suite.js.map +1 -1
- package/dist/tools/testSuite.js +30 -20
- package/dist/tools/testSuite.js.map +1 -1
- package/dist/tools/testThis.js +24 -28
- package/dist/tools/testThis.js.map +1 -1
- package/dist/tools/visual.js +686 -210
- package/dist/tools/visual.js.map +1 -1
- package/dist/tools/wait.js +9 -38
- package/dist/tools/wait.js.map +1 -1
- package/dist/tools/wda.js +187 -57
- package/dist/tools/wda.js.map +1 -1
- package/dist/version.js +31 -22
- package/dist/version.js.map +1 -1
- package/dist/visual/ocr.js +53 -6
- package/dist/visual/ocr.js.map +1 -1
- package/dist/visual/provider.js +80 -12
- 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 +194 -128
- package/docs/physical-devices.md +84 -0
- package/docs/tools.md +812 -152
- package/package.json +3 -2
- package/dist/tools/assertVisual.js +0 -84
- package/dist/tools/assertVisual.js.map +0 -1
- package/dist/tools/automationGenerate.js.map +0 -1
- package/dist/tools/capabilities.js +0 -179
- 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.map +0 -1
- package/dist/tools/history.js +0 -86
- package/dist/tools/history.js.map +0 -1
- package/dist/tools/locator.js +0 -85
- package/dist/tools/locator.js.map +0 -1
- package/dist/tools/permissions.js +0 -174
- package/dist/tools/permissions.js.map +0 -1
- package/dist/tools/plan.js +0 -52
- package/dist/tools/plan.js.map +0 -1
- package/dist/tools/screenInfo.js +0 -76
- package/dist/tools/screenInfo.js.map +0 -1
- package/dist/tools/seed.js +0 -133
- package/dist/tools/seed.js.map +0 -1
- package/dist/tools/state.js +0 -217
- package/dist/tools/state.js.map +0 -1
- package/dist/tools/visualText.js +0 -106
- package/dist/tools/visualText.js.map +0 -1
package/dist/consent/consent.js
CHANGED
|
@@ -1,12 +1,84 @@
|
|
|
1
|
-
// Portable consent state machine
|
|
1
|
+
// Portable consent state machine. Works WITHOUT client elicitation:
|
|
2
2
|
// a privileged action returns { requiresConsent, consentId, ... }; the agent surfaces
|
|
3
3
|
// it, the user approves, and the same tool is re-called with { consentId, approve:true }.
|
|
4
|
+
//
|
|
5
|
+
// THREAT_MODEL: the re-call is made by the client, so a compromised client can self-approve.
|
|
6
|
+
// When the connected client advertises the MCP elicitation capability, server.ts installs an
|
|
7
|
+
// elicitation provider here and routes each pending consent through a REAL out-of-band user
|
|
8
|
+
// prompt (requestConsentDecision) before the envelope ever reaches the model. On such clients a
|
|
9
|
+
// declined, dismissed (`cancel`), timed-out or failed prompt is a REFUSAL. It never falls back
|
|
10
|
+
// to the model-mediated re-call. Which path decided an action is tagged as its
|
|
11
|
+
// ApprovalMechanism and lands in the mutation ledger.
|
|
4
12
|
import { randomUUID } from 'node:crypto';
|
|
13
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
14
|
+
// The calling tool invocation's sessionId, set once per call by the server's tool wrapper
|
|
15
|
+
// (src/server.ts) so every consent-gated tool is session-bound with zero per-tool changes.
|
|
16
|
+
const consentScope = new AsyncLocalStorage();
|
|
17
|
+
/** Run `fn` as part of a tool call made in `sessionId` (undefined = no session). */
|
|
18
|
+
export function runWithConsentScope(sessionId, fn) {
|
|
19
|
+
return consentScope.run({ sessionId: typeof sessionId === 'string' && sessionId ? sessionId : undefined }, fn);
|
|
20
|
+
}
|
|
21
|
+
function currentConsentSession() {
|
|
22
|
+
return consentScope.getStore()?.sessionId;
|
|
23
|
+
}
|
|
24
|
+
// Pending challenges are bounded (review §4): a consent that is never resumed must not live
|
|
25
|
+
// forever, and a client minting challenges in a loop must not grow the map without limit.
|
|
26
|
+
// TTL comfortably exceeds the elicitation timeout below so an in-flight prompt never expires.
|
|
27
|
+
export const CONSENT_TTL_MS = 30 * 60_000;
|
|
28
|
+
export const CONSENT_PENDING_CAP = 200;
|
|
5
29
|
const pending = new Map();
|
|
30
|
+
function prunePending(now = Date.now()) {
|
|
31
|
+
for (const [id, p] of pending) {
|
|
32
|
+
if (now - p.createdAt > CONSENT_TTL_MS)
|
|
33
|
+
forget(id);
|
|
34
|
+
}
|
|
35
|
+
// Map iteration order is insertion order, so the first keys are the oldest challenges.
|
|
36
|
+
while (pending.size > CONSENT_PENDING_CAP) {
|
|
37
|
+
const oldest = pending.keys().next().value;
|
|
38
|
+
if (oldest === undefined)
|
|
39
|
+
break;
|
|
40
|
+
forget(oldest);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function forget(consentId) {
|
|
44
|
+
pending.delete(consentId);
|
|
45
|
+
elicitationApproved.delete(consentId);
|
|
46
|
+
awaitingElicitation.delete(consentId);
|
|
47
|
+
}
|
|
48
|
+
let elicitationProvider;
|
|
49
|
+
/** Installed once at server construction (src/server.ts); undefined disables elicitation. */
|
|
50
|
+
export function setElicitationProvider(provider) {
|
|
51
|
+
elicitationProvider = provider;
|
|
52
|
+
}
|
|
53
|
+
// consentId > mechanism for approvals already consumed, so the mutation ledger can record
|
|
54
|
+
// HOW each privileged action was approved even at recording sites far from the gate
|
|
55
|
+
// (SessionStore.recordMutation reads this). Bounded like the ledger itself.
|
|
56
|
+
const consumedMechanisms = new Map();
|
|
57
|
+
const elicitationApproved = new Set();
|
|
58
|
+
// Challenges currently routed to (or decided by) an out-of-band prompt: a client re-call can
|
|
59
|
+
// never approve these. Only the elicitation answer can (no approve:true bypass).
|
|
60
|
+
const awaitingElicitation = new Set();
|
|
61
|
+
/** Mechanism that approved an already-consumed consentId (audit trail for the ledger). */
|
|
62
|
+
export function approvalMechanismFor(consentId) {
|
|
63
|
+
return consumedMechanisms.get(consentId);
|
|
64
|
+
}
|
|
65
|
+
/** The still-pending request behind a consentId (read-only; used to ledger a refusal). */
|
|
66
|
+
export function peekConsent(consentId) {
|
|
67
|
+
const p = pending.get(consentId);
|
|
68
|
+
if (!p || Date.now() - p.createdAt > CONSENT_TTL_MS)
|
|
69
|
+
return undefined;
|
|
70
|
+
return p.req;
|
|
71
|
+
}
|
|
72
|
+
/** Burn a pending challenge without approving it (e.g. the routed action changed under a prompt). */
|
|
73
|
+
export function burnConsent(consentId) {
|
|
74
|
+
forget(consentId);
|
|
75
|
+
}
|
|
6
76
|
/** Build the tool result that asks for consent. */
|
|
7
77
|
export function requireConsent(req) {
|
|
78
|
+
prunePending();
|
|
8
79
|
const consentId = randomUUID().slice(0, 8);
|
|
9
|
-
|
|
80
|
+
const sessionId = currentConsentSession();
|
|
81
|
+
pending.set(consentId, { req, createdAt: Date.now(), ...(sessionId ? { sessionId } : {}) });
|
|
10
82
|
const payload = { requiresConsent: true, consentId, ...req };
|
|
11
83
|
const text = `🔐 Consent required (${req.risk}): ${req.explain}\n` +
|
|
12
84
|
(req.exactCommand ? `Will run: ${req.exactCommand}\n` : '') +
|
|
@@ -16,6 +88,61 @@ export function requireConsent(req) {
|
|
|
16
88
|
'\n```';
|
|
17
89
|
return { content: [{ type: 'text', text }], structuredContent: payload };
|
|
18
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* Ask the connected client's HUMAN to decide a freshly-minted consent via MCP elicitation.
|
|
93
|
+
* - approved: the caller re-invokes the tool; consumeConsent tags mechanism 'elicitation'.
|
|
94
|
+
* - declined / cancelled (dismissed, timed out, transport error, aborted call): REFUSAL. The
|
|
95
|
+
* challenge is burned so the client cannot self-approve it afterwards (a re-call of the tool
|
|
96
|
+
* mints a fresh challenge and a fresh prompt).
|
|
97
|
+
* - unavailable (client does not advertise elicitation): portable re-call convention
|
|
98
|
+
* ('client-assertion'), unless SWIPIUM_REQUIRE_ELICITATION=1, in which case EVERY
|
|
99
|
+
* consent-gated action (builds, Metro, installs, data wipes, seeds…) is refused outright.
|
|
100
|
+
*/
|
|
101
|
+
export async function requestConsentDecision(consentId, ctx) {
|
|
102
|
+
const req = peekConsent(consentId);
|
|
103
|
+
if (!req)
|
|
104
|
+
return { mechanism: 'client-assertion' };
|
|
105
|
+
let answer = 'unavailable';
|
|
106
|
+
let failure;
|
|
107
|
+
if (elicitationProvider) {
|
|
108
|
+
awaitingElicitation.add(consentId);
|
|
109
|
+
try {
|
|
110
|
+
answer = await elicitationProvider(req, ctx);
|
|
111
|
+
}
|
|
112
|
+
catch (e) {
|
|
113
|
+
// The client advertised elicitation, so a throw here is a timeout / transport failure /
|
|
114
|
+
// aborted call / invalid answer while the prompt was outstanding: fail CLOSED.
|
|
115
|
+
answer = 'cancelled';
|
|
116
|
+
failure = e instanceof Error ? e.message : String(e);
|
|
117
|
+
}
|
|
118
|
+
if (answer === 'unavailable')
|
|
119
|
+
awaitingElicitation.delete(consentId);
|
|
120
|
+
}
|
|
121
|
+
if (answer === 'approved') {
|
|
122
|
+
elicitationApproved.add(consentId);
|
|
123
|
+
return { mechanism: 'elicitation', approved: true };
|
|
124
|
+
}
|
|
125
|
+
if (answer === 'declined' || answer === 'cancelled') {
|
|
126
|
+
forget(consentId);
|
|
127
|
+
return {
|
|
128
|
+
mechanism: 'elicitation',
|
|
129
|
+
approved: false,
|
|
130
|
+
outcome: answer,
|
|
131
|
+
reason: answer === 'declined'
|
|
132
|
+
? `User declined "${req.action}" in the consent prompt`
|
|
133
|
+
: `Consent prompt for "${req.action}" was dismissed or not answered${failure ? ` (${failure})` : ''}, treated as a refusal`,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
if (process.env.SWIPIUM_REQUIRE_ELICITATION === '1') {
|
|
137
|
+
forget(consentId);
|
|
138
|
+
return {
|
|
139
|
+
mechanism: 'refused',
|
|
140
|
+
reason: `SWIPIUM_REQUIRE_ELICITATION=1: "${req.action}" (risk ${req.risk}) needs an out-of-band user prompt, ` +
|
|
141
|
+
'but the connected client does not support MCP elicitation.',
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
return { mechanism: 'client-assertion' };
|
|
145
|
+
}
|
|
19
146
|
/**
|
|
20
147
|
* Validate a resume call. Consent is single-use AND bound to the exact action:
|
|
21
148
|
* `expected.action`/`expected.affects` must match what was originally requested, so an
|
|
@@ -24,9 +151,19 @@ export function requireConsent(req) {
|
|
|
24
151
|
export function consumeConsent(consentId, approve, expected) {
|
|
25
152
|
if (!consentId)
|
|
26
153
|
return { approved: false, reason: 'no consentId supplied' };
|
|
27
|
-
const
|
|
154
|
+
const entry = pending.get(consentId);
|
|
155
|
+
if (entry && Date.now() - entry.createdAt > CONSENT_TTL_MS) {
|
|
156
|
+
forget(consentId);
|
|
157
|
+
return { approved: false, reason: 'consent expired; re-call without consentId for a fresh challenge' };
|
|
158
|
+
}
|
|
159
|
+
const req = entry?.req;
|
|
28
160
|
if (!req)
|
|
29
161
|
return { approved: false, reason: 'unknown or already-used consentId' };
|
|
162
|
+
// Session binding: checked BEFORE consuming (like the action binding) so a cross-session replay
|
|
163
|
+
// attempt never burns the challenge for its real session.
|
|
164
|
+
if (entry.sessionId !== undefined && entry.sessionId !== currentConsentSession()) {
|
|
165
|
+
return { approved: false, req, reason: 'consent was issued for a different session' };
|
|
166
|
+
}
|
|
30
167
|
// Bind to the exact action/affects BEFORE consuming, so a mismatched id stays valid
|
|
31
168
|
// for its real use rather than being silently burned.
|
|
32
169
|
if (expected?.action && req.action !== expected.action) {
|
|
@@ -35,9 +172,29 @@ export function consumeConsent(consentId, approve, expected) {
|
|
|
35
172
|
if (expected?.affects && JSON.stringify(req.affects ?? {}) !== JSON.stringify(expected.affects)) {
|
|
36
173
|
return { approved: false, req, reason: 'consent does not match the affected target' };
|
|
37
174
|
}
|
|
38
|
-
|
|
175
|
+
const wasElicited = elicitationApproved.has(consentId);
|
|
176
|
+
const routed = awaitingElicitation.has(consentId);
|
|
177
|
+
forget(consentId);
|
|
39
178
|
if (!approve)
|
|
40
179
|
return { approved: false, req, reason: 'user did not approve' };
|
|
41
|
-
|
|
180
|
+
// A challenge routed to an out-of-band prompt can only be approved BY that prompt: a client
|
|
181
|
+
// re-call with approve:true (e.g. racing the dialog) must not bypass the human.
|
|
182
|
+
if (routed && !wasElicited)
|
|
183
|
+
return { approved: false, req, reason: 'consent is awaiting the out-of-band user prompt' };
|
|
184
|
+
const mechanism = wasElicited ? 'elicitation' : 'client-assertion';
|
|
185
|
+
recordMechanism(consentId, mechanism);
|
|
186
|
+
return { approved: true, req, mechanism };
|
|
187
|
+
}
|
|
188
|
+
function recordMechanism(consentId, mechanism) {
|
|
189
|
+
consumedMechanisms.set(consentId, mechanism);
|
|
190
|
+
if (consumedMechanisms.size > 500) {
|
|
191
|
+
const oldest = consumedMechanisms.keys().next().value;
|
|
192
|
+
if (oldest !== undefined)
|
|
193
|
+
consumedMechanisms.delete(oldest);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
/** Test/diagnostic view of the pending-challenge map size (bounded by CONSENT_PENDING_CAP). */
|
|
197
|
+
export function pendingConsentCount() {
|
|
198
|
+
return pending.size;
|
|
42
199
|
}
|
|
43
200
|
//# sourceMappingURL=consent.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"consent.js","sourceRoot":"","sources":["../../src/consent/consent.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"consent.js","sourceRoot":"","sources":["../../src/consent/consent.ts"],"names":[],"mappings":"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"}
|
package/dist/context/detect.js
CHANGED
|
@@ -1,9 +1,33 @@
|
|
|
1
|
-
// Detect the mobile project context under a resolved projectRoot
|
|
1
|
+
// Detect the mobile project context under a resolved projectRoot.
|
|
2
2
|
// Best-effort, file-marker based; never trusts cwd.
|
|
3
3
|
import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
|
|
4
4
|
import { join } from 'node:path';
|
|
5
5
|
import { which, firstLine, adbDevices, listAvds, findAapt2 } from '../lib/android.js';
|
|
6
6
|
import { resolveArtifact } from '../artifacts/resolve.js';
|
|
7
|
+
import { simctlAvailable, listSimulators } from '../lib/simctl.js';
|
|
8
|
+
/** Booted + available (shut down) iOS simulators. Tolerates absence: non-macOS hosts, no Xcode
|
|
9
|
+
* command-line tools, or a failing simctl all yield empty lists, never an error. */
|
|
10
|
+
export async function detectIosSimulators() {
|
|
11
|
+
if (process.platform !== 'darwin')
|
|
12
|
+
return { iosBooted: [], iosAvailable: [] };
|
|
13
|
+
try {
|
|
14
|
+
if (!(await simctlAvailable()))
|
|
15
|
+
return { iosBooted: [], iosAvailable: [] };
|
|
16
|
+
const sims = await listSimulators();
|
|
17
|
+
const brief = (s) => ({ udid: s.udid, name: s.name, runtime: s.runtime });
|
|
18
|
+
return {
|
|
19
|
+
iosBooted: sims.filter((s) => s.state === 'Booted').map(brief),
|
|
20
|
+
iosAvailable: sims.filter((s) => s.state !== 'Booted').map(brief),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return { iosBooted: [], iosAvailable: [] };
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/** Any usable device at all (online/bootable Android emulator, or a booted/bootable iOS simulator). */
|
|
28
|
+
export function hasAnyDevice(d) {
|
|
29
|
+
return d.androidOnline.length > 0 || d.avds.length > 0 || d.iosBooted.length > 0 || d.iosAvailable.length > 0;
|
|
30
|
+
}
|
|
7
31
|
function readJson(p) {
|
|
8
32
|
try {
|
|
9
33
|
return JSON.parse(readFileSync(p, 'utf8'));
|
|
@@ -121,32 +145,39 @@ export async function detectContext(projectRoot) {
|
|
|
121
145
|
aapt2: findAapt2() !== null,
|
|
122
146
|
xcodebuild,
|
|
123
147
|
};
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
148
|
+
const [androidOnline, avds, ios] = await Promise.all([
|
|
149
|
+
adb ? adbDevices() : Promise.resolve([]),
|
|
150
|
+
emulator ? listAvds() : Promise.resolve([]),
|
|
151
|
+
detectIosSimulators(),
|
|
152
|
+
]);
|
|
153
|
+
const devices = { androidOnline, avds, ...ios };
|
|
154
|
+
const iosUsable = ios.iosBooted.length > 0 || ios.iosAvailable.length > 0;
|
|
128
155
|
const blockers = [];
|
|
129
156
|
if (framework === 'unknown')
|
|
130
|
-
blockers.push('Could not identify a mobile project here
|
|
157
|
+
blockers.push('Could not identify a mobile project here. Pass an explicit projectRoot, or this is not a supported framework.');
|
|
131
158
|
if (monorepo)
|
|
132
|
-
blockers.push('Monorepo detected
|
|
133
|
-
|
|
134
|
-
|
|
159
|
+
blockers.push('Monorepo detected. Specify which app target to use (avoids guessing).');
|
|
160
|
+
// adb is only a blocker when Android is the only way forward (an iOS project, or any project
|
|
161
|
+
// with a usable iOS simulator, can still be tested without it).
|
|
162
|
+
if (!toolchain.adb && framework !== 'native-ios' && !iosUsable)
|
|
163
|
+
blockers.push('adb not found. Install Android platform-tools.');
|
|
135
164
|
if (framework === 'native-android' && artifacts.apks.length === 0) {
|
|
136
|
-
blockers.push('No prebuilt Android APK found
|
|
165
|
+
blockers.push('No prebuilt Android APK found. Drop an APK under apps/android, build Gradle output, or pass apk=.');
|
|
137
166
|
}
|
|
138
167
|
else if (framework === 'native-ios' && artifacts.ipas.length === 0 && artifacts.appBundles.length === 0) {
|
|
139
|
-
blockers.push('No prebuilt iOS app artifact found
|
|
168
|
+
blockers.push('No prebuilt iOS app artifact found. Build a simulator .app or provide an .ipa for a real device lane.');
|
|
140
169
|
}
|
|
141
170
|
else if (framework !== 'native-android' &&
|
|
142
171
|
framework !== 'native-ios' &&
|
|
143
172
|
artifacts.apks.length === 0 &&
|
|
144
173
|
artifacts.ipas.length === 0 &&
|
|
145
174
|
artifacts.appBundles.length === 0) {
|
|
146
|
-
blockers.push('No prebuilt app artifact found
|
|
175
|
+
blockers.push('No prebuilt app artifact found. Build an APK for Android or a simulator .app for iOS, then run swipium scan again.');
|
|
147
176
|
}
|
|
148
|
-
if (
|
|
149
|
-
blockers.push(
|
|
177
|
+
if (!hasAnyDevice(devices))
|
|
178
|
+
blockers.push(framework === 'native-ios'
|
|
179
|
+
? 'No iOS simulator booted or available. Create one in Xcode (Settings > Platforms).'
|
|
180
|
+
: 'No online device, no AVD, and no iOS simulator. Create an AVD (see qa_doctor) or an iOS simulator.');
|
|
150
181
|
return {
|
|
151
182
|
projectRoot,
|
|
152
183
|
location,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detect.js","sourceRoot":"","sources":["../../src/context/detect.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"detect.js","sourceRoot":"","sources":["../../src/context/detect.ts"],"names":[],"mappings":"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"}
|
package/dist/context/findApps.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
// Mobile app discovery for low-context roots (Developer 1
|
|
1
|
+
// Mobile app discovery for low-context roots (Developer 1). When a developer
|
|
2
2
|
// or agent points Swipium at a monorepo root, a parent directory, or any folder that is not itself
|
|
3
3
|
// a mobile app, this locates the candidate app(s) so `qa_test_this` can either proceed with the one
|
|
4
|
-
// strong candidate (recording a workaround) or ask ONE disambiguation question
|
|
4
|
+
// strong candidate (recording a workaround) or ask ONE disambiguation question, instead of failing
|
|
5
5
|
// with NOT_MOBILE_PROJECT at a root that does in fact contain an app.
|
|
6
6
|
//
|
|
7
7
|
// Pure + bounded + side-effect free: it scans a fixed, shallow set of conventional locations and
|
|
@@ -82,7 +82,7 @@ function readdirSafe(dir) {
|
|
|
82
82
|
return [];
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
|
-
/** Best-effort app id from cheap config markers (no APK badging
|
|
85
|
+
/** Best-effort app id from cheap config markers (no APK badging; that is too heavy here). */
|
|
86
86
|
function lightAppId(dir, fw) {
|
|
87
87
|
if (fw === 'expo') {
|
|
88
88
|
const cfg = readJson(join(dir, 'app.json'));
|
|
@@ -197,9 +197,9 @@ export function findMobileApps(root, nowMs = Date.now()) {
|
|
|
197
197
|
}
|
|
198
198
|
/**
|
|
199
199
|
* Decide what `qa_test_this` should do with the discovery result.
|
|
200
|
-
* - 'adopt'
|
|
201
|
-
* - 'disambiguate'
|
|
202
|
-
* - 'none'
|
|
200
|
+
* - 'adopt' > exactly one recognized app; proceed with it.
|
|
201
|
+
* - 'disambiguate' > ≥2 recognized apps; ask one monorepo_target question with ranked choices.
|
|
202
|
+
* - 'none' > no recognized app anywhere searched.
|
|
203
203
|
*/
|
|
204
204
|
export function classifyDiscovery(result) {
|
|
205
205
|
const choices = result.candidates;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"findApps.js","sourceRoot":"","sources":["../../src/context/findApps.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"findApps.js","sourceRoot":"","sources":["../../src/context/findApps.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,16 +1,158 @@
|
|
|
1
|
-
// Resolve the project root
|
|
2
|
-
// Order
|
|
3
|
-
|
|
1
|
+
// Resolve the project root the server should work in.
|
|
2
|
+
// Order (first hit wins):
|
|
3
|
+
// 1. explicit `projectRoot` arg (must be absolute + an existing directory; an invalid explicit
|
|
4
|
+
// value is an error, never silently replaced by a fallback)
|
|
5
|
+
// 2. MCP roots (the client's declared workspace, the proper mechanism)
|
|
6
|
+
// 3. env SWIPIUM_PROJECT_ROOT (user-set in the client's server config)
|
|
7
|
+
// 4. env CLAUDE_PROJECT_DIR (Claude Code sets it for every stdio server it launches)
|
|
8
|
+
// 5. process.cwd(), only when it is a real directory that is NOT the filesystem root and NOT
|
|
9
|
+
// $HOME, AND it contains a project marker (package.json, app.json, pubspec.yaml, Gradle
|
|
10
|
+
// build/settings files, android/, ios/, *.xcodeproj, *.xcworkspace, Podfile). GUI clients
|
|
11
|
+
// often launch servers from `/`, `~` or an arbitrary directory, which must never be treated
|
|
12
|
+
// as an app repo; clients that honor a configured `cwd` (Codex, Gemini, VS Code) land here.
|
|
13
|
+
// Unresolved: failureCode PROJECT_ROOT_UNRESOLVED (see unresolvedProjectRootError).
|
|
14
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
15
|
+
import { existsSync, readdirSync, statSync } from 'node:fs';
|
|
4
16
|
import { fileURLToPath } from 'node:url';
|
|
5
|
-
import { isAbsolute } from 'node:path';
|
|
6
|
-
|
|
17
|
+
import { isAbsolute, join, parse, resolve } from 'node:path';
|
|
18
|
+
import { homedir } from 'node:os';
|
|
19
|
+
import { qaError } from '../lib/result.js';
|
|
20
|
+
export const PROJECT_ROOT_UNRESOLVED = 'PROJECT_ROOT_UNRESOLVED';
|
|
21
|
+
function isDir(p) {
|
|
22
|
+
try {
|
|
23
|
+
return existsSync(p) && statSync(p).isDirectory();
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/** Files / directories whose presence marks a directory as a mobile (or JS) app project. */
|
|
30
|
+
export const PROJECT_MARKER_FILES = [
|
|
31
|
+
'package.json',
|
|
32
|
+
'app.json',
|
|
33
|
+
'pubspec.yaml',
|
|
34
|
+
'build.gradle',
|
|
35
|
+
'build.gradle.kts',
|
|
36
|
+
'settings.gradle',
|
|
37
|
+
'settings.gradle.kts',
|
|
38
|
+
'Podfile',
|
|
39
|
+
];
|
|
40
|
+
export const PROJECT_MARKER_DIRS = ['android', 'ios'];
|
|
41
|
+
/** Whether `dir` looks like an app project (see PROJECT_MARKER_FILES / _DIRS, *.xcodeproj, *.xcworkspace). */
|
|
42
|
+
export function hasProjectMarker(dir) {
|
|
43
|
+
if (PROJECT_MARKER_FILES.some((f) => existsSync(join(dir, f))))
|
|
44
|
+
return true;
|
|
45
|
+
if (PROJECT_MARKER_DIRS.some((d) => isDir(join(dir, d))))
|
|
46
|
+
return true;
|
|
47
|
+
try {
|
|
48
|
+
return readdirSync(dir).some((e) => /\.(xcodeproj|xcworkspace)$/i.test(e));
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/** A cwd is a usable project root only if it is a directory other than `/` (or a drive root) and
|
|
55
|
+
* $HOME that contains a project marker (an arbitrary launch directory is never guessed as the app). */
|
|
56
|
+
export function isUsableCwd(cwd, home = homedir()) {
|
|
57
|
+
if (!cwd || !isAbsolute(cwd))
|
|
58
|
+
return false;
|
|
59
|
+
const abs = resolve(cwd);
|
|
60
|
+
if (abs === parse(abs).root)
|
|
61
|
+
return false;
|
|
62
|
+
if (home && abs === resolve(home))
|
|
63
|
+
return false;
|
|
64
|
+
return isDir(abs) && hasProjectMarker(abs);
|
|
65
|
+
}
|
|
66
|
+
/** Steps 3-5 of the chain (env vars, then cwd). Exported for tests and CLI reuse. Env values are
|
|
67
|
+
* explicit user/client configuration and are trusted as-is; only the cwd guess needs a marker. */
|
|
68
|
+
export function resolveFallbackRoot(opts = {}) {
|
|
69
|
+
const env = opts.env ?? process.env;
|
|
70
|
+
for (const key of ['SWIPIUM_PROJECT_ROOT', 'CLAUDE_PROJECT_DIR']) {
|
|
71
|
+
const v = env[key]?.trim();
|
|
72
|
+
if (v && isAbsolute(v) && isDir(v))
|
|
73
|
+
return { root: v, source: `env:${key}` };
|
|
74
|
+
}
|
|
75
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
76
|
+
if (isUsableCwd(cwd, opts.home ?? homedir()))
|
|
77
|
+
return { root: resolve(cwd), source: 'cwd' };
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
/** Choose among the client's MCP roots (review P2): the first existing file:// root that has a
|
|
81
|
+
* project marker; else the first one that is neither `/` nor $HOME. A client exposing
|
|
82
|
+
* [$HOME, app] must land on the app, not on the home directory. Exported for tests. */
|
|
83
|
+
export function pickMcpRoot(uris, home = homedir()) {
|
|
84
|
+
const dirs = [];
|
|
85
|
+
for (const u of uris) {
|
|
86
|
+
if (typeof u !== 'string' || !u.startsWith('file://'))
|
|
87
|
+
continue;
|
|
88
|
+
try {
|
|
89
|
+
const p = fileURLToPath(u);
|
|
90
|
+
if (isDir(p))
|
|
91
|
+
dirs.push(p);
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
/* malformed URI, skip */
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const unsafe = (p) => {
|
|
98
|
+
const abs = resolve(p);
|
|
99
|
+
return abs === parse(abs).root || (!!home && abs === resolve(home));
|
|
100
|
+
};
|
|
101
|
+
return dirs.find((p) => !unsafe(p) && hasProjectMarker(p)) ?? dirs.find((p) => !unsafe(p));
|
|
102
|
+
}
|
|
103
|
+
const UNRESOLVED_HINT = 'No project root: the client exposed no MCP roots, SWIPIUM_PROJECT_ROOT / CLAUDE_PROJECT_DIR are unset, and the server cwd is not an app directory (no package.json / app.json / pubspec.yaml / Gradle files / android/ / ios/ / *.xcodeproj / Podfile). ' +
|
|
104
|
+
'Pass projectRoot="/absolute/path/to/app", or set SWIPIUM_PROJECT_ROOT in the MCP server "env" (or a "cwd" where the client supports it).';
|
|
105
|
+
/** Per-tool-call record of the first project root resolveProjectRoot() found (AsyncLocalStorage,
|
|
106
|
+
* like the response mode). Lets the server wrapper surface `rootSource` on EVERY tool that
|
|
107
|
+
* resolves a root without threading it through each result builder. */
|
|
108
|
+
const rootResolutionStore = new AsyncLocalStorage();
|
|
109
|
+
/** Run `fn` (one tool call) while recording the project root it resolves. */
|
|
110
|
+
export async function withRootResolutionRecording(fn) {
|
|
111
|
+
const slot = {};
|
|
112
|
+
const value = await rootResolutionStore.run(slot, fn);
|
|
113
|
+
return { value, resolved: slot.resolved };
|
|
114
|
+
}
|
|
115
|
+
/** The note shown when the root was guessed from the server's working directory. */
|
|
116
|
+
export function cwdRootNote(root) {
|
|
117
|
+
return `project root taken from server cwd: ${root}; pass projectRoot to override`;
|
|
118
|
+
}
|
|
119
|
+
/** Additively stamp `rootSource` (+ `projectRoot` when absent) onto a successful tool result, and
|
|
120
|
+
* the cwd note onto its text when the root was only guessed from the server cwd. Results that
|
|
121
|
+
* already carry `rootSource`, errors, and results without structuredContent are left as-is. */
|
|
122
|
+
export function annotateRootSource(result, resolved) {
|
|
123
|
+
if (!resolved)
|
|
124
|
+
return result;
|
|
125
|
+
const r = result;
|
|
126
|
+
const sc = r?.structuredContent;
|
|
127
|
+
if (!r || r.isError || !sc || typeof sc !== 'object' || Array.isArray(sc) || 'rootSource' in sc)
|
|
128
|
+
return result;
|
|
129
|
+
const structuredContent = { ...sc, rootSource: resolved.source, ...('projectRoot' in sc ? {} : { projectRoot: resolved.root }) };
|
|
130
|
+
let content = r.content;
|
|
131
|
+
if (resolved.source === 'cwd' && Array.isArray(content)) {
|
|
132
|
+
const i = content.findIndex((c) => c.type === 'text');
|
|
133
|
+
if (i >= 0) {
|
|
134
|
+
const block = content[i];
|
|
135
|
+
content = [...content];
|
|
136
|
+
content[i] = { ...block, text: `${block.text}\nℹ ${cwdRootNote(resolved.root)}` };
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return { ...r, content, structuredContent };
|
|
140
|
+
}
|
|
141
|
+
export async function resolveProjectRoot(server, explicit, opts = {}) {
|
|
142
|
+
const resolved = await resolveProjectRootUnrecorded(server, explicit, opts);
|
|
143
|
+
const slot = rootResolutionStore.getStore();
|
|
144
|
+
if (slot && !slot.resolved && resolved.root)
|
|
145
|
+
slot.resolved = { root: resolved.root, source: resolved.source };
|
|
146
|
+
return resolved;
|
|
147
|
+
}
|
|
148
|
+
async function resolveProjectRootUnrecorded(server, explicit, opts = {}) {
|
|
7
149
|
// 1) explicit arg wins (must be an absolute, existing directory)
|
|
8
150
|
if (explicit && explicit.trim()) {
|
|
9
151
|
const p = explicit.trim();
|
|
10
152
|
if (!isAbsolute(p)) {
|
|
11
153
|
return { source: 'none', hint: `projectRoot must be an absolute path, got "${p}".` };
|
|
12
154
|
}
|
|
13
|
-
if (
|
|
155
|
+
if (isDir(p)) {
|
|
14
156
|
return { root: p, source: 'arg' };
|
|
15
157
|
}
|
|
16
158
|
return { source: 'none', hint: `Path not found or not a directory: ${p}` };
|
|
@@ -20,22 +162,35 @@ export async function resolveProjectRoot(server, explicit) {
|
|
|
20
162
|
const caps = server.server.getClientCapabilities?.();
|
|
21
163
|
if (caps?.roots) {
|
|
22
164
|
const res = await server.server.listRoots();
|
|
23
|
-
const
|
|
24
|
-
if (
|
|
25
|
-
|
|
26
|
-
if (existsSync(p) && statSync(p).isDirectory()) {
|
|
27
|
-
return { root: p, source: 'mcp-roots' };
|
|
28
|
-
}
|
|
29
|
-
}
|
|
165
|
+
const picked = pickMcpRoot((res.roots ?? []).map((r) => r.uri), opts.home ?? homedir());
|
|
166
|
+
if (picked)
|
|
167
|
+
return { root: picked, source: 'mcp-roots' };
|
|
30
168
|
}
|
|
31
169
|
}
|
|
32
170
|
catch {
|
|
33
|
-
// client doesn't support roots, or the call failed
|
|
171
|
+
// client doesn't support roots, or the call failed; fall through
|
|
34
172
|
}
|
|
35
|
-
// 3)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
};
|
|
173
|
+
// 3-5) env vars, then a meaningful cwd
|
|
174
|
+
const fallback = resolveFallbackRoot(opts);
|
|
175
|
+
if (fallback)
|
|
176
|
+
return fallback;
|
|
177
|
+
return { source: 'none', hint: UNRESOLVED_HINT };
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* The typed error every tool should return when resolveProjectRoot() finds nothing. Keeps the
|
|
181
|
+
* failureCode (PROJECT_ROOT_UNRESOLVED) and wording consistent across call sites.
|
|
182
|
+
*/
|
|
183
|
+
export function unresolvedProjectRootError(resolved, opts = {}) {
|
|
184
|
+
return qaError({
|
|
185
|
+
what: opts.what ?? 'Could not resolve a project root',
|
|
186
|
+
changedState: false,
|
|
187
|
+
retrySafe: true,
|
|
188
|
+
failureCode: PROJECT_ROOT_UNRESOLVED,
|
|
189
|
+
nextSteps: opts.nextSteps ?? [
|
|
190
|
+
'Pass projectRoot="/absolute/path/to/app" (or call qa_start_session with it first).',
|
|
191
|
+
'Or set SWIPIUM_PROJECT_ROOT in the MCP server config "env".',
|
|
192
|
+
],
|
|
193
|
+
clientHint: resolved.hint,
|
|
194
|
+
});
|
|
40
195
|
}
|
|
41
196
|
//# sourceMappingURL=projectRoot.js.map
|