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
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// qa_screenshot — capture the screen, save as a session artifact, return a resource URI
|
|
2
|
+
// (not inline bytes, DESIGN §4). Sensitive-mode: if a secure field is on screen, withhold
|
|
3
|
+
// by default (pixels can't be redacted) unless force:true.
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { qaOk, qaError, qaStop } from '../lib/result.js';
|
|
6
|
+
import { isSecureNode } from '../lib/redact.js';
|
|
7
|
+
import { sensitiveRefusal } from '../lib/sensitive.js';
|
|
8
|
+
import { captureCoordinateSpace } from '../lib/coordSpace.js';
|
|
9
|
+
import { getDriver } from '../session/attach.js';
|
|
10
|
+
export function registerScreenshot(server, sessions) {
|
|
11
|
+
server.registerTool('qa_screenshot', {
|
|
12
|
+
title: 'Capture a screenshot',
|
|
13
|
+
description: 'Capture the current screen, save it as a session artifact, and return a resource URI (swipium://…) — not inline image bytes. If a secure field (password/OTP) is on screen the capture is withheld unless force:true, since screenshot pixels can\'t be redacted. Requires qa_prepare_target.',
|
|
14
|
+
inputSchema: { sessionId: z.string(), force: z.boolean().optional(), reason: z.string().optional().describe('Short label of what this screenshot documents (shown in qa_report).') },
|
|
15
|
+
}, async ({ sessionId, force, reason }) => {
|
|
16
|
+
const session = sessions.get(sessionId);
|
|
17
|
+
const { driver } = session ? await getDriver(session) : { driver: undefined };
|
|
18
|
+
if (!session || !driver) {
|
|
19
|
+
return qaError({
|
|
20
|
+
what: 'No device attached to this session',
|
|
21
|
+
changedState: false,
|
|
22
|
+
retrySafe: true,
|
|
23
|
+
nextSteps: ['Call qa_prepare_target first.'],
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
if (session.sensitive)
|
|
27
|
+
return sensitiveRefusal('Screenshot');
|
|
28
|
+
const stopReason = sessions.budgetStop(session);
|
|
29
|
+
if (stopReason)
|
|
30
|
+
return qaStop(stopReason, { counters: session.counters, mode: session.mode });
|
|
31
|
+
// Sensitive screen guard (M6): based on the latest snapshot's nodes.
|
|
32
|
+
const hasSecure = session.lastSnapshot
|
|
33
|
+
? [...session.lastSnapshot.fullByRef.values()].some((n) => isSecureNode(n))
|
|
34
|
+
: false;
|
|
35
|
+
if (hasSecure && !force) {
|
|
36
|
+
return qaError({
|
|
37
|
+
what: 'Screenshot withheld — a secure field (password/OTP) is on screen',
|
|
38
|
+
changedState: false,
|
|
39
|
+
retrySafe: true,
|
|
40
|
+
nextSteps: ['Pass force:true to capture anyway (pixels are NOT redactable), or screenshot a non-sensitive screen.'],
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
const png = await driver.screenshot();
|
|
45
|
+
const n = ++session.screenshotCount;
|
|
46
|
+
const uri = sessions.saveArtifact(session, 'screenshot', `screenshot-${n}.png`, png, 'image/png', reason);
|
|
47
|
+
const rec = sessions.findArtifact(uri).rec;
|
|
48
|
+
sessions.bump(session, 'screenshots');
|
|
49
|
+
const coordinateSpace = await captureCoordinateSpace(driver, png);
|
|
50
|
+
const budgetReached = sessions.budgetStop(session);
|
|
51
|
+
return qaOk({ uri, path: rec.path, bytes: png.length, coordinateSpace, sensitiveForced: hasSecure ? true : undefined, counters: session.counters, ...(budgetReached ? { budgetReached } : {}) }, `Saved screenshot #${n} (${png.length} bytes) → ${uri}\ncoordinate space: ${coordinateSpace.screenshot?.width}x${coordinateSpace.screenshot?.height} screenshot px, scale ${coordinateSpace.scale}, ${coordinateSpace.orientation}${budgetReached ? `\n⏹ budget reached: ${budgetReached} — call qa_report.` : ''}`);
|
|
52
|
+
}
|
|
53
|
+
catch (e) {
|
|
54
|
+
return qaError({
|
|
55
|
+
what: `Screenshot failed: ${String(e)}`,
|
|
56
|
+
changedState: false,
|
|
57
|
+
retrySafe: true,
|
|
58
|
+
nextSteps: ['Confirm the device is still online (`adb devices`).'],
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=screenshot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screenshot.js","sourceRoot":"","sources":["../../src/tools/screenshot.ts"],"names":[],"mappings":"AAAA,wFAAwF;AACxF,0FAA0F;AAC1F,2DAA2D;AAE3D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAGjD,MAAM,UAAU,kBAAkB,CAAC,MAAiB,EAAE,QAAsB;IAC1E,MAAM,CAAC,YAAY,CACjB,eAAe,EACf;QACE,KAAK,EAAE,sBAAsB;QAC7B,WAAW,EACT,+RAA+R;QACjS,WAAW,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,qEAAqE,CAAC,EAAE;KACrL,EACD,KAAK,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE;QACrC,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACxC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,MAAM,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;QAC9E,IAAI,CAAC,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC;YACxB,OAAO,OAAO,CAAC;gBACb,IAAI,EAAE,oCAAoC;gBAC1C,YAAY,EAAE,KAAK;gBACnB,SAAS,EAAE,IAAI;gBACf,SAAS,EAAE,CAAC,+BAA+B,CAAC;aAC7C,CAAC,CAAC;QACL,CAAC;QAED,IAAI,OAAO,CAAC,SAAS;YAAE,OAAO,gBAAgB,CAAC,YAAY,CAAC,CAAC;QAE7D,MAAM,UAAU,GAAG,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAChD,IAAI,UAAU;YAAE,OAAO,MAAM,CAAC,UAAU,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;QAE9F,qEAAqE;QACrE,MAAM,SAAS,GAAG,OAAO,CAAC,YAAY;YACpC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YAC3E,CAAC,CAAC,KAAK,CAAC;QACV,IAAI,SAAS,IAAI,CAAC,KAAK,EAAE,CAAC;YACxB,OAAO,OAAO,CAAC;gBACb,IAAI,EAAE,kEAAkE;gBACxE,YAAY,EAAE,KAAK;gBACnB,SAAS,EAAE,IAAI;gBACf,SAAS,EAAE,CAAC,sGAAsG,CAAC;aACpH,CAAC,CAAC;QACL,CAAC;QAED,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,UAAU,EAAE,CAAC;YACtC,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,eAAe,CAAC;YACpC,MAAM,GAAG,GAAG,QAAQ,CAAC,YAAY,CAAC,OAAO,EAAE,YAAY,EAAE,cAAc,CAAC,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC;YAC1G,MAAM,GAAG,GAAG,QAAQ,CAAC,YAAY,CAAC,GAAG,CAAE,CAAC,GAAG,CAAC;YAC5C,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;YACtC,MAAM,eAAe,GAAG,MAAM,sBAAsB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;YAClE,MAAM,aAAa,GAAG,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YACnD,OAAO,IAAI,CACT,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,EAAE,eAAe,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EACnL,qBAAqB,CAAC,KAAK,GAAG,CAAC,MAAM,aAAa,GAAG,uBAAuB,eAAe,CAAC,UAAU,EAAE,KAAK,IAAI,eAAe,CAAC,UAAU,EAAE,MAAM,yBAAyB,eAAe,CAAC,KAAK,KAAK,eAAe,CAAC,WAAW,GAAG,aAAa,CAAC,CAAC,CAAC,uBAAuB,aAAa,oBAAoB,CAAC,CAAC,CAAC,EAAE,EAAE,CACpT,CAAC;QACJ,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,OAAO,CAAC;gBACb,IAAI,EAAE,sBAAsB,MAAM,CAAC,CAAC,CAAC,EAAE;gBACvC,YAAY,EAAE,KAAK;gBACnB,SAAS,EAAE,IAAI;gBACf,SAAS,EAAE,CAAC,qDAAqD,CAAC;aACnE,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// qa_smoke (PHASE3-PLAN §7.2) — server-side smoke orchestration. Runs the whole loop WITHOUT
|
|
2
|
+
// the model mediating each step (the context-efficiency + determinism win): launch the app,
|
|
3
|
+
// run the deterministic baseline (snapshot quality + Tier-1 health + an evidence screenshot),
|
|
4
|
+
// then run every saved flow (.swipium/flows/*.yaml). Records a structured qa_note per workflow
|
|
5
|
+
// and points the agent at qa_report. One call replaces a long hand-driven chain.
|
|
6
|
+
//
|
|
7
|
+
// Scope note: a single honest orchestrator. Generic credential-login / per-screen-visual smokes
|
|
8
|
+
// are app-specific and fragile to synthesize, so login is handled by authoring a login *flow*
|
|
9
|
+
// (run here automatically) rather than a separate qa_login_smoke that guesses.
|
|
10
|
+
import { z } from 'zod';
|
|
11
|
+
import { qaOk, qaError } from '../lib/result.js';
|
|
12
|
+
import { getDriver } from '../session/attach.js';
|
|
13
|
+
import { runSmoke } from '../services/smoke.js';
|
|
14
|
+
export function registerSmoke(server, sessions) {
|
|
15
|
+
server.registerTool('qa_smoke', {
|
|
16
|
+
title: 'Run a smoke test',
|
|
17
|
+
description: 'Run a full smoke server-side (no per-step model round-trips): optionally launch the app, run the deterministic baseline (snapshot quality + Tier-1 health + an evidence screenshot), then run every saved flow under .swipium/flows. Records a qa_note per workflow and tells you to call qa_report. Use `variables` for flow ${VARS} (e.g. TEST_EMAIL). Requires a session with a prepared device.',
|
|
18
|
+
inputSchema: {
|
|
19
|
+
sessionId: z.string(),
|
|
20
|
+
launch: z.boolean().optional().describe('Launch the app first (default true if the session has an appId).'),
|
|
21
|
+
runFlows: z.boolean().optional().describe('Run saved .swipium/flows (default true).'),
|
|
22
|
+
variables: z.record(z.string()).optional().describe('Values for ${VAR} placeholders in flows (merged over process.env).'),
|
|
23
|
+
},
|
|
24
|
+
}, async ({ sessionId, launch, runFlows, variables }) => {
|
|
25
|
+
const session = sessions.get(sessionId);
|
|
26
|
+
const { driver: d } = session ? await getDriver(session) : { driver: undefined };
|
|
27
|
+
if (!session || !d) {
|
|
28
|
+
return qaError({ what: 'No device attached to this session', changedState: false, retrySafe: true, nextSteps: ['Call qa_prepare_target first, then qa_smoke.'] });
|
|
29
|
+
}
|
|
30
|
+
const result = await runSmoke(sessions, session, d, { launch, runFlows, variables });
|
|
31
|
+
const launchOutcome = result.baseline.launch?.outcome ?? 'unknown';
|
|
32
|
+
const summary = `qa_smoke done — launch=${launchOutcome}, flows ${result.flowsPassed}/${result.flowsTotal} passed.\n` +
|
|
33
|
+
`baseline: ${JSON.stringify(result.baseline.launch)}\n` +
|
|
34
|
+
(result.flows.length ? result.flows.map((f) => `${f.passed ? '✓' : '✗'} ${f.name}${f.passed ? '' : ` — ${f.reason}`}`).join('\n') : 'no saved flows (.swipium/flows is empty)') +
|
|
35
|
+
`\nCall qa_report to summarize.`;
|
|
36
|
+
return qaOk({ baseline: result.baseline.launch, flows: result.flows, flowsPassed: result.flowsPassed, flowsTotal: result.flowsTotal, counters: session.counters }, summary);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=smoke.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"smoke.js","sourceRoot":"","sources":["../../src/tools/smoke.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// qa_snapshot — the observation layer.
|
|
2
|
+
// Snapshot returns compact @eN refs + a snapshotQuality verdict (+ optional diff).
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { qaOk, qaError } from '../lib/result.js';
|
|
5
|
+
import { parseSnapshot, signature, renderElements } from '../snapshot/parse.js';
|
|
6
|
+
import { presentElements } from '../snapshot/present.js';
|
|
7
|
+
import { makeRedactor } from '../lib/redact.js';
|
|
8
|
+
import { detectTreeOverlays, classifyForeground } from '../snapshot/overlays.js';
|
|
9
|
+
import { detectAuthScreen } from '../oracle/auth.js';
|
|
10
|
+
import { getDriver, REHYDRATE_NOTE } from '../session/attach.js';
|
|
11
|
+
export function registerSnapshot(server, sessions) {
|
|
12
|
+
server.registerTool('qa_snapshot', {
|
|
13
|
+
title: 'Snapshot the screen',
|
|
14
|
+
description: 'Capture the current screen as compact, addressable elements (@e1, @e2 …) with a snapshotQuality verdict (good/partial/poor — whether the app is automation-friendly). Defaults to interactive-only and NO screenshot to stay cheap. Use the @eN refs as targets for qa_act. Re-snapshot after navigation because refs invalidate.',
|
|
15
|
+
inputSchema: {
|
|
16
|
+
sessionId: z.string(),
|
|
17
|
+
diff: z.boolean().optional().describe('Return only what changed vs the previous snapshot (needs a prior snapshot in this session).'),
|
|
18
|
+
},
|
|
19
|
+
}, async ({ sessionId, diff }) => {
|
|
20
|
+
const session = sessions.get(sessionId);
|
|
21
|
+
const { driver, rehydrated } = session ? await getDriver(session) : { driver: undefined, rehydrated: false };
|
|
22
|
+
if (!session || !driver) {
|
|
23
|
+
return qaError({
|
|
24
|
+
what: 'No device attached to this session',
|
|
25
|
+
changedState: false,
|
|
26
|
+
retrySafe: true,
|
|
27
|
+
nextSteps: ['Call qa_prepare_target first.'],
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
if (driver.kind === 'simulator') {
|
|
31
|
+
return qaError({
|
|
32
|
+
what: 'A structured UI tree is not available on the iOS simulator backend',
|
|
33
|
+
changedState: false,
|
|
34
|
+
retrySafe: false,
|
|
35
|
+
failureCode: 'BACKEND_UNSUPPORTED',
|
|
36
|
+
nextSteps: ['Attach WebDriverAgent with qa_wda for a structured UI tree. Without WDA, use qa_screenshot + qa_assert_visual.'],
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
// Already in visual-fallback (uiautomator can't reach idle on this app) → don't keep
|
|
40
|
+
// hammering structured dumps; point the agent at the visual tools immediately.
|
|
41
|
+
if (session.mode === 'visual-fallback') {
|
|
42
|
+
return qaError({
|
|
43
|
+
what: 'Session is in visual-fallback mode — structured snapshots are unavailable on this screen.',
|
|
44
|
+
changedState: false,
|
|
45
|
+
retrySafe: false,
|
|
46
|
+
failureCode: 'VISUAL_ONLY_SCREEN',
|
|
47
|
+
nextSteps: ['Use qa_screenshot, then qa_act with coordinate targets (durationMs press). qa_check_health still works.'],
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
let xml;
|
|
51
|
+
try {
|
|
52
|
+
xml = await driver.dumpXml();
|
|
53
|
+
}
|
|
54
|
+
catch (e) {
|
|
55
|
+
// Classify repeated idle-state / dump failures and switch to visual fallback.
|
|
56
|
+
const msg = String(e);
|
|
57
|
+
const idle = /idle|could not get idle|dump/i.test(msg);
|
|
58
|
+
sessions.bump(session, 'snapshotFailures');
|
|
59
|
+
const failures = session.counters.snapshotFailures;
|
|
60
|
+
if (failures >= session.budget.maxSnapshotFailures) {
|
|
61
|
+
sessions.setMode(session, 'visual-fallback');
|
|
62
|
+
return qaError({
|
|
63
|
+
what: `Could not produce a UI tree after ${failures} attempts${idle ? ' (never reached idle)' : ''} — likely a looping animation, dev overlay, web view, or canvas.`,
|
|
64
|
+
changedState: false,
|
|
65
|
+
retrySafe: false,
|
|
66
|
+
failureCode: 'VISUAL_ONLY_SCREEN',
|
|
67
|
+
nextSteps: [
|
|
68
|
+
'Switched session to visual-fallback mode.',
|
|
69
|
+
'Use qa_screenshot, then qa_act with coordinate targets (taps default to a short press).',
|
|
70
|
+
'qa_check_health stays available (crash/ANR/foreground).',
|
|
71
|
+
],
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
return qaError({
|
|
75
|
+
what: `Snapshot (UI tree dump) failed (${failures}/${session.budget.maxSnapshotFailures})${idle ? ' — never reached idle' : ''}: ${msg}`,
|
|
76
|
+
changedState: false,
|
|
77
|
+
retrySafe: true,
|
|
78
|
+
failureCode: 'SNAPSHOT_FAILED',
|
|
79
|
+
nextSteps: [`Retry; after ${session.budget.maxSnapshotFailures} failures Swipium switches to visual-fallback (screenshots).`],
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
const parsed = parseSnapshot(xml, { interactiveOnly: true });
|
|
83
|
+
const prev = session.lastSnapshot;
|
|
84
|
+
const newSigs = new Set(parsed.elements.map(signature));
|
|
85
|
+
const redact = makeRedactor(session.secrets);
|
|
86
|
+
const { elements: shown, rendered } = presentElements(parsed.elements, redact);
|
|
87
|
+
let diffText = '';
|
|
88
|
+
let diffPayload;
|
|
89
|
+
if (diff && prev) {
|
|
90
|
+
const added = parsed.elements.filter((e) => !prev.signatures.has(signature(e)));
|
|
91
|
+
const removed = [...prev.signatures].filter((s) => !newSigs.has(s));
|
|
92
|
+
const addedShown = presentElements(added, redact).elements;
|
|
93
|
+
diffPayload = { added: addedShown.map((e) => e.ref + ' ' + (e.label ?? e.text ?? e.role)), removed };
|
|
94
|
+
diffText = `\nDIFF vs previous: +${added.length} / -${removed.length}\n` + renderElements(addedShown);
|
|
95
|
+
}
|
|
96
|
+
// persist for inspect + next diff (fullByRef keeps raw nodes; masking happens on emit)
|
|
97
|
+
session.lastSnapshot = { fullByRef: parsed.fullByRef, signatures: newSigs, allNodes: parsed.allNodes };
|
|
98
|
+
// Auth-state awareness (P1.5): note login screens; the FIRST screen seen sets authedAtStart.
|
|
99
|
+
const auth = detectAuthScreen(parsed.allNodes);
|
|
100
|
+
if (session.auth.authedAtStart === undefined)
|
|
101
|
+
sessions.markAuth(session, { authedAtStart: !auth.isLoginScreen });
|
|
102
|
+
if (auth.isLoginScreen && !session.auth.loginScreenSeen)
|
|
103
|
+
sessions.markAuth(session, { loginScreenSeen: true, loginScreenSeenAt: Date.now() });
|
|
104
|
+
// Overlay awareness (CR4): tree overlays (LogBox/dialog/snackbar) + keyboard + foreground class.
|
|
105
|
+
const overlays = detectTreeOverlays(parsed.allNodes, parsed.screen);
|
|
106
|
+
if (await driver.imeShown())
|
|
107
|
+
overlays.push({ type: 'keyboard', detail: 'soft keyboard shown' });
|
|
108
|
+
const fgOverlay = classifyForeground(session.appId, await driver.foregroundOwner().catch(() => 'unknown'));
|
|
109
|
+
if (fgOverlay)
|
|
110
|
+
overlays.push(fgOverlay);
|
|
111
|
+
const q = parsed.quality;
|
|
112
|
+
const header = (rehydrated ? REHYDRATE_NOTE + '\n' : '') +
|
|
113
|
+
`quality=${q.verdict} (${q.reasons.join('; ')})\n` +
|
|
114
|
+
`screen=${parsed.screen[0]}x${parsed.screen[1]} elements=${parsed.elements.length} totalNodes=${parsed.total}` +
|
|
115
|
+
(overlays.length ? `\noverlays: ${overlays.map((o) => o.type).join(', ')} (clear with qa_clear_overlay)` : '');
|
|
116
|
+
return qaOk({
|
|
117
|
+
quality: q.verdict,
|
|
118
|
+
qualityReasons: q.reasons,
|
|
119
|
+
qualitySignals: q.signals,
|
|
120
|
+
screen: parsed.screen,
|
|
121
|
+
elementCount: parsed.elements.length,
|
|
122
|
+
totalNodes: parsed.total,
|
|
123
|
+
overlays,
|
|
124
|
+
elements: shown,
|
|
125
|
+
...(diffPayload ? { diff: diffPayload } : {}),
|
|
126
|
+
}, `${header}\n\n${rendered}${diffText}`);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=snapshot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../../src/tools/snapshot.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
// qa_start_session — resolve projectRoot (roots → arg → ask) and open a session.
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { qaOk, qaError } from '../lib/result.js';
|
|
6
|
+
import { resolveProjectRoot } from '../context/projectRoot.js';
|
|
7
|
+
import { loadProjectConfig } from '../cli/scan.js';
|
|
8
|
+
import { SWIPIUM_VERSION, TOOL_COUNT } from '../version.js';
|
|
9
|
+
import { getSchemaHash } from '../lib/schemaHash.js';
|
|
10
|
+
import { BUDGET_PROFILES } from '../session/store.js';
|
|
11
|
+
const PROFILE_KEYS = Object.keys(BUDGET_PROFILES);
|
|
12
|
+
/** Load declared fixtures from <root>/.swipium/fixtures.json (best-effort, array or {fixtures:[]}). */
|
|
13
|
+
export function loadProjectFixtures(root) {
|
|
14
|
+
const p = join(root, '.swipium', 'fixtures.json');
|
|
15
|
+
if (!existsSync(p))
|
|
16
|
+
return [];
|
|
17
|
+
try {
|
|
18
|
+
const raw = JSON.parse(readFileSync(p, 'utf8'));
|
|
19
|
+
const arr = Array.isArray(raw) ? raw : Array.isArray(raw?.fixtures) ? raw.fixtures : [];
|
|
20
|
+
return arr.filter((f) => f && typeof f.name === 'string');
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return [];
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export function registerStartSession(server, sessions) {
|
|
27
|
+
server.registerTool('qa_start_session', {
|
|
28
|
+
title: 'Start a QA session',
|
|
29
|
+
description: 'Resolve the project root and open a QA session. Resolution order: MCP workspace roots → explicit `projectRoot` arg → ask. NEVER uses the server cwd. A session enforces a BUDGET (default: 8 min / 20 actions / 8 screenshots / 3 snapshot-failures / 3 no-change-actions). Pass `profile` to size the time budget to the workflow (guardrail 8m / login_smoke 10m / full_smoke 15m / install_smoke 20m) — Swipium WARNS if your explicit budget is likely too low. Pass `fixtures` (or add .swipium/fixtures.json) to declare preconditions so unmet ones report as blocked-with-setup, not failures. Pass `responseMode` (compact|normal|verbose) to control transcript size: compact drops the duplicated JSON from the text channel (structured data is unchanged) — recommended for long smoke runs. Call this before snapshot/act tools.',
|
|
30
|
+
inputSchema: {
|
|
31
|
+
projectRoot: z.string().optional().describe('Absolute path to the app project. Optional if the client exposes a workspace root.'),
|
|
32
|
+
responseMode: z
|
|
33
|
+
.enum(['compact', 'normal', 'verbose'])
|
|
34
|
+
.optional()
|
|
35
|
+
.describe('Text-channel verbosity for every tool in this session. compact = summary + artifact URIs only (structuredContent stays full); normal (default) = summary + JSON; verbose = everything.'),
|
|
36
|
+
sensitive: z
|
|
37
|
+
.boolean()
|
|
38
|
+
.optional()
|
|
39
|
+
.describe('Sensitive mode: refuse all screenshots, screen recordings, and on-screen-error evidence capture for this session (no pixels leave the device). For privacy-sensitive apps.'),
|
|
40
|
+
profile: z.enum(['guardrail', 'login_smoke', 'full_smoke', 'install_smoke']).optional().describe('Budget class — sizes the time budget to the intended workflow.'),
|
|
41
|
+
budget: z
|
|
42
|
+
.object({
|
|
43
|
+
maxMinutes: z.number().optional(),
|
|
44
|
+
maxActions: z.number().optional(),
|
|
45
|
+
maxScreenshots: z.number().optional(),
|
|
46
|
+
maxSnapshotFailures: z.number().optional(),
|
|
47
|
+
maxNoChangeActions: z.number().optional(),
|
|
48
|
+
})
|
|
49
|
+
.optional()
|
|
50
|
+
.describe('Override default budget caps.'),
|
|
51
|
+
fixtures: z
|
|
52
|
+
.array(z.object({
|
|
53
|
+
name: z.string(),
|
|
54
|
+
description: z.string().optional(),
|
|
55
|
+
requiredState: z.string().optional(),
|
|
56
|
+
recommendedSetup: z.string().optional(),
|
|
57
|
+
testAccount: z.string().optional(),
|
|
58
|
+
apkPath: z.string().optional(),
|
|
59
|
+
value: z.string().optional().describe('Non-secret safe test input (e.g. flight number/search term) for exploration text entry.'),
|
|
60
|
+
disposable: z.boolean().optional().describe('True only for disposable accounts/data that destructive QA may mutate or delete.'),
|
|
61
|
+
environment: z.string().optional().describe('Environment label. Use "test" for non-production disposable test state.'),
|
|
62
|
+
fields: z
|
|
63
|
+
.record(z.object({
|
|
64
|
+
value: z.string().optional(),
|
|
65
|
+
var: z.string().optional().describe('Environment/secure-input variable name to read at runtime.'),
|
|
66
|
+
secret: z.boolean().optional(),
|
|
67
|
+
generator: z.enum(['email', 'email_address', 'person', 'person_name', 'full_name', 'display_name', 'number', 'numeric', 'text', 'city', 'city_name', 'country', 'country_name', 'color', 'phone', 'phone_number', 'mobile', 'date', 'date_iso']).optional(),
|
|
68
|
+
role: z.string().optional(),
|
|
69
|
+
inputType: z.string().optional(),
|
|
70
|
+
}))
|
|
71
|
+
.optional()
|
|
72
|
+
.describe('Typed fixture catalog for form entry. Fields match by label/id/role and may use a fixed value, variable, or safe generator.'),
|
|
73
|
+
seed: z
|
|
74
|
+
.object({
|
|
75
|
+
type: z.enum(['deeplink', 'script', 'api']),
|
|
76
|
+
url: z.string().optional(),
|
|
77
|
+
command: z.union([z.string(), z.array(z.string())]).optional().describe('script: argv array preferred (string is deprecated).'),
|
|
78
|
+
method: z.string().optional(),
|
|
79
|
+
body: z.string().optional(),
|
|
80
|
+
headers: z.record(z.string()).optional(),
|
|
81
|
+
idempotent: z.boolean().optional().describe('True when re-running this seed safely converges to the same state.'),
|
|
82
|
+
cleanup: z
|
|
83
|
+
.object({
|
|
84
|
+
type: z.enum(['deeplink', 'script', 'api']),
|
|
85
|
+
url: z.string().optional(),
|
|
86
|
+
command: z.union([z.string(), z.array(z.string())]).optional().describe('script: argv array preferred (string is deprecated).'),
|
|
87
|
+
method: z.string().optional(),
|
|
88
|
+
body: z.string().optional(),
|
|
89
|
+
headers: z.record(z.string()).optional(),
|
|
90
|
+
})
|
|
91
|
+
.optional()
|
|
92
|
+
.describe('Optional teardown/rollback action used for state-profile transactions.'),
|
|
93
|
+
})
|
|
94
|
+
.optional()
|
|
95
|
+
.describe('Opt-in, consent-gated way to create this precondition during flows.'),
|
|
96
|
+
}))
|
|
97
|
+
.optional()
|
|
98
|
+
.describe('Declared preconditions/fixtures this run needs (merged with .swipium/fixtures.json).'),
|
|
99
|
+
},
|
|
100
|
+
}, async ({ projectRoot, profile, budget, fixtures, responseMode, sensitive }) => {
|
|
101
|
+
const resolved = await resolveProjectRoot(server, projectRoot);
|
|
102
|
+
if (!resolved.root) {
|
|
103
|
+
return qaError({
|
|
104
|
+
what: 'Could not resolve a project root',
|
|
105
|
+
changedState: false,
|
|
106
|
+
retrySafe: true,
|
|
107
|
+
nextSteps: ['Re-call qa_start_session with projectRoot="/absolute/path/to/app"'],
|
|
108
|
+
clientHint: resolved.hint,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
// Budget profile → recommended minutes; explicit profile sets the budget unless the
|
|
112
|
+
// caller also gave maxMinutes. Warn when the resulting time budget is below the class min.
|
|
113
|
+
const profileMinutes = profile ? BUDGET_PROFILES[profile] : undefined;
|
|
114
|
+
const effBudget = { ...(budget ?? {}) };
|
|
115
|
+
if (profileMinutes != null && effBudget.maxMinutes == null)
|
|
116
|
+
effBudget.maxMinutes = profileMinutes;
|
|
117
|
+
const warnings = [];
|
|
118
|
+
if (profileMinutes != null && effBudget.maxMinutes != null && effBudget.maxMinutes < profileMinutes) {
|
|
119
|
+
warnings.push(`Requested ${effBudget.maxMinutes}m is below the ${profile} class (${profileMinutes}m) — likely too short; consider raising maxMinutes.`);
|
|
120
|
+
}
|
|
121
|
+
// Surface a prior `swipium scan` (.swipium/config.json) so the agent knows the
|
|
122
|
+
// recommended profile / appId without re-scanning. Informational — never auto-overrides
|
|
123
|
+
// an explicit profile choice.
|
|
124
|
+
const projectConfig = loadProjectConfig(resolved.root);
|
|
125
|
+
if (projectConfig && !profile && typeof projectConfig.recommendedProfile === 'string') {
|
|
126
|
+
warnings.push(`swipium scan recommends profile "${projectConfig.recommendedProfile}" for this project (pass profile= to apply).`);
|
|
127
|
+
}
|
|
128
|
+
// Merge declared fixtures: project file first, then the call arg (arg can override by name).
|
|
129
|
+
const fileFixtures = loadProjectFixtures(resolved.root);
|
|
130
|
+
const byName = new Map();
|
|
131
|
+
for (const f of fileFixtures)
|
|
132
|
+
byName.set(f.name, f);
|
|
133
|
+
for (const f of fixtures ?? [])
|
|
134
|
+
byName.set(f.name, f);
|
|
135
|
+
const mergedFixtures = [...byName.values()];
|
|
136
|
+
const session = sessions.create(resolved.root, effBudget, { fixtures: mergedFixtures, budgetProfile: profile, responseMode, sensitive });
|
|
137
|
+
// Fix 8: durably register this project so its app-map resource URI resolves across restarts.
|
|
138
|
+
try {
|
|
139
|
+
const { rememberProject } = await import('../appMap/projectRegistry.js');
|
|
140
|
+
rememberProject(session.root, { packageName: typeof projectConfig?.appId === 'string' ? projectConfig.appId : null });
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
/* best-effort */
|
|
144
|
+
}
|
|
145
|
+
return qaOk({
|
|
146
|
+
sessionId: session.id,
|
|
147
|
+
swipiumVersion: SWIPIUM_VERSION,
|
|
148
|
+
schemaHash: getSchemaHash(),
|
|
149
|
+
toolCount: TOOL_COUNT,
|
|
150
|
+
projectRoot: session.root,
|
|
151
|
+
rootSource: resolved.source,
|
|
152
|
+
artifactsDir: session.dir,
|
|
153
|
+
budget: session.budget,
|
|
154
|
+
budgetProfile: profile ?? null,
|
|
155
|
+
responseMode: session.responseMode,
|
|
156
|
+
sensitive: session.sensitive,
|
|
157
|
+
scan: projectConfig
|
|
158
|
+
? { recommendedProfile: projectConfig.recommendedProfile ?? null, appId: projectConfig.appId ?? null, readiness: projectConfig.readiness ?? null }
|
|
159
|
+
: null,
|
|
160
|
+
declaredPreconditions: mergedFixtures,
|
|
161
|
+
warnings,
|
|
162
|
+
}, `Session ${session.id} started (Swipium v${SWIPIUM_VERSION}, ${TOOL_COUNT} tools — if your client lists fewer, restart it).\n` +
|
|
163
|
+
`projectRoot: ${session.root} (via ${resolved.source})\n` +
|
|
164
|
+
`budget: ${JSON.stringify(session.budget)}${profile ? ` (profile=${profile})` : ''}\n` +
|
|
165
|
+
(mergedFixtures.length ? `preconditions declared: ${mergedFixtures.map((f) => f.name).join(', ')}\n` : '') +
|
|
166
|
+
(warnings.length ? `⚠ ${warnings.join(' ')}` : ''));
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=startSession.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"startSession.js","sourceRoot":"","sources":["../../src/tools/startSession.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { normalizeCommand } from '../flows/seedExec.js';
|
|
3
|
+
function stable(value) {
|
|
4
|
+
if (Array.isArray(value))
|
|
5
|
+
return value.map(stable);
|
|
6
|
+
if (value && typeof value === 'object') {
|
|
7
|
+
return Object.fromEntries(Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => [k, stable(v)]));
|
|
8
|
+
}
|
|
9
|
+
return value;
|
|
10
|
+
}
|
|
11
|
+
function hash(value) {
|
|
12
|
+
return createHash('sha256').update(JSON.stringify(stable(value))).digest('hex');
|
|
13
|
+
}
|
|
14
|
+
function seedActionPreview(seed) {
|
|
15
|
+
if (!seed)
|
|
16
|
+
return null;
|
|
17
|
+
if (seed.type === 'script') {
|
|
18
|
+
const normalized = normalizeCommand(seed.command);
|
|
19
|
+
return {
|
|
20
|
+
type: 'script',
|
|
21
|
+
command: normalized.argv,
|
|
22
|
+
deprecatedStringCommand: normalized.deprecated || undefined,
|
|
23
|
+
parseError: normalized.parseError,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
if (seed.type === 'api')
|
|
27
|
+
return { type: 'api', method: seed.method ?? 'POST', url: seed.url ?? null, bodyHash: seed.body ? hash(seed.body).slice(0, 16) : null, headerKeys: Object.keys(seed.headers ?? {}).sort() };
|
|
28
|
+
return { type: 'deeplink', url: seed.url ?? null };
|
|
29
|
+
}
|
|
30
|
+
function seedPreview(seed) {
|
|
31
|
+
const preview = seedActionPreview(seed);
|
|
32
|
+
if (!preview)
|
|
33
|
+
return null;
|
|
34
|
+
return { ...preview, idempotent: seed?.idempotent ?? false, cleanup: seedActionPreview(seed?.cleanup) };
|
|
35
|
+
}
|
|
36
|
+
function cleanupFixtures(session, profile) {
|
|
37
|
+
if (!session)
|
|
38
|
+
return [];
|
|
39
|
+
return (profile.seed ?? [])
|
|
40
|
+
.map((s) => s.fixture)
|
|
41
|
+
.filter((name) => !!session.fixtures.find((f) => f.name === name)?.seed?.cleanup);
|
|
42
|
+
}
|
|
43
|
+
export function teardownMutations(profile, session) {
|
|
44
|
+
const explicit = (profile.teardown ?? [])
|
|
45
|
+
.filter((t) => t === 'networkOnline' || (typeof t === 'object' && t.networkOnline))
|
|
46
|
+
.map(() => 'networkOnline');
|
|
47
|
+
return [...explicit, ...cleanupFixtures(session, profile).map((name) => `seedCleanup:${name}`)];
|
|
48
|
+
}
|
|
49
|
+
export function stateProfileAffects(session, action, profile, path) {
|
|
50
|
+
const appId = profile.appId ?? session.appId ?? null;
|
|
51
|
+
const seedFixtures = (profile.seed ?? []).map((s) => s.fixture);
|
|
52
|
+
return {
|
|
53
|
+
action,
|
|
54
|
+
sessionId: session.id,
|
|
55
|
+
profileName: profile.name,
|
|
56
|
+
profilePath: path ?? null,
|
|
57
|
+
profileHash: hash(profile),
|
|
58
|
+
appId,
|
|
59
|
+
reset: profile.reset ?? null,
|
|
60
|
+
launch: profile.launch ?? null,
|
|
61
|
+
seedFixtures,
|
|
62
|
+
seedDetails: seedFixtures.map((name) => ({ fixture: name, seed: seedPreview(session.fixtures.find((f) => f.name === name)?.seed) })),
|
|
63
|
+
teardownMutations: teardownMutations(profile, session),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
export function hasStateProfileMutation(action, profile, session) {
|
|
67
|
+
if (action === 'verify')
|
|
68
|
+
return false;
|
|
69
|
+
if (action === 'teardown')
|
|
70
|
+
return teardownMutations(profile, session).length > 0;
|
|
71
|
+
return !!((profile.reset?.android && profile.reset.android !== 'none') ||
|
|
72
|
+
(profile.reset?.ios && profile.reset.ios !== 'none') ||
|
|
73
|
+
profile.launch ||
|
|
74
|
+
(profile.seed?.length ?? 0) > 0);
|
|
75
|
+
}
|
|
76
|
+
export function stateRisk(action, profile, session) {
|
|
77
|
+
if (profile.reset?.android === 'clearData' || profile.reset?.ios === 'reinstallApp' || profile.launch?.clearState)
|
|
78
|
+
return 'high';
|
|
79
|
+
const seedTypes = (profile.seed ?? []).map((s) => session.fixtures.find((f) => f.name === s.fixture)?.seed?.type);
|
|
80
|
+
const cleanupTypes = action === 'teardown' ? (profile.seed ?? []).map((s) => session.fixtures.find((f) => f.name === s.fixture)?.seed?.cleanup?.type) : [];
|
|
81
|
+
if (seedTypes.includes('script') || cleanupTypes.includes('script'))
|
|
82
|
+
return 'high';
|
|
83
|
+
if (seedTypes.includes('api') || cleanupTypes.includes('api') || profile.launch?.permissions || action === 'teardown')
|
|
84
|
+
return 'medium';
|
|
85
|
+
return 'low';
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/tools/state.ts"],"names":[],"mappings":"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"}
|