swipium 1.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/LICENSE +21 -0
- package/README.md +295 -0
- package/dist/appMap/automationLink.js +74 -0
- package/dist/appMap/automationLink.js.map +1 -0
- package/dist/appMap/build.js +193 -0
- package/dist/appMap/build.js.map +1 -0
- package/dist/appMap/codeIndex.js +73 -0
- package/dist/appMap/codeIndex.js.map +1 -0
- package/dist/appMap/featureModel.js +83 -0
- package/dist/appMap/featureModel.js.map +1 -0
- package/dist/appMap/firstRunApply.js +131 -0
- package/dist/appMap/firstRunApply.js.map +1 -0
- package/dist/appMap/fsWalk.js +75 -0
- package/dist/appMap/fsWalk.js.map +1 -0
- package/dist/appMap/issues.js +227 -0
- package/dist/appMap/issues.js.map +1 -0
- package/dist/appMap/migrations.js +87 -0
- package/dist/appMap/migrations.js.map +1 -0
- package/dist/appMap/prelaunch.js +66 -0
- package/dist/appMap/prelaunch.js.map +1 -0
- package/dist/appMap/projectRegistry.js +70 -0
- package/dist/appMap/projectRegistry.js.map +1 -0
- package/dist/appMap/provenance.js +52 -0
- package/dist/appMap/provenance.js.map +1 -0
- package/dist/appMap/query.js +118 -0
- package/dist/appMap/query.js.map +1 -0
- package/dist/appMap/runtimeMerge.js +207 -0
- package/dist/appMap/runtimeMerge.js.map +1 -0
- package/dist/appMap/schema.js +65 -0
- package/dist/appMap/schema.js.map +1 -0
- package/dist/appMap/screenMatch.js +75 -0
- package/dist/appMap/screenMatch.js.map +1 -0
- package/dist/appMap/staticScan.js +614 -0
- package/dist/appMap/staticScan.js.map +1 -0
- package/dist/appMap/store.js +173 -0
- package/dist/appMap/store.js.map +1 -0
- package/dist/appMap/tsAstScan.js +184 -0
- package/dist/appMap/tsAstScan.js.map +1 -0
- package/dist/artifacts/bundletool.js +199 -0
- package/dist/artifacts/bundletool.js.map +1 -0
- package/dist/artifacts/resolve.js +388 -0
- package/dist/artifacts/resolve.js.map +1 -0
- package/dist/automationGen/appiumModel.js +129 -0
- package/dist/automationGen/appiumModel.js.map +1 -0
- package/dist/automationGen/ciEmitter.js +80 -0
- package/dist/automationGen/ciEmitter.js.map +1 -0
- package/dist/automationGen/jsEmitter.js +440 -0
- package/dist/automationGen/jsEmitter.js.map +1 -0
- package/dist/automationGen/packagePatch.js +56 -0
- package/dist/automationGen/packagePatch.js.map +1 -0
- package/dist/automationGen/projectProfile.js +317 -0
- package/dist/automationGen/projectProfile.js.map +1 -0
- package/dist/automationGen/pythonEmitter.js +386 -0
- package/dist/automationGen/pythonEmitter.js.map +1 -0
- package/dist/automationGen/readmeEmitter.js +66 -0
- package/dist/automationGen/readmeEmitter.js.map +1 -0
- package/dist/automationGen/suitePlan.js +94 -0
- package/dist/automationGen/suitePlan.js.map +1 -0
- package/dist/automationGen/validation.js +150 -0
- package/dist/automationGen/validation.js.map +1 -0
- package/dist/build/parseBuildLog.js +119 -0
- package/dist/build/parseBuildLog.js.map +1 -0
- package/dist/build/plan.js +150 -0
- package/dist/build/plan.js.map +1 -0
- package/dist/ci/preflight.js +85 -0
- package/dist/ci/preflight.js.map +1 -0
- package/dist/cli/init.js +105 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/scan.js +85 -0
- package/dist/cli/scan.js.map +1 -0
- package/dist/cli/suite.js +85 -0
- package/dist/cli/suite.js.map +1 -0
- package/dist/cli/verify.js +62 -0
- package/dist/cli/verify.js.map +1 -0
- package/dist/consent/consent.js +43 -0
- package/dist/consent/consent.js.map +1 -0
- package/dist/context/detect.js +156 -0
- package/dist/context/detect.js.map +1 -0
- package/dist/context/findApps.js +198 -0
- package/dist/context/findApps.js.map +1 -0
- package/dist/context/projectRoot.js +41 -0
- package/dist/context/projectRoot.js.map +1 -0
- package/dist/context/scan.js +167 -0
- package/dist/context/scan.js.map +1 -0
- package/dist/core/target.js +115 -0
- package/dist/core/target.js.map +1 -0
- package/dist/core/targetPlan.js +140 -0
- package/dist/core/targetPlan.js.map +1 -0
- package/dist/drivers/DirectDriver.js +228 -0
- package/dist/drivers/DirectDriver.js.map +1 -0
- package/dist/drivers/Driver.js +4 -0
- package/dist/drivers/Driver.js.map +1 -0
- package/dist/drivers/SimctlDriver.js +127 -0
- package/dist/drivers/SimctlDriver.js.map +1 -0
- package/dist/drivers/WdaDriver.js +250 -0
- package/dist/drivers/WdaDriver.js.map +1 -0
- package/dist/explore/candidates.js +93 -0
- package/dist/explore/candidates.js.map +1 -0
- package/dist/explore/graph.js +116 -0
- package/dist/explore/graph.js.map +1 -0
- package/dist/explore/memory.js +35 -0
- package/dist/explore/memory.js.map +1 -0
- package/dist/explore/planner.js +105 -0
- package/dist/explore/planner.js.map +1 -0
- package/dist/explore/policy.js +85 -0
- package/dist/explore/policy.js.map +1 -0
- package/dist/explore/runner.js +475 -0
- package/dist/explore/runner.js.map +1 -0
- package/dist/explore/signatures.js +35 -0
- package/dist/explore/signatures.js.map +1 -0
- package/dist/explore/suite.js +55 -0
- package/dist/explore/suite.js.map +1 -0
- package/dist/featureTesting/executionBootstrap.js +140 -0
- package/dist/featureTesting/executionBootstrap.js.map +1 -0
- package/dist/firstRun/authStateMachine.js +83 -0
- package/dist/firstRun/authStateMachine.js.map +1 -0
- package/dist/firstRun/classifyScreen.js +201 -0
- package/dist/firstRun/classifyScreen.js.map +1 -0
- package/dist/firstRun/firstRunPlanner.js +207 -0
- package/dist/firstRun/firstRunPlanner.js.map +1 -0
- package/dist/firstRun/firstRunRunner.js +331 -0
- package/dist/firstRun/firstRunRunner.js.map +1 -0
- package/dist/firstRun/generatedDataPolicy.js +215 -0
- package/dist/firstRun/generatedDataPolicy.js.map +1 -0
- package/dist/firstRun/inputPlanner.js +67 -0
- package/dist/firstRun/inputPlanner.js.map +1 -0
- package/dist/firstRun/onboardingStateMachine.js +46 -0
- package/dist/firstRun/onboardingStateMachine.js.map +1 -0
- package/dist/firstRun/paywallPolicy.js +54 -0
- package/dist/firstRun/paywallPolicy.js.map +1 -0
- package/dist/firstRun/types.js +7 -0
- package/dist/firstRun/types.js.map +1 -0
- package/dist/fixtures/catalog.js +131 -0
- package/dist/fixtures/catalog.js.map +1 -0
- package/dist/flows/discover.js +18 -0
- package/dist/flows/discover.js.map +1 -0
- package/dist/flows/generate.js +211 -0
- package/dist/flows/generate.js.map +1 -0
- package/dist/flows/lint.js +97 -0
- package/dist/flows/lint.js.map +1 -0
- package/dist/flows/pack.js +68 -0
- package/dist/flows/pack.js.map +1 -0
- package/dist/flows/run.js +738 -0
- package/dist/flows/run.js.map +1 -0
- package/dist/flows/schema.js +240 -0
- package/dist/flows/schema.js.map +1 -0
- package/dist/flows/seedExec.js +108 -0
- package/dist/flows/seedExec.js.map +1 -0
- package/dist/flows/templates.js +155 -0
- package/dist/flows/templates.js.map +1 -0
- package/dist/flows/waitGuards.js +12 -0
- package/dist/flows/waitGuards.js.map +1 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/ios/signing.js +182 -0
- package/dist/ios/signing.js.map +1 -0
- package/dist/issues/classify.js +186 -0
- package/dist/issues/classify.js.map +1 -0
- package/dist/issues/fingerprint.js +130 -0
- package/dist/issues/fingerprint.js.map +1 -0
- package/dist/issues/index.js +240 -0
- package/dist/issues/index.js.map +1 -0
- package/dist/issues/metrics.js +155 -0
- package/dist/issues/metrics.js.map +1 -0
- package/dist/issues/recurrence.js +193 -0
- package/dist/issues/recurrence.js.map +1 -0
- package/dist/issues/report.js +110 -0
- package/dist/issues/report.js.map +1 -0
- package/dist/issues/reportBridge.js +119 -0
- package/dist/issues/reportBridge.js.map +1 -0
- package/dist/issues/schema.js +90 -0
- package/dist/issues/schema.js.map +1 -0
- package/dist/issues/sourceRevision.js +108 -0
- package/dist/issues/sourceRevision.js.map +1 -0
- package/dist/issues/store.js +155 -0
- package/dist/issues/store.js.map +1 -0
- package/dist/lib/android.js +278 -0
- package/dist/lib/android.js.map +1 -0
- package/dist/lib/commandTemplate.js +55 -0
- package/dist/lib/commandTemplate.js.map +1 -0
- package/dist/lib/coordSpace.js +23 -0
- package/dist/lib/coordSpace.js.map +1 -0
- package/dist/lib/device.js +87 -0
- package/dist/lib/device.js.map +1 -0
- package/dist/lib/gitignore.js +22 -0
- package/dist/lib/gitignore.js.map +1 -0
- package/dist/lib/image.js +97 -0
- package/dist/lib/image.js.map +1 -0
- package/dist/lib/logger.js +8 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/metroState.js +45 -0
- package/dist/lib/metroState.js.map +1 -0
- package/dist/lib/needsInput.js +201 -0
- package/dist/lib/needsInput.js.map +1 -0
- package/dist/lib/png.js +103 -0
- package/dist/lib/png.js.map +1 -0
- package/dist/lib/redact.js +21 -0
- package/dist/lib/redact.js.map +1 -0
- package/dist/lib/result.js +87 -0
- package/dist/lib/result.js.map +1 -0
- package/dist/lib/schemaHash.js +65 -0
- package/dist/lib/schemaHash.js.map +1 -0
- package/dist/lib/sensitive.js +13 -0
- package/dist/lib/sensitive.js.map +1 -0
- package/dist/lib/simctl.js +149 -0
- package/dist/lib/simctl.js.map +1 -0
- package/dist/lib/spawn.js +144 -0
- package/dist/lib/spawn.js.map +1 -0
- package/dist/lib/wda.js +347 -0
- package/dist/lib/wda.js.map +1 -0
- package/dist/lib/wdaConfig.js +69 -0
- package/dist/lib/wdaConfig.js.map +1 -0
- package/dist/lib/wdaTune.js +58 -0
- package/dist/lib/wdaTune.js.map +1 -0
- package/dist/oracle/auth.js +22 -0
- package/dist/oracle/auth.js.map +1 -0
- package/dist/oracle/failures.js +193 -0
- package/dist/oracle/failures.js.map +1 -0
- package/dist/oracle/health.js +123 -0
- package/dist/oracle/health.js.map +1 -0
- package/dist/oracle/record.js +36 -0
- package/dist/oracle/record.js.map +1 -0
- package/dist/orchestration/envelope.js +52 -0
- package/dist/orchestration/envelope.js.map +1 -0
- package/dist/orchestration/goal.js +98 -0
- package/dist/orchestration/goal.js.map +1 -0
- package/dist/plan/plan.js +124 -0
- package/dist/plan/plan.js.map +1 -0
- package/dist/prompts/index.js +63 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/report/artifactManifest.js +44 -0
- package/dist/report/artifactManifest.js.map +1 -0
- package/dist/report/coverage.js +60 -0
- package/dist/report/coverage.js.map +1 -0
- package/dist/report/evidence.js +84 -0
- package/dist/report/evidence.js.map +1 -0
- package/dist/report/export.js +447 -0
- package/dist/report/export.js.map +1 -0
- package/dist/report/flake.js +61 -0
- package/dist/report/flake.js.map +1 -0
- package/dist/report/history.js +564 -0
- package/dist/report/history.js.map +1 -0
- package/dist/report/policy.js +98 -0
- package/dist/report/policy.js.map +1 -0
- package/dist/report/qaLevel.js +96 -0
- package/dist/report/qaLevel.js.map +1 -0
- package/dist/report/readiness.js +213 -0
- package/dist/report/readiness.js.map +1 -0
- package/dist/report/summary.js +42 -0
- package/dist/report/summary.js.map +1 -0
- package/dist/report/testCatalog.js +93 -0
- package/dist/report/testCatalog.js.map +1 -0
- package/dist/report/timing.js +37 -0
- package/dist/report/timing.js.map +1 -0
- package/dist/server.js +180 -0
- package/dist/server.js.map +1 -0
- package/dist/services/automationGenerate.js +60 -0
- package/dist/services/automationGenerate.js.map +1 -0
- package/dist/services/build.js +66 -0
- package/dist/services/build.js.map +1 -0
- package/dist/services/preflight.js +51 -0
- package/dist/services/preflight.js.map +1 -0
- package/dist/services/prepareAndroid.js +183 -0
- package/dist/services/prepareAndroid.js.map +1 -0
- package/dist/services/prepareIos.js +162 -0
- package/dist/services/prepareIos.js.map +1 -0
- package/dist/services/report.js +537 -0
- package/dist/services/report.js.map +1 -0
- package/dist/services/smoke.js +120 -0
- package/dist/services/smoke.js.map +1 -0
- package/dist/services/suiteGenerate.js +123 -0
- package/dist/services/suiteGenerate.js.map +1 -0
- package/dist/services/testSuiteKnowledge.js +150 -0
- package/dist/services/testSuiteKnowledge.js.map +1 -0
- package/dist/session/attach.js +47 -0
- package/dist/session/attach.js.map +1 -0
- package/dist/session/progress.js +56 -0
- package/dist/session/progress.js.map +1 -0
- package/dist/session/store.js +329 -0
- package/dist/session/store.js.map +1 -0
- package/dist/snapshot/overlays.js +132 -0
- package/dist/snapshot/overlays.js.map +1 -0
- package/dist/snapshot/parse.js +204 -0
- package/dist/snapshot/parse.js.map +1 -0
- package/dist/snapshot/present.js +12 -0
- package/dist/snapshot/present.js.map +1 -0
- package/dist/snapshot/settle.js +36 -0
- package/dist/snapshot/settle.js.map +1 -0
- package/dist/state/profile.js +318 -0
- package/dist/state/profile.js.map +1 -0
- package/dist/suite/compile.js +176 -0
- package/dist/suite/compile.js.map +1 -0
- package/dist/suite/lint.js +45 -0
- package/dist/suite/lint.js.map +1 -0
- package/dist/suite/pom.js +285 -0
- package/dist/suite/pom.js.map +1 -0
- package/dist/suite/testcase.js +87 -0
- package/dist/suite/testcase.js.map +1 -0
- package/dist/testSuite/generator.js +222 -0
- package/dist/testSuite/generator.js.map +1 -0
- package/dist/testSuite/history.js +44 -0
- package/dist/testSuite/history.js.map +1 -0
- package/dist/testSuite/issueLinks.js +96 -0
- package/dist/testSuite/issueLinks.js.map +1 -0
- package/dist/testSuite/merge.js +190 -0
- package/dist/testSuite/merge.js.map +1 -0
- package/dist/testSuite/schema.js +86 -0
- package/dist/testSuite/schema.js.map +1 -0
- package/dist/testSuite/store.js +116 -0
- package/dist/testSuite/store.js.map +1 -0
- package/dist/testSuite/traceability.js +55 -0
- package/dist/testSuite/traceability.js.map +1 -0
- package/dist/tools/act.js +457 -0
- package/dist/tools/act.js.map +1 -0
- package/dist/tools/agent.js +225 -0
- package/dist/tools/agent.js.map +1 -0
- package/dist/tools/appMap.js +317 -0
- package/dist/tools/appMap.js.map +1 -0
- package/dist/tools/assertVisual.js +74 -0
- package/dist/tools/assertVisual.js.map +1 -0
- package/dist/tools/automationGenerate.js +394 -0
- package/dist/tools/automationGenerate.js.map +1 -0
- package/dist/tools/capabilities.js +114 -0
- package/dist/tools/capabilities.js.map +1 -0
- package/dist/tools/clearOverlay.js +150 -0
- package/dist/tools/clearOverlay.js.map +1 -0
- package/dist/tools/detectContext.js +41 -0
- package/dist/tools/detectContext.js.map +1 -0
- package/dist/tools/doctor.js +116 -0
- package/dist/tools/doctor.js.map +1 -0
- package/dist/tools/explore.js +289 -0
- package/dist/tools/explore.js.map +1 -0
- package/dist/tools/firstRun.js +136 -0
- package/dist/tools/firstRun.js.map +1 -0
- package/dist/tools/flow.js +331 -0
- package/dist/tools/flow.js.map +1 -0
- package/dist/tools/flowGenerate.js +55 -0
- package/dist/tools/flowGenerate.js.map +1 -0
- package/dist/tools/getArtifact.js +39 -0
- package/dist/tools/getArtifact.js.map +1 -0
- package/dist/tools/health.js +41 -0
- package/dist/tools/health.js.map +1 -0
- package/dist/tools/ios.js +492 -0
- package/dist/tools/ios.js.map +1 -0
- package/dist/tools/jobs.js +20 -0
- package/dist/tools/jobs.js.map +1 -0
- package/dist/tools/network.js +50 -0
- package/dist/tools/network.js.map +1 -0
- package/dist/tools/note.js +69 -0
- package/dist/tools/note.js.map +1 -0
- package/dist/tools/plan.js +49 -0
- package/dist/tools/plan.js.map +1 -0
- package/dist/tools/prepareIosTarget.js +99 -0
- package/dist/tools/prepareIosTarget.js.map +1 -0
- package/dist/tools/prepareTarget.js +257 -0
- package/dist/tools/prepareTarget.js.map +1 -0
- package/dist/tools/report.js +42 -0
- package/dist/tools/report.js.map +1 -0
- package/dist/tools/screenRecord.js +24 -0
- package/dist/tools/screenRecord.js.map +1 -0
- package/dist/tools/screenshot.js +63 -0
- package/dist/tools/screenshot.js.map +1 -0
- package/dist/tools/smoke.js +39 -0
- package/dist/tools/smoke.js.map +1 -0
- package/dist/tools/snapshot.js +129 -0
- package/dist/tools/snapshot.js.map +1 -0
- package/dist/tools/startSession.js +169 -0
- package/dist/tools/startSession.js.map +1 -0
- package/dist/tools/state.js +87 -0
- package/dist/tools/state.js.map +1 -0
- package/dist/tools/suite.js +412 -0
- package/dist/tools/suite.js.map +1 -0
- package/dist/tools/testThis.js +774 -0
- package/dist/tools/testThis.js.map +1 -0
- package/dist/tools/wda.js +477 -0
- package/dist/tools/wda.js.map +1 -0
- package/dist/version.js +62 -0
- package/dist/version.js.map +1 -0
- package/dist/visual/ocr.js +72 -0
- package/dist/visual/ocr.js.map +1 -0
- package/dist/visual/provider.js +75 -0
- package/dist/visual/provider.js.map +1 -0
- package/docs/README.md +19 -0
- package/docs/assets/swipium-lockup-ink-on-light.png +0 -0
- package/docs/mcp-server.md +135 -0
- package/docs/tools.md +130 -0
- package/package.json +70 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 swipium contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="docs/assets/swipium-lockup-ink-on-light.png" alt="Swipium" width="420">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
# Swipium
|
|
6
|
+
|
|
7
|
+
MCP server for simulator-based mobile QA agents.
|
|
8
|
+
|
|
9
|
+
[](https://www.npmjs.com/package/swipium)
|
|
10
|
+
[](LICENSE)
|
|
11
|
+
[](https://nodejs.org)
|
|
12
|
+
[](https://modelcontextprotocol.io)
|
|
13
|
+
[](https://swipium.com)
|
|
14
|
+
|
|
15
|
+
Swipium lets an AI agent run practical mobile QA from a local MCP client: launch an app in an Android Emulator or iOS Simulator, inspect screens, act on the UI, run smoke checks, collect evidence, build an app knowledge map, generate reports, and create reusable test assets.
|
|
16
|
+
|
|
17
|
+
Website: [swipium.com](https://swipium.com)
|
|
18
|
+
|
|
19
|
+
## About
|
|
20
|
+
|
|
21
|
+
Swipium is a local MCP server for mobile QA workflows. It gives agents a structured tool surface for simulator setup, UI observation, action execution, evidence capture, app-map memory, reporting, and generated test suites.
|
|
22
|
+
|
|
23
|
+
Swipium's mission is to help development teams and indie developers get fast feedback on applications from a usage perspective, not from a code perspective. Earlier usage feedback helps teams iterate quickly and avoid shipping production builds with issues that could have been detected before release.
|
|
24
|
+
|
|
25
|
+
Swipium is intended to be used through an agent. The agent communicates with the MCP server and gets access to a QA-oriented suite of testing tools for exploration, evidence collection, app knowledge, report generation, test assets, and automation.
|
|
26
|
+
|
|
27
|
+
Public v1 scope:
|
|
28
|
+
|
|
29
|
+
- Android Emulator and iOS Simulator.
|
|
30
|
+
- Local MCP stdio server.
|
|
31
|
+
- Evidence stored as local Swipium artifacts.
|
|
32
|
+
- Durable app knowledge map under the tested project.
|
|
33
|
+
- Flow, test-case, suite, and automation generation from observed behavior.
|
|
34
|
+
- Consent gates for mutating actions.
|
|
35
|
+
- Secret redaction for credentials, tokens, OTPs, and generated sensitive values.
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
## What is Swipium?
|
|
39
|
+
|
|
40
|
+
Swipium is not a replacement for a test runner. It is an agent-facing QA harness.
|
|
41
|
+
|
|
42
|
+
It helps an agent answer requests like:
|
|
43
|
+
|
|
44
|
+
- "Test it."
|
|
45
|
+
- "Test this e2e flow."
|
|
46
|
+
- "Create test automation for this app."
|
|
47
|
+
- "Smoke test this app."
|
|
48
|
+
- "Explore the login flow."
|
|
49
|
+
- "Generate a report with evidence."
|
|
50
|
+
- "Turn this run into a reusable flow."
|
|
51
|
+
- "Create an automation suite from what you observed."
|
|
52
|
+
|
|
53
|
+
The MCP server keeps the workflow deterministic where possible and explicit where risk exists. Heavy steps such as booting simulators, installing apps, writing files, or generating automation are exposed as tools with structured outputs, blockers, artifacts, and consent prompts.
|
|
54
|
+
|
|
55
|
+
## QuickStart
|
|
56
|
+
|
|
57
|
+
Run this from the mobile app repository:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
npx -y swipium verify
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Add Swipium to your agent:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npm install -g swipium
|
|
67
|
+
swipium init claude --apply --scope project
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Then ask the agent:
|
|
71
|
+
|
|
72
|
+
```text
|
|
73
|
+
Test this app with Swipium. Start with qa_test_this. Use Android Emulator or iOS Simulator only. Generate a report with evidence.
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
For a direct MCP configuration without a global install:
|
|
77
|
+
|
|
78
|
+
```jsonc
|
|
79
|
+
{
|
|
80
|
+
"mcpServers": {
|
|
81
|
+
"swipium": {
|
|
82
|
+
"command": "npx",
|
|
83
|
+
"args": ["-y", "swipium"],
|
|
84
|
+
"cwd": "/absolute/path/to/your/mobile-app",
|
|
85
|
+
"timeout": 600000
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Installation
|
|
92
|
+
|
|
93
|
+
Run without installing:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
npx -y swipium verify
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Install globally:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
npm install -g swipium
|
|
103
|
+
swipium verify
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Install in a project:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
npm install --save-dev swipium
|
|
110
|
+
npx swipium verify
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Requirements:
|
|
114
|
+
|
|
115
|
+
- Node.js 20 or newer.
|
|
116
|
+
- Android Studio for Android Emulator workflows.
|
|
117
|
+
- Xcode for iOS Simulator workflows.
|
|
118
|
+
- A simulator-ready app artifact when testing iOS, such as a simulator `.app`.
|
|
119
|
+
- An APK or buildable Android project when testing Android.
|
|
120
|
+
|
|
121
|
+
## Usage
|
|
122
|
+
|
|
123
|
+
Start with the autopilot tool:
|
|
124
|
+
|
|
125
|
+
```text
|
|
126
|
+
qa_test_this {
|
|
127
|
+
"projectRoot": "/absolute/path/to/app",
|
|
128
|
+
"mode": "execute",
|
|
129
|
+
"goal": "smoke"
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Common workflow:
|
|
134
|
+
|
|
135
|
+
1. `qa_doctor` checks local toolchain readiness.
|
|
136
|
+
2. `qa_test_this` resolves the project, artifact, and simulator target.
|
|
137
|
+
3. `qa_job_status` polls long-running work.
|
|
138
|
+
4. `qa_smoke` or `qa_explore` runs the app.
|
|
139
|
+
5. `qa_report` produces the evidence report.
|
|
140
|
+
6. `qa_app_map_read` or `qa_app_map_query` reads the durable app map.
|
|
141
|
+
7. `qa_flow_generate`, `qa_suite_generate`, or `qa_automation_generate` creates reusable QA assets.
|
|
142
|
+
|
|
143
|
+
CLI helpers:
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
swipium verify # starts the server and checks tool injection
|
|
147
|
+
swipium init claude # preview Claude Code registration
|
|
148
|
+
swipium init gemini # preview Gemini registration
|
|
149
|
+
swipium init codex # preview Codex config
|
|
150
|
+
swipium init flows # create starter flow templates
|
|
151
|
+
swipium scan # scan project context
|
|
152
|
+
swipium suite # local suite helper
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## MCP Server
|
|
156
|
+
|
|
157
|
+
Swipium runs as a stdio MCP server. MCP clients launch it as a local process and communicate through JSON-RPC over stdin and stdout.
|
|
158
|
+
|
|
159
|
+
Manual MCP configuration:
|
|
160
|
+
|
|
161
|
+
```jsonc
|
|
162
|
+
{
|
|
163
|
+
"mcpServers": {
|
|
164
|
+
"swipium": {
|
|
165
|
+
"command": "npx",
|
|
166
|
+
"args": ["-y", "swipium"],
|
|
167
|
+
"cwd": "/absolute/path/to/your/mobile-app",
|
|
168
|
+
"timeout": 600000
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Installed binary configuration:
|
|
175
|
+
|
|
176
|
+
```jsonc
|
|
177
|
+
{
|
|
178
|
+
"mcpServers": {
|
|
179
|
+
"swipium": {
|
|
180
|
+
"command": "swipium",
|
|
181
|
+
"args": [],
|
|
182
|
+
"cwd": "/absolute/path/to/your/mobile-app",
|
|
183
|
+
"timeout": 600000
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Important:
|
|
190
|
+
|
|
191
|
+
- Set `cwd` to the mobile app repository.
|
|
192
|
+
- Restart the MCP client after installing or upgrading.
|
|
193
|
+
- Run `qa_doctor` if tools are missing or stale.
|
|
194
|
+
- Use `qa_get_artifact` for report, screenshot, dump, and log artifacts.
|
|
195
|
+
|
|
196
|
+
More detail: [docs/mcp-server.md](docs/mcp-server.md)
|
|
197
|
+
|
|
198
|
+
## Agent Integration
|
|
199
|
+
|
|
200
|
+
### Claude Code
|
|
201
|
+
|
|
202
|
+
Global install:
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
npm install -g swipium
|
|
206
|
+
swipium init claude --apply --scope project
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
No global install:
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
claude mcp add swipium --scope project -- npx -y swipium
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Gemini CLI
|
|
216
|
+
|
|
217
|
+
Global install:
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
npm install -g swipium
|
|
221
|
+
swipium init gemini --apply
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
No global install:
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
gemini mcp add swipium npx -y swipium
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Codex
|
|
231
|
+
|
|
232
|
+
Global install:
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
npm install -g swipium
|
|
236
|
+
swipium init codex --apply
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Manual Codex config:
|
|
240
|
+
|
|
241
|
+
```toml
|
|
242
|
+
[mcp_servers.swipium]
|
|
243
|
+
command = "npx"
|
|
244
|
+
args = ["-y", "swipium"]
|
|
245
|
+
cwd = "/absolute/path/to/your/mobile-app"
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
After setup, verify that the client lists `qa_test_this`, `qa_capabilities`, and `qa_report`.
|
|
249
|
+
|
|
250
|
+
## Tool Docs
|
|
251
|
+
|
|
252
|
+
Swipium v1 exposes 42 public MCP tools. Start with `qa_test_this` for low-context requests.
|
|
253
|
+
|
|
254
|
+
Full reference: [docs/tools.md](docs/tools.md)
|
|
255
|
+
|
|
256
|
+
| Group | Tools |
|
|
257
|
+
| --- | --- |
|
|
258
|
+
| Start | `qa_agent_brief`, `qa_capabilities`, `qa_test_this`, `qa_job_status`, `qa_status`, `qa_explain_blocker`, `qa_continue_from_blocker`, `qa_get_artifact` |
|
|
259
|
+
| Setup | `qa_doctor`, `qa_start_session`, `qa_detect_context`, `qa_plan`, `qa_prepare_target`, `qa_prepare_ios_target`, `qa_ios`, `qa_wda` |
|
|
260
|
+
| Drive | `qa_snapshot`, `qa_act`, `qa_clear_overlay`, `qa_check_health`, `qa_screenshot`, `qa_note`, `qa_assert_visual` |
|
|
261
|
+
| Run | `qa_smoke`, `qa_explore`, `qa_report` |
|
|
262
|
+
| App map | `qa_app_map_build`, `qa_app_map_read`, `qa_app_map_query`, `qa_app_map_feature_scope`, `qa_app_map_validate` |
|
|
263
|
+
| Flows and suites | `qa_flow_check`, `qa_flow_run`, `qa_flow_generate`, `qa_suite_generate`, `qa_suite_compile`, `qa_testcase_generate` |
|
|
264
|
+
| First run | `qa_first_run_plan`, `qa_first_run_continue` |
|
|
265
|
+
| Automation | `qa_automation_plan`, `qa_automation_generate`, `qa_automation_validate` |
|
|
266
|
+
|
|
267
|
+
## Why Swipium?
|
|
268
|
+
|
|
269
|
+
- Agent-native: exposes QA work as MCP tools with structured outputs.
|
|
270
|
+
- Simulator-first: focuses v1 on Android Emulator and iOS Simulator reliability.
|
|
271
|
+
- Evidence-first: screenshots, logs, reports, dumps, and artifacts are stored and linked.
|
|
272
|
+
- App memory: the app map preserves screens, features, test cases, flows, and coverage context.
|
|
273
|
+
- Practical consent: mutating actions are gated instead of hidden behind agent text.
|
|
274
|
+
- Reusable output: exploratory runs can become flows, test cases, suites, and generated automation.
|
|
275
|
+
- Local by default: the server runs on the developer machine and uses local simulators.
|
|
276
|
+
|
|
277
|
+
## Docs
|
|
278
|
+
|
|
279
|
+
- [MCP Server](docs/mcp-server.md)
|
|
280
|
+
- [Tool Reference](docs/tools.md)
|
|
281
|
+
- [Project Docs Index](docs/README.md)
|
|
282
|
+
- [Security Policy](SECURITY.md)
|
|
283
|
+
- [Contributing](CONTRIBUTING.md)
|
|
284
|
+
- [Support](SUPPORT.md)
|
|
285
|
+
- [Changelog](CHANGELOG.md)
|
|
286
|
+
|
|
287
|
+
## Topics
|
|
288
|
+
|
|
289
|
+
Recommended GitHub topics:
|
|
290
|
+
|
|
291
|
+
`mcp`, `model-context-protocol`, `mobile-testing`, `qa-automation`, `android-emulator`, `ios-simulator`, `appium`, `ai-agents`, `test-automation`, `e2e-testing`, `react-native-testing`, `flutter-testing`, `app-map`, `test-suites`, `developer-tools`
|
|
292
|
+
|
|
293
|
+
## License
|
|
294
|
+
|
|
295
|
+
MIT. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// Vision Gap Fix 7 — write a generated automation suite back into the durable app map. After
|
|
2
|
+
// qa_automation_generate emits an Appium POM suite, the app map should KNOW automation now exists for
|
|
3
|
+
// these screens/features, so future feature/ticket decisions can see which flows are automated. Pure-
|
|
4
|
+
// ish: loads + saves `.swipium/app-map.json`, upserting an AutomationSuiteRef (by path) with the
|
|
5
|
+
// screen/feature ids the suite covers. Best-effort: returns ok:false rather than throwing on no map.
|
|
6
|
+
import { loadAppMap, saveAppMap } from './store.js';
|
|
7
|
+
import { addProvenance, makeProvenance, recomputeConfidence } from './provenance.js';
|
|
8
|
+
import { detectFramework } from './../context/detect.js';
|
|
9
|
+
function fallbackProject(root) {
|
|
10
|
+
const fw = detectFramework(root);
|
|
11
|
+
return { root, gitRemote: null, packageName: null, workspaceTarget: null, framework: fw, platforms: fw === 'native-android' ? ['android'] : fw === 'native-ios' ? ['ios'] : ['android', 'ios'] };
|
|
12
|
+
}
|
|
13
|
+
// Generic page/screen suffixes carry no identity — a POM "LoginPage" and a static "login" route are
|
|
14
|
+
// the same screen. Strip these (on both sides) so the page-name → static-screen match actually fires.
|
|
15
|
+
const SCREEN_NOISE = new Set(['page', 'screen', 'view', 'component', 'tab', 'modal', 'navigator', 'stack', 'drawer', 'route', 'index']);
|
|
16
|
+
/** Split camelCase/PascalCase/snake/kebab into lowercase identity tokens, dropping generic noise. */
|
|
17
|
+
function tokenize(s) {
|
|
18
|
+
return s
|
|
19
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1 $2') // camelCase boundary: LoginPage → Login Page
|
|
20
|
+
.replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2') // ACRONYMWord boundary
|
|
21
|
+
.toLowerCase()
|
|
22
|
+
.split(/[^a-z0-9]+/)
|
|
23
|
+
.filter((t) => t.length >= 2 && !SCREEN_NOISE.has(t));
|
|
24
|
+
}
|
|
25
|
+
/** Best-effort map of generated POM screen names → app-map static screen ids + their feature ids. */
|
|
26
|
+
export function deriveAutomationLinks(map, screenNames) {
|
|
27
|
+
const screenIds = new Set();
|
|
28
|
+
for (const name of screenNames) {
|
|
29
|
+
const want = new Set(tokenize(name));
|
|
30
|
+
if (!want.size)
|
|
31
|
+
continue;
|
|
32
|
+
let best;
|
|
33
|
+
for (const s of map.staticTopology.screens) {
|
|
34
|
+
// Match against the static screen's name, route, AND id slug (e.g. "screen:login" / "route:login").
|
|
35
|
+
const have = new Set([...tokenize(s.name), ...tokenize(s.route ?? ''), ...tokenize(s.id)]);
|
|
36
|
+
let score = 0;
|
|
37
|
+
for (const t of want)
|
|
38
|
+
if (have.has(t))
|
|
39
|
+
score++;
|
|
40
|
+
if (score > 0 && (!best || score > best.score))
|
|
41
|
+
best = { id: s.id, score };
|
|
42
|
+
}
|
|
43
|
+
if (best)
|
|
44
|
+
screenIds.add(best.id);
|
|
45
|
+
}
|
|
46
|
+
const featureIds = new Set();
|
|
47
|
+
for (const f of map.features) {
|
|
48
|
+
if (f.staticScreens.some((sid) => screenIds.has(sid)))
|
|
49
|
+
featureIds.add(f.id);
|
|
50
|
+
}
|
|
51
|
+
return { screenIds: [...screenIds], featureIds: [...featureIds] };
|
|
52
|
+
}
|
|
53
|
+
/** Upsert (by path) an automation suite record into the durable app map. */
|
|
54
|
+
export function linkAutomationSuite(root, suite, now) {
|
|
55
|
+
const loaded = loadAppMap(root, fallbackProject(root), now);
|
|
56
|
+
if (!loaded.map)
|
|
57
|
+
return { ok: false };
|
|
58
|
+
const map = loaded.map;
|
|
59
|
+
// Enrich screen/feature links from the map when the caller didn't already resolve them.
|
|
60
|
+
if ((!suite.linkedScreenIds || !suite.linkedScreenIds.length) && suite.linkedFeatureIds === undefined) {
|
|
61
|
+
// nothing to enrich
|
|
62
|
+
}
|
|
63
|
+
const existing = map.automation.suites.find((s) => s.path === suite.path);
|
|
64
|
+
if (existing)
|
|
65
|
+
Object.assign(existing, suite);
|
|
66
|
+
else
|
|
67
|
+
map.automation.suites.push(suite);
|
|
68
|
+
addProvenance(map, makeProvenance('test_case', now, `Automation suite ${suite.name} linked (${suite.framework ?? 'appium'})`, { targetType: 'test', refs: [suite.path] }));
|
|
69
|
+
map.updatedAt = now;
|
|
70
|
+
recomputeConfidence(map);
|
|
71
|
+
const save = saveAppMap(root, map);
|
|
72
|
+
return { ok: true, appMapUri: save.resourceUri, suite };
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=automationLink.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"automationLink.js","sourceRoot":"","sources":["../../src/appMap/automationLink.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
// App map builder (SWIPIUM-REQ-01 qa_app_map_build orchestration). Resolves project identity, runs
|
|
2
|
+
// the framework-aware static scan, loads + migrates any existing map, optionally merges a runtime
|
|
3
|
+
// explore graph, recomputes coverage/confidence, and persists. Additive: a static rescan refreshes
|
|
4
|
+
// the static topology while PRESERVING runtime observations, tickets, the test suite, and automation
|
|
5
|
+
// links. Pure-ish: filesystem I/O is confined to staticScan/codeIndex/store; this composes them.
|
|
6
|
+
import { readFileSync } from 'node:fs';
|
|
7
|
+
import { join } from 'node:path';
|
|
8
|
+
import { detectFramework } from '../context/detect.js';
|
|
9
|
+
import { buildCodeIndex } from './codeIndex.js';
|
|
10
|
+
import { inferFeatures } from './featureModel.js';
|
|
11
|
+
import { addProvenance, makeProvenance, recomputeConfidence } from './provenance.js';
|
|
12
|
+
import { applyIssueSummariesToAppMap } from './issues.js';
|
|
13
|
+
import { mergeRuntimeGraph, computeUnvisitedStaticScreens } from './runtimeMerge.js';
|
|
14
|
+
import { applyFirstRunPatches } from './firstRunApply.js';
|
|
15
|
+
import { emptyAppMap } from './schema.js';
|
|
16
|
+
import { hasFormLibrary, staticScan } from './staticScan.js';
|
|
17
|
+
import { loadAppMap, saveAppMap, saveIndexes } from './store.js';
|
|
18
|
+
import { rememberProject } from './projectRegistry.js';
|
|
19
|
+
function gitRemote(root) {
|
|
20
|
+
try {
|
|
21
|
+
const cfg = readFileSync(join(root, '.git', 'config'), 'utf8');
|
|
22
|
+
const m = cfg.match(/\[remote "origin"\][^[]*url\s*=\s*(.+)/);
|
|
23
|
+
return m ? m[1].trim() : null;
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function platformsFor(fw) {
|
|
30
|
+
switch (fw) {
|
|
31
|
+
case 'native-android':
|
|
32
|
+
return ['android'];
|
|
33
|
+
case 'native-ios':
|
|
34
|
+
return ['ios'];
|
|
35
|
+
default:
|
|
36
|
+
return ['android', 'ios'];
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function projectIdentity(root, fw, packageName) {
|
|
40
|
+
return {
|
|
41
|
+
root,
|
|
42
|
+
gitRemote: gitRemote(root),
|
|
43
|
+
packageName,
|
|
44
|
+
workspaceTarget: null,
|
|
45
|
+
framework: fw,
|
|
46
|
+
platforms: platformsFor(fw),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function recomputeCoverage(map) {
|
|
50
|
+
// Recompute unvisited static screens here so it is correct after EVERY build path — including a
|
|
51
|
+
// static-only scan where mergeRuntimeGraph never runs (SWIPIUM-REQ-01 Fix Group 6).
|
|
52
|
+
map.runtimeTopology.unvisitedStaticScreens = computeUnvisitedStaticScreens(map);
|
|
53
|
+
const staticScreens = map.staticTopology.screens.length;
|
|
54
|
+
const runtimeScreens = map.runtimeTopology.screens.length;
|
|
55
|
+
const linkedScreens = map.runtimeTopology.screens.filter((r) => r.linkedStaticScreenId).length;
|
|
56
|
+
const unmapped = map.runtimeTopology.screens.filter((r) => r.unmapped).length;
|
|
57
|
+
const featureCoverage = {};
|
|
58
|
+
for (const f of map.features)
|
|
59
|
+
featureCoverage[f.id] = f.testCoverage;
|
|
60
|
+
const staleTests = map.testSuite.cases.filter((c) => c.stale).length;
|
|
61
|
+
const overallPercent = staticScreens ? Math.round((linkedScreens / staticScreens) * 100) : runtimeScreens ? 100 : 0;
|
|
62
|
+
map.coverage = {
|
|
63
|
+
staticScreens,
|
|
64
|
+
runtimeScreens,
|
|
65
|
+
linkedScreens,
|
|
66
|
+
unvisitedStaticScreens: map.runtimeTopology.unvisitedStaticScreens.length,
|
|
67
|
+
unmappedRuntimeScreens: unmapped,
|
|
68
|
+
featureCoverage,
|
|
69
|
+
staleTests,
|
|
70
|
+
overallPercent,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/** Replace the static topology + static-derived facts; preserve runtime feature enrichment. */
|
|
74
|
+
function applyStaticScan(map, root, at) {
|
|
75
|
+
const scan = staticScan(root, at);
|
|
76
|
+
map.staticTopology = scan.staticTopology;
|
|
77
|
+
map.appIdentity = {
|
|
78
|
+
androidPackage: scan.appIdentity.androidPackage ?? map.appIdentity.androidPackage,
|
|
79
|
+
iosBundleId: scan.appIdentity.iosBundleId ?? map.appIdentity.iosBundleId,
|
|
80
|
+
appName: scan.appIdentity.appName ?? map.appIdentity.appName,
|
|
81
|
+
version: scan.appIdentity.version ?? map.appIdentity.version,
|
|
82
|
+
artifactHash: map.appIdentity.artifactHash,
|
|
83
|
+
environment: map.appIdentity.environment,
|
|
84
|
+
};
|
|
85
|
+
map.auth = scan.auth;
|
|
86
|
+
map.onboarding = scan.onboarding;
|
|
87
|
+
map.paywalls = scan.paywalls;
|
|
88
|
+
map.inputModels = scan.inputModels;
|
|
89
|
+
map.sourceFingerprint = scan.sourceFingerprint;
|
|
90
|
+
if (scan.packageName)
|
|
91
|
+
map.project.packageName = scan.packageName;
|
|
92
|
+
// Re-infer features, but carry over runtime enrichment (runtimeScreens/testCoverage) by id.
|
|
93
|
+
const fresh = inferFeatures({ topo: scan.staticTopology, auth: scan.auth, onboarding: scan.onboarding, paywalls: scan.paywalls, hasForms: hasFormLibrary(root) });
|
|
94
|
+
const prevById = new Map(map.features.map((f) => [f.id, f]));
|
|
95
|
+
map.features = fresh.map((f) => {
|
|
96
|
+
const prev = prevById.get(f.id);
|
|
97
|
+
if (!prev)
|
|
98
|
+
return f;
|
|
99
|
+
return { ...f, runtimeScreens: prev.runtimeScreens, testCoverage: prev.testCoverage, actions: prev.actions.length ? prev.actions : f.actions };
|
|
100
|
+
});
|
|
101
|
+
addProvenance(map, makeProvenance('code_scan', at, `Static scan: ${scan.staticTopology.screens.length} screen(s), router=${scan.staticTopology.router ?? 'none'}`, { targetType: 'map', refs: scan.staticTopology.parserNotes.slice(0, 3) }));
|
|
102
|
+
if (scan.appIdentity.androidPackage || scan.appIdentity.iosBundleId) {
|
|
103
|
+
addProvenance(map, makeProvenance('app_config', at, `App identity from config: ${scan.appIdentity.androidPackage ?? scan.appIdentity.iosBundleId}`, { targetType: 'identity' }));
|
|
104
|
+
}
|
|
105
|
+
// Code index over the collected files.
|
|
106
|
+
return buildCodeIndex(root, scan.collectedFiles, at);
|
|
107
|
+
}
|
|
108
|
+
/** Build (or incrementally update) the app map. Filesystem-bound but never throws on scan errors. */
|
|
109
|
+
export function buildAppMap(root, opts) {
|
|
110
|
+
const fw = detectFramework(root);
|
|
111
|
+
const fallbackProject = projectIdentity(root, fw, null);
|
|
112
|
+
const loaded = loadAppMap(root, fallbackProject, opts.at);
|
|
113
|
+
let map = loaded.map ?? emptyAppMap(fallbackProject, opts.at);
|
|
114
|
+
// refresh project identity (framework can change as the repo evolves)
|
|
115
|
+
map.project = { ...map.project, ...projectIdentity(root, fw, map.project.packageName) };
|
|
116
|
+
let codeIndex = null;
|
|
117
|
+
const doRescan = opts.mode === 'static_only' || opts.mode === 'full' || !loaded.existed || opts.forceRescan === true;
|
|
118
|
+
let rescanned = false;
|
|
119
|
+
if (doRescan) {
|
|
120
|
+
codeIndex = applyStaticScan(map, root, opts.at);
|
|
121
|
+
rescanned = true;
|
|
122
|
+
}
|
|
123
|
+
let mergeResult;
|
|
124
|
+
if ((opts.mode === 'runtime_merge' || opts.mode === 'full') && opts.exploreGraph) {
|
|
125
|
+
mergeResult = mergeRuntimeGraph(map, opts.exploreGraph, { sessionId: opts.sessionId, at: opts.at });
|
|
126
|
+
addProvenance(map, makeProvenance('runtime', opts.at, `Runtime merge: +${mergeResult.newRuntimeScreens} new, ~${mergeResult.updatedRuntimeScreens} updated, ${mergeResult.linkedScreens} linked`, { targetType: 'map', refs: opts.sessionId ? [opts.sessionId] : [] }));
|
|
127
|
+
}
|
|
128
|
+
let firstRunApply;
|
|
129
|
+
if (opts.firstRunPatches?.length) {
|
|
130
|
+
firstRunApply = applyFirstRunPatches(map, opts.firstRunPatches, opts.at);
|
|
131
|
+
addProvenance(map, makeProvenance('runtime', opts.at, `First-run merge: ${firstRunApply.newScreens} new, ${firstRunApply.updatedScreens} updated runtime screen(s)`, { targetType: 'map', refs: opts.sessionId ? [opts.sessionId] : [] }));
|
|
132
|
+
}
|
|
133
|
+
if (opts.appIdentityHints) {
|
|
134
|
+
map.appIdentity.androidPackage = opts.appIdentityHints.androidPackage ?? map.appIdentity.androidPackage;
|
|
135
|
+
map.appIdentity.iosBundleId = opts.appIdentityHints.iosBundleId ?? map.appIdentity.iosBundleId;
|
|
136
|
+
map.appIdentity.artifactHash = opts.appIdentityHints.artifactHash ?? map.appIdentity.artifactHash;
|
|
137
|
+
map.appIdentity.environment = opts.appIdentityHints.environment ?? map.appIdentity.environment;
|
|
138
|
+
}
|
|
139
|
+
recomputeCoverage(map);
|
|
140
|
+
recomputeConfidence(map);
|
|
141
|
+
// Derived issue summaries from the durable issue ledger (SWIPIUM-REQ-08). Best-effort — the issue
|
|
142
|
+
// ledger is an additive context layer and must never break an app-map build.
|
|
143
|
+
try {
|
|
144
|
+
applyIssueSummariesToAppMap(map, root, opts.at);
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
/* best-effort */
|
|
148
|
+
}
|
|
149
|
+
map.updatedAt = opts.at;
|
|
150
|
+
if (!map.generatedAt)
|
|
151
|
+
map.generatedAt = opts.at;
|
|
152
|
+
let save;
|
|
153
|
+
if (opts.persist !== false) {
|
|
154
|
+
save = saveAppMap(root, map);
|
|
155
|
+
if (opts.includeCodeIndex !== false)
|
|
156
|
+
saveIndexes(root, codeIndex, map.features);
|
|
157
|
+
// Fix 8: durably remember this project so its app-map resource URI resolves across restarts.
|
|
158
|
+
rememberProject(root, { packageName: map.project.packageName, framework: map.project.framework, at: opts.at });
|
|
159
|
+
}
|
|
160
|
+
return { map, codeIndex, mergeResult, firstRunApply, migration: loaded.migration, save, rescanned };
|
|
161
|
+
}
|
|
162
|
+
/** Read just the coverage counts from an existing map (zeros if none) — for computing a delta. */
|
|
163
|
+
export function quickCoverage(root, at) {
|
|
164
|
+
const fw = detectFramework(root);
|
|
165
|
+
const loaded = loadAppMap(root, projectIdentity(root, fw, null), at);
|
|
166
|
+
const c = loaded.map?.coverage;
|
|
167
|
+
return { overallPercent: c?.overallPercent ?? 0, runtimeScreens: c?.runtimeScreens ?? 0, staticScreens: c?.staticScreens ?? 0 };
|
|
168
|
+
}
|
|
169
|
+
/** Compact, context-friendly summary of a map for tool text + structured results. */
|
|
170
|
+
export function summarizeMap(map) {
|
|
171
|
+
const gaps = [];
|
|
172
|
+
if (map.runtimeTopology.unvisitedStaticScreens.length)
|
|
173
|
+
gaps.push(`${map.runtimeTopology.unvisitedStaticScreens.length} static screen(s) never visited at runtime`);
|
|
174
|
+
const uncovered = map.features.filter((f) => f.testCoverage === 'none');
|
|
175
|
+
if (uncovered.length)
|
|
176
|
+
gaps.push(`${uncovered.length} feature(s) with no coverage: ${uncovered.slice(0, 4).map((f) => f.title).join(', ')}`);
|
|
177
|
+
const hypotheses = map.features.filter((f) => f.status === 'hypothesis');
|
|
178
|
+
if (hypotheses.length)
|
|
179
|
+
gaps.push(`${hypotheses.length} low-confidence feature hypothesis(es)`);
|
|
180
|
+
return {
|
|
181
|
+
framework: map.project.framework,
|
|
182
|
+
router: map.staticTopology.router,
|
|
183
|
+
appIdentity: map.appIdentity,
|
|
184
|
+
staticScreens: map.staticTopology.screens.length,
|
|
185
|
+
runtimeScreens: map.runtimeTopology.screens.length,
|
|
186
|
+
features: map.features.map((f) => ({ id: f.id, title: f.title, status: f.status, testCoverage: f.testCoverage, confidence: f.confidence })),
|
|
187
|
+
coverage: map.coverage,
|
|
188
|
+
confidence: map.confidence.overall,
|
|
189
|
+
topGaps: gaps.slice(0, 6),
|
|
190
|
+
parserNotes: map.staticTopology.parserNotes.slice(0, 4),
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
//# sourceMappingURL=build.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/appMap/build.ts"],"names":[],"mappings":"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"}
|