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,120 @@
|
|
|
1
|
+
// Smoke service (hardening P0.1) — the server-side smoke loop, extracted from the qa_smoke tool so
|
|
2
|
+
// BOTH the tool and qa_test_this execute mode run the exact same path (no MCP-over-transport). It
|
|
3
|
+
// launches the app, runs the deterministic baseline (snapshot quality + health + evidence shot),
|
|
4
|
+
// then runs every saved flow, recording a structured qa_note per workflow.
|
|
5
|
+
import { readFileSync } from 'node:fs';
|
|
6
|
+
import { parseSnapshot, signature } from '../snapshot/parse.js';
|
|
7
|
+
import { settle } from '../snapshot/settle.js';
|
|
8
|
+
import { checkHealth } from '../oracle/health.js';
|
|
9
|
+
import { recordHealthFindings } from '../oracle/record.js';
|
|
10
|
+
import { listFlowFiles } from '../flows/discover.js';
|
|
11
|
+
import { parseFlow } from '../flows/schema.js';
|
|
12
|
+
import { runFlow } from '../flows/run.js';
|
|
13
|
+
import { ciMutatingSteps } from '../ci/preflight.js';
|
|
14
|
+
function externalProviderSteps(flow) {
|
|
15
|
+
const out = [];
|
|
16
|
+
[...flow.setup, ...flow.steps, ...flow.teardown].forEach((step, index) => {
|
|
17
|
+
if (step.kind === 'tapOcrText' || step.kind === 'assertOcrText')
|
|
18
|
+
out.push({ step: index + 1, kind: step.kind });
|
|
19
|
+
});
|
|
20
|
+
return out;
|
|
21
|
+
}
|
|
22
|
+
export async function runSmoke(sessions, session, d, opts = {}) {
|
|
23
|
+
const note = (n) => sessions.addNote(session, { at: Date.now(), ...n });
|
|
24
|
+
const doLaunch = opts.launch ?? !!session.appId;
|
|
25
|
+
const baseline = {};
|
|
26
|
+
// ---- baseline: launch → snapshot quality → health → evidence screenshot ----
|
|
27
|
+
try {
|
|
28
|
+
if (doLaunch && session.appId) {
|
|
29
|
+
await d.launchApp(session.appId);
|
|
30
|
+
await settle(d, { timeoutMs: 8000 });
|
|
31
|
+
}
|
|
32
|
+
let quality;
|
|
33
|
+
if (session.mode !== 'visual-fallback') {
|
|
34
|
+
try {
|
|
35
|
+
const parsed = parseSnapshot(await d.dumpXml());
|
|
36
|
+
session.lastSnapshot = { fullByRef: parsed.fullByRef, signatures: new Set(parsed.elements.map(signature)), allNodes: parsed.allNodes };
|
|
37
|
+
quality = parsed.quality.verdict;
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
/* visual-only screen — health + screenshot still run */
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const health = await checkHealth(d, session.appId);
|
|
44
|
+
await recordHealthFindings(sessions, session, health.findings, d, health.foreground);
|
|
45
|
+
let shotUri;
|
|
46
|
+
try {
|
|
47
|
+
const png = await d.screenshot();
|
|
48
|
+
shotUri = sessions.saveArtifact(session, 'screenshot', `smoke-baseline-${Date.now()}.png`, png, 'image/png', 'qa_smoke baseline evidence');
|
|
49
|
+
sessions.bump(session, 'screenshots');
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
/* best-effort */
|
|
53
|
+
}
|
|
54
|
+
const outcome = !health.nativeHealthy || health.appStatus === 'error' ? 'fail' : 'pass';
|
|
55
|
+
note({
|
|
56
|
+
workflow: 'launch_smoke',
|
|
57
|
+
outcome,
|
|
58
|
+
category: outcome === 'fail' ? 'app_bug' : undefined,
|
|
59
|
+
reason: `native=${health.nativeHealthy ? 'ok' : health.nativeStatus} app=${health.appStatus}` + (quality ? ` quality=${quality}` : ''),
|
|
60
|
+
artifactUris: shotUri ? [shotUri] : undefined,
|
|
61
|
+
});
|
|
62
|
+
baseline.launch = { outcome, nativeHealth: health.nativeHealthy ? 'ok' : health.nativeStatus, appHealth: health.appStatus, quality, screenshotUri: shotUri };
|
|
63
|
+
}
|
|
64
|
+
catch (e) {
|
|
65
|
+
note({ workflow: 'launch_smoke', outcome: 'fail', category: 'mcp_limitation', reason: `baseline failed: ${String(e)}` });
|
|
66
|
+
baseline.launch = { outcome: 'fail', error: String(e) };
|
|
67
|
+
}
|
|
68
|
+
// ---- run saved flows ----
|
|
69
|
+
const flowResults = [];
|
|
70
|
+
if (opts.runFlows ?? true) {
|
|
71
|
+
for (const f of listFlowFiles(session.root)) {
|
|
72
|
+
const stop = sessions.budgetStop(session);
|
|
73
|
+
if (stop) {
|
|
74
|
+
note({ workflow: f.name, outcome: 'skipped', category: 'intentionally_skipped', reason: `budget: ${stop}` });
|
|
75
|
+
flowResults.push({ name: f.name, passed: false, reason: `skipped (budget)` });
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
const { flow, errors } = parseFlow(readFileSync(f.path, 'utf8'));
|
|
79
|
+
if (errors.length || !flow) {
|
|
80
|
+
note({ workflow: f.name, outcome: 'blocked', category: 'other', reason: `flow invalid: ${errors[0] ?? 'parse error'}`, requiredState: 'a valid flow file' });
|
|
81
|
+
flowResults.push({ name: f.name, passed: false, reason: 'invalid flow' });
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
const mutatingSteps = ciMutatingSteps(flow);
|
|
85
|
+
if (mutatingSteps.length) {
|
|
86
|
+
const reason = `mutating flow requires explicit qa_flow_run consent or CI policy: ${mutatingSteps.map((m) => `${m.step}:${m.kind}`).join(', ')}`;
|
|
87
|
+
note({ workflow: f.name, outcome: 'blocked', category: 'destructive_refused', reason, recommendedSetup: 'Run this flow with qa_flow_run and approve the flow_mutation_run consent, or run it through a CI policy that allowlists the mutation.' });
|
|
88
|
+
flowResults.push({ name: f.name, passed: false, reason });
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
const providerSteps = externalProviderSteps(flow);
|
|
92
|
+
if (providerSteps.length) {
|
|
93
|
+
const reason = `external visual-provider flow requires explicit qa_flow_run consent: ${providerSteps.map((m) => `${m.step}:${m.kind}`).join(', ')}`;
|
|
94
|
+
note({ workflow: f.name, outcome: 'blocked', category: 'destructive_refused', reason, recommendedSetup: 'Run this flow with qa_flow_run and approve the provider consent, or run it through reviewed CI configuration.' });
|
|
95
|
+
flowResults.push({ name: f.name, passed: false, reason });
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
let r;
|
|
99
|
+
try {
|
|
100
|
+
r = await runFlow(sessions, session, d, flow, { variables: opts.variables });
|
|
101
|
+
}
|
|
102
|
+
catch (e) {
|
|
103
|
+
note({ workflow: f.name, outcome: 'fail', category: 'mcp_limitation', reason: `flow run error: ${String(e)}` });
|
|
104
|
+
flowResults.push({ name: f.name, passed: false, reason: String(e) });
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
const failShot = r.steps.find((s) => s.screenshotUri)?.screenshotUri;
|
|
108
|
+
note({
|
|
109
|
+
workflow: f.name,
|
|
110
|
+
outcome: r.passed ? 'pass' : 'fail',
|
|
111
|
+
category: r.passed ? undefined : 'app_bug',
|
|
112
|
+
reason: r.passed ? `${r.steps.length} steps in ${r.durationSec}s` : `failed at step ${r.failedAtStep}: ${r.reason}`,
|
|
113
|
+
artifactUris: failShot ? [failShot] : undefined,
|
|
114
|
+
});
|
|
115
|
+
flowResults.push({ name: f.name, passed: r.passed, failedAtStep: r.failedAtStep, reason: r.reason });
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return { baseline, flows: flowResults, flowsPassed: flowResults.filter((f) => f.passed).length, flowsTotal: flowResults.length };
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=smoke.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"smoke.js","sourceRoot":"","sources":["../../src/services/smoke.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
// Suite generation service (Phase 3.2 Milestone C) — generate POM files + test cases from a
|
|
2
|
+
// session's recorded actions, write them under .swipium/, and (optionally) compile them to runnable
|
|
3
|
+
// Flow V2. Shared by qa_suite_generate and qa_test_this execute so the autopilot
|
|
4
|
+
// produces REAL files (not a note). Honest: when there are no recorded actions it returns a typed
|
|
5
|
+
// `skipped` result rather than pretending a suite was created.
|
|
6
|
+
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
7
|
+
import { join, dirname } from 'node:path';
|
|
8
|
+
import { generatePom } from '../suite/pom.js';
|
|
9
|
+
import { generateTestCases } from '../suite/testcase.js';
|
|
10
|
+
import { compileSuite } from '../suite/compile.js';
|
|
11
|
+
import { parseFlow } from '../flows/schema.js';
|
|
12
|
+
import { loadProjectConfig } from '../cli/scan.js';
|
|
13
|
+
import { readinessForSession } from '../report/readiness.js';
|
|
14
|
+
export function appIdOf(session) {
|
|
15
|
+
return session.appId ?? (loadProjectConfig(session.root)?.appId ?? undefined);
|
|
16
|
+
}
|
|
17
|
+
/** Write generated files under .swipium/, returning absolute paths written. */
|
|
18
|
+
export function writeSuiteFiles(session, files) {
|
|
19
|
+
const base = join(session.root, '.swipium');
|
|
20
|
+
const written = [];
|
|
21
|
+
for (const f of files) {
|
|
22
|
+
const abs = join(base, f.path);
|
|
23
|
+
mkdirSync(dirname(abs), { recursive: true });
|
|
24
|
+
writeFileSync(abs, f.content);
|
|
25
|
+
written.push(abs);
|
|
26
|
+
}
|
|
27
|
+
return written;
|
|
28
|
+
}
|
|
29
|
+
/** Build the POM (+ flowName) for a session's recorded actions. */
|
|
30
|
+
export function pomForSession(session, name, actions = session.recordedActions) {
|
|
31
|
+
const appId = appIdOf(session);
|
|
32
|
+
const flowName = (name ?? `${(appId ?? 'app').split('.').pop()}-smoke`).replace(/[^\w.-]+/g, '-');
|
|
33
|
+
const pom = generatePom(actions, { name: flowName, appId, budgetProfile: session.budgetProfile });
|
|
34
|
+
return { pom, flowName };
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Generate (and optionally compile) a full suite from the session's recorded actions.
|
|
38
|
+
* Returns `skipped:true` honestly when there is nothing to record.
|
|
39
|
+
*/
|
|
40
|
+
export function generateAndCompileSuite(sessions, session, opts = {}) {
|
|
41
|
+
const actions = opts.actions ?? session.recordedActions;
|
|
42
|
+
if (!actions.length) {
|
|
43
|
+
return {
|
|
44
|
+
skipped: true,
|
|
45
|
+
skippedReason: 'no recorded actions',
|
|
46
|
+
recommendation: 'Drive the app with qa_act, qa_smoke, or qa_explore so a suite can be recorded.',
|
|
47
|
+
written: [],
|
|
48
|
+
compiledFlows: [],
|
|
49
|
+
suiteRunnable: false,
|
|
50
|
+
readinessLabels: [],
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
const save = opts.save ?? true;
|
|
54
|
+
const compile = opts.compile ?? true;
|
|
55
|
+
const { pom, flowName } = pomForSession(session, opts.name, actions);
|
|
56
|
+
const tc = generateTestCases(pom, { appId: appIdOf(session), fixtures: session.fixtures, notes: session.notes, budgetProfile: session.budgetProfile });
|
|
57
|
+
const files = [
|
|
58
|
+
...pom.files,
|
|
59
|
+
{ path: `testcases/${flowName}.cases.yaml`, content: tc.yaml },
|
|
60
|
+
{ path: `testcases/${flowName}.cases.md`, content: tc.markdown },
|
|
61
|
+
];
|
|
62
|
+
const written = save ? writeSuiteFiles(session, files) : [];
|
|
63
|
+
// Compile to runnable Flow V2 (needs the page objects on disk).
|
|
64
|
+
const compiledFlows = [];
|
|
65
|
+
if (save && compile) {
|
|
66
|
+
const result = compileSuite(session.root, 'suites/smoke.yaml');
|
|
67
|
+
const flowsDir = join(session.root, '.swipium', 'flows');
|
|
68
|
+
const compiledDir = join(session.root, '.swipium', 'compiled');
|
|
69
|
+
mkdirSync(flowsDir, { recursive: true });
|
|
70
|
+
mkdirSync(compiledDir, { recursive: true });
|
|
71
|
+
for (const f of result.flows) {
|
|
72
|
+
const slug = f.name.replace(/[^\w.-]+/g, '-');
|
|
73
|
+
const parse = f.yaml ? parseFlow(f.yaml) : { errors: ['empty'] };
|
|
74
|
+
const ok = !!f.yaml && parse.errors.length === 0 && f.errors.length === 0;
|
|
75
|
+
let flowPath;
|
|
76
|
+
let compiledPath;
|
|
77
|
+
if (ok) {
|
|
78
|
+
flowPath = join(flowsDir, `${slug}.yaml`);
|
|
79
|
+
compiledPath = join(compiledDir, `${slug}.flow.yaml`);
|
|
80
|
+
writeFileSync(flowPath, f.yaml);
|
|
81
|
+
writeFileSync(compiledPath, f.yaml);
|
|
82
|
+
written.push(flowPath, compiledPath);
|
|
83
|
+
}
|
|
84
|
+
compiledFlows.push({ name: f.name, slug, ok, flowPath, compiledPath, errors: [...f.errors, ...parse.errors] });
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const suiteRunnable = compiledFlows.length > 0 && compiledFlows.every((c) => c.ok);
|
|
88
|
+
const readinessLabels = readinessForSession(session, { suiteRunnable });
|
|
89
|
+
if (!readinessLabels.includes('generated'))
|
|
90
|
+
readinessLabels.push('generated');
|
|
91
|
+
if (suiteRunnable && !readinessLabels.includes('compiled'))
|
|
92
|
+
readinessLabels.push('compiled');
|
|
93
|
+
let manifestPath;
|
|
94
|
+
if (save) {
|
|
95
|
+
manifestPath = join(session.root, '.swipium', 'suites', 'smoke.manifest.json');
|
|
96
|
+
writeFileSync(manifestPath, JSON.stringify({
|
|
97
|
+
schema: 'swipium.suite.manifest.v1',
|
|
98
|
+
generatedAt: new Date(session.createdAt).toISOString(),
|
|
99
|
+
name: flowName,
|
|
100
|
+
suiteFile: 'suites/smoke.yaml',
|
|
101
|
+
readinessLabels,
|
|
102
|
+
suiteRunnable,
|
|
103
|
+
compiledFlows: compiledFlows.map((f) => ({ name: f.name, slug: f.slug, ok: f.ok, errors: f.errors, flowPath: f.flowPath ?? null, compiledPath: f.compiledPath ?? null })),
|
|
104
|
+
audit: pom.audit,
|
|
105
|
+
variables: pom.variables,
|
|
106
|
+
}, null, 2));
|
|
107
|
+
written.push(manifestPath);
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
skipped: false,
|
|
111
|
+
name: flowName,
|
|
112
|
+
pages: pom.pages.map((p) => p.name),
|
|
113
|
+
written,
|
|
114
|
+
compiledFlows,
|
|
115
|
+
suiteRunnable,
|
|
116
|
+
readinessLabels,
|
|
117
|
+
manifestPath,
|
|
118
|
+
audit: pom.audit,
|
|
119
|
+
variables: pom.variables,
|
|
120
|
+
testCases: tc.cases,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=suiteGenerate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"suiteGenerate.js","sourceRoot":"","sources":["../../src/services/suiteGenerate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// Vision Gap Fix 9 — the single "suite knowledge merge" service. The vision requires the persistent
|
|
2
|
+
// suite (.swipium/test-suite.json) to stay current after EVERY flow that observes or creates QA
|
|
3
|
+
// knowledge — exploration, automation generation, and report — without depending on
|
|
4
|
+
// a later qa_report or a manual suite generation. Each flow funnels its cases through here so stable
|
|
5
|
+
// ids, dedup, provenance, and the run ledger are enforced in ONE place (store.applyMerge), and a merge
|
|
6
|
+
// failure is returned as a WARNING (best-effort) rather than failing an otherwise-valid QA run.
|
|
7
|
+
import { applyMerge, suiteDelta, suiteResourceUri, suiteJsonPath, loadSuite } from '../testSuite/store.js';
|
|
8
|
+
import { loadAppMap, saveAppMap } from '../appMap/store.js';
|
|
9
|
+
import { detectFramework } from '../context/detect.js';
|
|
10
|
+
import { casesFromExploration, caseFromPom } from '../testSuite/generator.js';
|
|
11
|
+
import { pomForSession } from './suiteGenerate.js';
|
|
12
|
+
import { join } from 'node:path';
|
|
13
|
+
import { log } from '../lib/logger.js';
|
|
14
|
+
const EMPTY = { ok: true, created: [], updated: [], deprecated: [], written: [], caseIds: [] };
|
|
15
|
+
function fallbackProject(root) {
|
|
16
|
+
const fw = detectFramework(root);
|
|
17
|
+
return { root, gitRemote: null, packageName: null, workspaceTarget: null, framework: fw, platforms: fw === 'native-android' ? ['android'] : fw === 'native-ios' ? ['ios'] : ['android', 'ios'] };
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Mirror a COMPACT index of the persistent suite into the app map's testSuite section so the durable
|
|
21
|
+
* map (and qa_app_map_query / feature scoping) reflect the growing suite — the "map + suite as one
|
|
22
|
+
* growing QA business context" loop the vision requires. Best-effort: no map yet ⇒ no-op.
|
|
23
|
+
*/
|
|
24
|
+
function mirrorSuiteIndexToMap(root, now) {
|
|
25
|
+
try {
|
|
26
|
+
const loaded = loadAppMap(root, fallbackProject(root), now);
|
|
27
|
+
if (!loaded.map)
|
|
28
|
+
return; // no durable map yet — feature scope still reads the suite directly
|
|
29
|
+
const suite = loadSuite(root);
|
|
30
|
+
const refs = suite.cases.map((c) => ({
|
|
31
|
+
id: c.id,
|
|
32
|
+
title: c.title,
|
|
33
|
+
featureId: c.featureId,
|
|
34
|
+
status: c.actualResult.status,
|
|
35
|
+
source: 'test-suite',
|
|
36
|
+
lastRun: c.actualResult.lastRunAt,
|
|
37
|
+
stale: c.status === 'deprecated',
|
|
38
|
+
}));
|
|
39
|
+
loaded.map.testSuite = { cases: refs };
|
|
40
|
+
loaded.map.coverage.staleTests = refs.filter((r) => r.stale).length;
|
|
41
|
+
loaded.map.updatedAt = now;
|
|
42
|
+
saveAppMap(root, loaded.map);
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
/* best-effort: a mirror failure never fails the suite merge */
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/** Core: merge already-canonical cases into the suite. Best-effort — never throws. */
|
|
49
|
+
export function mergeCanonical(root, cases, ctx) {
|
|
50
|
+
if (!cases.length)
|
|
51
|
+
return EMPTY;
|
|
52
|
+
try {
|
|
53
|
+
const applied = applyMerge(root, cases, { source: ctx.source, mode: ctx.mode ?? 'update', now: ctx.now, runId: ctx.runId, sourceUri: ctx.sourceUri, liveFeatureIds: ctx.liveFeatureIds }, ctx.appId);
|
|
54
|
+
const delta = suiteDelta(applied.result.suite, applied.result);
|
|
55
|
+
const caseIds = [...applied.result.created, ...applied.result.updated];
|
|
56
|
+
// Keep the durable app map's suite index in sync with the persistent suite (Fix #3).
|
|
57
|
+
mirrorSuiteIndexToMap(root, ctx.now);
|
|
58
|
+
return {
|
|
59
|
+
ok: true,
|
|
60
|
+
created: applied.result.created,
|
|
61
|
+
updated: applied.result.updated,
|
|
62
|
+
deprecated: applied.result.deprecated,
|
|
63
|
+
delta,
|
|
64
|
+
suiteUri: ctx.sessionId ? suiteResourceUri(ctx.sessionId) : `file://${suiteJsonPath(root)}`,
|
|
65
|
+
written: applied.written,
|
|
66
|
+
caseIds,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
catch (e) {
|
|
70
|
+
log('warn', 'suite knowledge merge failed', { source: ctx.source, err: String(e) });
|
|
71
|
+
return { ...EMPTY, ok: false, warning: `suite merge failed: ${String(e)}` };
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/** Merge exploration-derived feature coverage cases into the persistent suite. */
|
|
75
|
+
export function mergeFromExploration(root, exploration, ctx) {
|
|
76
|
+
if (!exploration?.summary?.featureCoverage)
|
|
77
|
+
return EMPTY;
|
|
78
|
+
let cases;
|
|
79
|
+
try {
|
|
80
|
+
cases = casesFromExploration({ exploration, source: 'exploration', now: ctx.now, appId: ctx.appId });
|
|
81
|
+
}
|
|
82
|
+
catch (e) {
|
|
83
|
+
return { ...EMPTY, ok: false, warning: `exploration→canonical conversion failed: ${String(e)}` };
|
|
84
|
+
}
|
|
85
|
+
return mergeCanonical(root, cases, { ...ctx, source: 'exploration' });
|
|
86
|
+
}
|
|
87
|
+
function readinessGrade(brittlePct) {
|
|
88
|
+
if (brittlePct <= 0)
|
|
89
|
+
return 'A';
|
|
90
|
+
if (brittlePct < 25)
|
|
91
|
+
return 'B';
|
|
92
|
+
if (brittlePct < 50)
|
|
93
|
+
return 'C';
|
|
94
|
+
return 'D';
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Fix 7 — merge automation metadata into the persistent suite. Converts the generated POM smoke flow
|
|
98
|
+
* into a canonical case carrying the real page-object/test-file paths, framework, locator readiness and
|
|
99
|
+
* automation status, AND (Fix #4) upgrades the automation link of EXISTING suite cases whose app-map
|
|
100
|
+
* feature/screen links overlap the generated suite — so a prior feature case is marked automated
|
|
101
|
+
* instead of a parallel POM-only case silently superseding it.
|
|
102
|
+
*/
|
|
103
|
+
export function mergeFromAutomation(root, session, input, ctx) {
|
|
104
|
+
const { assembled, links } = input;
|
|
105
|
+
let cases;
|
|
106
|
+
try {
|
|
107
|
+
const framework = assembled.profile.automationLanguage === 'python' ? 'appium_python' : 'appium_js';
|
|
108
|
+
const pageObjects = assembled.files.filter((f) => /page|screen|pages\//i.test(f.path)).map((f) => join(assembled.outputDir, f.path));
|
|
109
|
+
const testFiles = assembled.files.filter((f) => /test|spec|smoke|\.e2e\./i.test(f.path)).map((f) => join(assembled.outputDir, f.path));
|
|
110
|
+
const status = !input.validationOk ? 'partial' : assembled.model.audit.brittle > 0 ? 'partial' : 'automated';
|
|
111
|
+
const automation = { status, framework, pageObjects, testFiles, locatorReadiness: readinessGrade(assembled.model.audit.brittlePct), replayStatus: 'not_replayed' };
|
|
112
|
+
const { pom } = pomForSession(session);
|
|
113
|
+
const platforms = [assembled.profile.platforms.android.level !== 'none' ? 'android' : null, assembled.profile.platforms.ios.level !== 'none' ? 'ios' : null].filter(Boolean);
|
|
114
|
+
const base = caseFromPom({ pom, appId: session.appId, source: 'generate', now: ctx.now, platforms: platforms.length ? platforms : ['android'] });
|
|
115
|
+
if (!base)
|
|
116
|
+
return EMPTY;
|
|
117
|
+
// Group the POM case under the linked map feature so it doesn't fork from existing feature cases.
|
|
118
|
+
if (links?.featureIds.length) {
|
|
119
|
+
base.featureId = links.featureIds[0];
|
|
120
|
+
base.mapLinks = [
|
|
121
|
+
...links.featureIds.map((id) => ({ kind: 'feature', id })),
|
|
122
|
+
...links.screenIds.map((id) => ({ kind: 'screen', id })),
|
|
123
|
+
...base.mapLinks.filter((l) => l.kind !== 'feature'),
|
|
124
|
+
];
|
|
125
|
+
}
|
|
126
|
+
base.automation = automation;
|
|
127
|
+
cases = [base];
|
|
128
|
+
// Enrich EXISTING cases linked to the same feature/screen ids (Fix #4): re-emit them with their
|
|
129
|
+
// own id + upgraded automation so applyMerge updates (never duplicates) them. mergeAutomation only
|
|
130
|
+
// ever raises status/readiness, so this can't regress a stronger existing link.
|
|
131
|
+
if (links && (links.featureIds.length || links.screenIds.length)) {
|
|
132
|
+
const feat = new Set(links.featureIds);
|
|
133
|
+
const scr = new Set(links.screenIds);
|
|
134
|
+
const suite = loadSuite(root, ctx.appId);
|
|
135
|
+
for (const c of suite.cases) {
|
|
136
|
+
if (c.status === 'deprecated' || c.id === base.id)
|
|
137
|
+
continue;
|
|
138
|
+
const overlaps = feat.has(c.featureId) || c.mapLinks.some((l) => (l.kind === 'feature' && feat.has(l.id)) || ((l.kind === 'screen' || l.kind === 'static_screen' || l.kind === 'runtime_screen') && scr.has(l.id)));
|
|
139
|
+
if (!overlaps)
|
|
140
|
+
continue;
|
|
141
|
+
cases.push({ ...c, automation, provenance: [] });
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
catch (e) {
|
|
146
|
+
return { ...EMPTY, ok: false, warning: `automation→canonical conversion failed: ${String(e)}` };
|
|
147
|
+
}
|
|
148
|
+
return mergeCanonical(root, cases, { ...ctx, source: 'generate' });
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=testSuiteKnowledge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testSuiteKnowledge.js","sourceRoot":"","sources":["../../src/services/testSuiteKnowledge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Centralized device resolution + lazy driver attach (Phase 2.1). One place decides
|
|
2
|
+
// "which device" so qa_doctor / qa_prepare_target / UI tools
|
|
3
|
+
// all agree: a session-bound device, the single online device, or "needs selection".
|
|
4
|
+
import { adbDevices } from '../lib/android.js';
|
|
5
|
+
import { DirectDriver } from '../drivers/DirectDriver.js';
|
|
6
|
+
export async function resolveDevice(session, prefer) {
|
|
7
|
+
// Test-isolation hook (SWIPIUM-REQ-08 regression requirement): when set, device auto-discovery is
|
|
8
|
+
// disabled so "no device" tests assert no-device behavior even on a machine with a live emulator.
|
|
9
|
+
if (process.env.SWIPIUM_DISABLE_DEVICE_DISCOVERY) {
|
|
10
|
+
return { sessionDevice: undefined, available: [], effective: undefined, needSelection: false, source: 'none' };
|
|
11
|
+
}
|
|
12
|
+
const available = await adbDevices();
|
|
13
|
+
const sessionDevice = session.device && available.includes(session.device) ? session.device : undefined;
|
|
14
|
+
if (prefer) {
|
|
15
|
+
return available.includes(prefer)
|
|
16
|
+
? { sessionDevice, available, effective: prefer, needSelection: false, source: 'arg' }
|
|
17
|
+
: { sessionDevice, available, effective: undefined, needSelection: false, source: 'none' };
|
|
18
|
+
}
|
|
19
|
+
if (sessionDevice)
|
|
20
|
+
return { sessionDevice, available, effective: sessionDevice, needSelection: false, source: 'session' };
|
|
21
|
+
if (available.length === 1)
|
|
22
|
+
return { sessionDevice, available, effective: available[0], needSelection: false, source: 'single-online' };
|
|
23
|
+
if (available.length > 1)
|
|
24
|
+
return { sessionDevice, available, effective: undefined, needSelection: true, source: 'none' };
|
|
25
|
+
return { sessionDevice, available, effective: undefined, needSelection: false, source: 'none' };
|
|
26
|
+
}
|
|
27
|
+
/** Bind a serial to the session (used after prepare/boot or single-online auto-bind). */
|
|
28
|
+
export function bindDevice(session, serial) {
|
|
29
|
+
const driver = new DirectDriver(serial);
|
|
30
|
+
session.device = serial;
|
|
31
|
+
session.driver = driver;
|
|
32
|
+
return driver;
|
|
33
|
+
}
|
|
34
|
+
export async function getDriver(session) {
|
|
35
|
+
if (session.driver)
|
|
36
|
+
return { driver: session.driver, rehydrated: false };
|
|
37
|
+
const res = await resolveDevice(session);
|
|
38
|
+
if (res.effective) {
|
|
39
|
+
bindDevice(session, res.effective);
|
|
40
|
+
session.lastSnapshot = undefined; // refs invalid after (re)bind
|
|
41
|
+
return { driver: session.driver, rehydrated: true };
|
|
42
|
+
}
|
|
43
|
+
return { driver: undefined, rehydrated: false, needSelection: res.needSelection };
|
|
44
|
+
}
|
|
45
|
+
export const REHYDRATE_NOTE = 'Note: reattached the device transport after a restart — the app may not be in the ' +
|
|
46
|
+
'foreground (relaunch with qa_prepare_target) and previous @eN refs are invalid (re-run qa_snapshot).';
|
|
47
|
+
//# sourceMappingURL=attach.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attach.js","sourceRoot":"","sources":["../../src/session/attach.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// Progress model helper (hardening P1.1). Long-running jobs report a consistent progress shape
|
|
2
|
+
// (phase / elapsed / statusText / lastEvent / nextExpected / logUri / userActionRequired) so an
|
|
3
|
+
// agent can relay status compactly. `startProgress` returns a small controller a worker uses to
|
|
4
|
+
// emit events; it writes both the legacy `progress` string and the structured `progressDetail`.
|
|
5
|
+
export function startProgress(sessions, session, job, phase, init = { statusText: phase }) {
|
|
6
|
+
const now = Date.now();
|
|
7
|
+
const model = {
|
|
8
|
+
phase,
|
|
9
|
+
startedAt: now,
|
|
10
|
+
updatedAt: now,
|
|
11
|
+
statusText: init.statusText,
|
|
12
|
+
nextExpected: init.nextExpected,
|
|
13
|
+
logUri: init.logUri,
|
|
14
|
+
userActionRequired: false,
|
|
15
|
+
};
|
|
16
|
+
const write = () => {
|
|
17
|
+
model.updatedAt = Date.now();
|
|
18
|
+
sessions.updateJobIfRunning(session, job, { progress: model.statusText, progressDetail: { ...model } });
|
|
19
|
+
};
|
|
20
|
+
write();
|
|
21
|
+
return {
|
|
22
|
+
elapsedSec: () => Math.round((Date.now() - model.startedAt) / 1000),
|
|
23
|
+
event(lastEvent, opts) {
|
|
24
|
+
model.lastEvent = lastEvent;
|
|
25
|
+
if (opts?.statusText)
|
|
26
|
+
model.statusText = opts.statusText;
|
|
27
|
+
if (opts?.nextExpected)
|
|
28
|
+
model.nextExpected = opts.nextExpected;
|
|
29
|
+
write();
|
|
30
|
+
},
|
|
31
|
+
setLog(logUri) {
|
|
32
|
+
model.logUri = logUri;
|
|
33
|
+
write();
|
|
34
|
+
},
|
|
35
|
+
needsUser(statusText) {
|
|
36
|
+
model.userActionRequired = true;
|
|
37
|
+
model.statusText = statusText;
|
|
38
|
+
write();
|
|
39
|
+
},
|
|
40
|
+
done(statusText) {
|
|
41
|
+
model.userActionRequired = false;
|
|
42
|
+
if (statusText)
|
|
43
|
+
model.statusText = statusText;
|
|
44
|
+
model.nextExpected = undefined;
|
|
45
|
+
write();
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/** Compact one-line progress summary for qa_status / qa_job_status. */
|
|
50
|
+
export function progressLine(p) {
|
|
51
|
+
if (!p)
|
|
52
|
+
return undefined;
|
|
53
|
+
const sec = Math.round((p.updatedAt - p.startedAt) / 1000);
|
|
54
|
+
return `${p.phase} (${sec}s)${p.userActionRequired ? ' ⚠ needs you' : ''}: ${p.statusText}` + (p.nextExpected ? ` → ${p.nextExpected}` : '');
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=progress.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progress.js","sourceRoot":"","sources":["../../src/session/progress.ts"],"names":[],"mappings":"AAAA,+FAA+F;AAC/F,gGAAgG;AAChG,gGAAgG;AAChG,gGAAgG;AAahG,MAAM,UAAU,aAAa,CAC3B,QAAsB,EACtB,OAAgB,EAChB,GAAc,EACd,KAAa,EACb,OAAuE,EAAE,UAAU,EAAE,KAAK,EAAE;IAE5F,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,KAAK,GAAkB;QAC3B,KAAK;QACL,SAAS,EAAE,GAAG;QACd,SAAS,EAAE,GAAG;QACd,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,YAAY,EAAE,IAAI,CAAC,YAAY;QAC/B,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,kBAAkB,EAAE,KAAK;KAC1B,CAAC;IACF,MAAM,KAAK,GAAG,GAAG,EAAE;QACjB,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,QAAQ,CAAC,kBAAkB,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE,QAAQ,EAAE,KAAK,CAAC,UAAU,EAAE,cAAc,EAAE,EAAE,GAAG,KAAK,EAAE,EAAE,CAAC,CAAC;IAC1G,CAAC,CAAC;IACF,KAAK,EAAE,CAAC;IACR,OAAO;QACL,UAAU,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC;QACnE,KAAK,CAAC,SAAS,EAAE,IAAI;YACnB,KAAK,CAAC,SAAS,GAAG,SAAS,CAAC;YAC5B,IAAI,IAAI,EAAE,UAAU;gBAAE,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;YACzD,IAAI,IAAI,EAAE,YAAY;gBAAE,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC;YAC/D,KAAK,EAAE,CAAC;QACV,CAAC;QACD,MAAM,CAAC,MAAM;YACX,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC;YACtB,KAAK,EAAE,CAAC;QACV,CAAC;QACD,SAAS,CAAC,UAAU;YAClB,KAAK,CAAC,kBAAkB,GAAG,IAAI,CAAC;YAChC,KAAK,CAAC,UAAU,GAAG,UAAU,CAAC;YAC9B,KAAK,EAAE,CAAC;QACV,CAAC;QACD,IAAI,CAAC,UAAU;YACb,KAAK,CAAC,kBAAkB,GAAG,KAAK,CAAC;YACjC,IAAI,UAAU;gBAAE,KAAK,CAAC,UAAU,GAAG,UAAU,CAAC;YAC9C,KAAK,CAAC,YAAY,GAAG,SAAS,CAAC;YAC/B,KAAK,EAAE,CAAC;QACV,CAAC;KACF,CAAC;AACJ,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,YAAY,CAAC,CAA4B;IACvD,IAAI,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IACzB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,CAAC;IAC3D,OAAO,GAAG,CAAC,CAAC,KAAK,KAAK,GAAG,KAAK,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAC/I,CAAC"}
|