@validate.qa/runner 1.0.3 → 1.0.4
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/dist/cli.js +44 -5
- package/dist/cli.mjs +44 -5
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -7552,7 +7552,7 @@ Each entry is exactly one of:
|
|
|
7552
7552
|
const systemPrompt = context.mode === "survey" ? SURVEY_SYSTEM_PROMPT : exports2.SCENARIO_SYSTEM_PROMPT;
|
|
7553
7553
|
const userPrompt = formatEvidenceForPlanner(compressed, evidence, context);
|
|
7554
7554
|
logs2.push(`AI planner: ~${Math.ceil(userPrompt.length / 3.5)} input tokens`);
|
|
7555
|
-
const aiClient = options.modelOverride ? (0, ai_provider_js_1.getClientForModel)(options.modelOverride) : (0, ai_provider_js_1.getAIClient)();
|
|
7555
|
+
const aiClient = options.aiClient ?? (options.modelOverride ? (0, ai_provider_js_1.getClientForModel)(options.modelOverride) : (0, ai_provider_js_1.getAIClient)());
|
|
7556
7556
|
const messages = [
|
|
7557
7557
|
{ role: "system", content: systemPrompt },
|
|
7558
7558
|
{ role: "user", content: userPrompt }
|
|
@@ -7764,6 +7764,7 @@ var require_mobile_discovery_prompts = __commonJS({
|
|
|
7764
7764
|
exports2.formatMobileEvidenceForPlanner = formatMobileEvidenceForPlanner;
|
|
7765
7765
|
exports2.buildMobileSiteMap = buildMobileSiteMap;
|
|
7766
7766
|
exports2.runMobileAIPlanner = runMobileAIPlanner;
|
|
7767
|
+
var ai_provider_js_1 = require_ai_provider();
|
|
7767
7768
|
var discover_ai_planner_js_1 = require_discover_ai_planner();
|
|
7768
7769
|
exports2.MOBILE_SURVEY_SYSTEM_PROMPT = `You are a feature analyst for a native mobile application (iOS or Android). You receive evidence from an AI explorer that mapped the app's screens by tapping, typing, and swiping through the live UI. Your job is to organize screens into meaningful feature groups.
|
|
7769
7770
|
|
|
@@ -8163,6 +8164,8 @@ ${constraints.join("\n")}`);
|
|
|
8163
8164
|
}
|
|
8164
8165
|
async function runMobileAIPlanner(input, options = {}) {
|
|
8165
8166
|
const planner = options.planner ?? discover_ai_planner_js_1.runAIPlanner;
|
|
8167
|
+
const shouldBuildMobileAIClient = (process.env.SERVER_URL ?? "").trim().length > 0 || !options.planner;
|
|
8168
|
+
const aiClient = options.aiClient ?? (shouldBuildMobileAIClient ? options.modelOverride ? (0, ai_provider_js_1.getMobileClientForModel)(options.modelOverride) : (0, ai_provider_js_1.getMobileAIClient)() : void 0);
|
|
8166
8169
|
const siteMap = buildMobileSiteMap(input.graph, {
|
|
8167
8170
|
projectId: input.projectId,
|
|
8168
8171
|
appId: input.appId
|
|
@@ -8188,7 +8191,8 @@ ${constraints.join("\n")}`);
|
|
|
8188
8191
|
testBudget: input.testBudget
|
|
8189
8192
|
}, {
|
|
8190
8193
|
modelOverride: options.modelOverride,
|
|
8191
|
-
onAICall: options.onAICall
|
|
8194
|
+
onAICall: options.onAICall,
|
|
8195
|
+
...aiClient ? { aiClient } : {}
|
|
8192
8196
|
});
|
|
8193
8197
|
}
|
|
8194
8198
|
}
|
|
@@ -324796,7 +324800,7 @@ var require_package4 = __commonJS({
|
|
|
324796
324800
|
"package.json"(exports2, module2) {
|
|
324797
324801
|
module2.exports = {
|
|
324798
324802
|
name: "@validate.qa/runner",
|
|
324799
|
-
version: "1.0.
|
|
324803
|
+
version: "1.0.4",
|
|
324800
324804
|
description: "validate local test runner - execute Playwright tests on your machine, connected to validate.qa cloud.",
|
|
324801
324805
|
bin: {
|
|
324802
324806
|
"validate-runner": "dist/cli.js"
|
|
@@ -326314,6 +326318,7 @@ var polling = false;
|
|
|
326314
326318
|
var sessionStartInFlight = null;
|
|
326315
326319
|
var sessionReaperTimer = null;
|
|
326316
326320
|
var mirrorClientsEmptyAt = null;
|
|
326321
|
+
var mirrorSessionOwner = null;
|
|
326317
326322
|
var executorBusy = false;
|
|
326318
326323
|
var rateLimitBuckets = /* @__PURE__ */ new Map();
|
|
326319
326324
|
function isRateLimited(clientIp) {
|
|
@@ -326650,6 +326655,7 @@ async function startSession(validated, res) {
|
|
|
326650
326655
|
}
|
|
326651
326656
|
state.appiumSessionId = null;
|
|
326652
326657
|
state.platform = null;
|
|
326658
|
+
mirrorSessionOwner = null;
|
|
326653
326659
|
}
|
|
326654
326660
|
stopAllMirrorClients();
|
|
326655
326661
|
const realCaps = isPhysicalDevice(deviceId, targetPlatform) ? realDeviceCapabilities2(targetPlatform) : {};
|
|
@@ -326680,11 +326686,14 @@ async function startSession(validated, res) {
|
|
|
326680
326686
|
})
|
|
326681
326687
|
});
|
|
326682
326688
|
state.appiumSessionId = result?.value?.sessionId ?? result?.sessionId ?? null;
|
|
326683
|
-
state.platform = targetPlatform === "IOS" ? "IOS" : "ANDROID";
|
|
326684
326689
|
if (!state.appiumSessionId) {
|
|
326690
|
+
state.platform = null;
|
|
326691
|
+
mirrorSessionOwner = null;
|
|
326685
326692
|
sendJSON(res, 500, { error: "Appium session creation returned no session ID" });
|
|
326686
326693
|
return;
|
|
326687
326694
|
}
|
|
326695
|
+
state.platform = targetPlatform === "IOS" ? "IOS" : "ANDROID";
|
|
326696
|
+
mirrorSessionOwner = "recording";
|
|
326688
326697
|
if (launchMode === "DEEP_LINK" && deeplink) {
|
|
326689
326698
|
try {
|
|
326690
326699
|
const args = targetPlatform === "IOS" ? [{ url: deeplink, bundleId: appId }] : [{ url: deeplink, package: appId }];
|
|
@@ -326709,6 +326718,7 @@ async function handleSessionStop(_req, res) {
|
|
|
326709
326718
|
}
|
|
326710
326719
|
state.appiumSessionId = null;
|
|
326711
326720
|
state.platform = null;
|
|
326721
|
+
mirrorSessionOwner = null;
|
|
326712
326722
|
}
|
|
326713
326723
|
stopAllMirrorClients();
|
|
326714
326724
|
stopSessionReaper();
|
|
@@ -326789,6 +326799,7 @@ async function pollAndBroadcastFrame() {
|
|
|
326789
326799
|
if (!alive) {
|
|
326790
326800
|
state.appiumSessionId = null;
|
|
326791
326801
|
state.platform = null;
|
|
326802
|
+
mirrorSessionOwner = null;
|
|
326792
326803
|
stopAllMirrorClients();
|
|
326793
326804
|
return;
|
|
326794
326805
|
}
|
|
@@ -326859,6 +326870,7 @@ async function reapIdleSession() {
|
|
|
326859
326870
|
const sessionId = state.appiumSessionId;
|
|
326860
326871
|
state.appiumSessionId = null;
|
|
326861
326872
|
state.platform = null;
|
|
326873
|
+
mirrorSessionOwner = null;
|
|
326862
326874
|
mirrorClientsEmptyAt = null;
|
|
326863
326875
|
stopSessionReaper();
|
|
326864
326876
|
try {
|
|
@@ -327169,6 +327181,7 @@ async function stopMobileBridge() {
|
|
|
327169
327181
|
}
|
|
327170
327182
|
state.appiumSessionId = null;
|
|
327171
327183
|
state.platform = null;
|
|
327184
|
+
mirrorSessionOwner = null;
|
|
327172
327185
|
}
|
|
327173
327186
|
if (ngrokProcess) {
|
|
327174
327187
|
try {
|
|
@@ -327199,13 +327212,37 @@ function getBridgeState() {
|
|
|
327199
327212
|
tunnelUrl: state.tunnelUrl,
|
|
327200
327213
|
tunnelToken: state.tunnelToken,
|
|
327201
327214
|
hasActiveSession: !!state.appiumSessionId,
|
|
327202
|
-
recordingActive: !!state.appiumSessionId,
|
|
327215
|
+
recordingActive: !!state.appiumSessionId && mirrorSessionOwner === "recording",
|
|
327203
327216
|
platform: state.platform
|
|
327204
327217
|
};
|
|
327205
327218
|
}
|
|
327206
327219
|
function setExecutorBusy(busy) {
|
|
327207
327220
|
executorBusy = busy;
|
|
327208
327221
|
}
|
|
327222
|
+
function attachMirrorSession(sessionId, platform3) {
|
|
327223
|
+
validateSessionId(sessionId);
|
|
327224
|
+
if (state.appiumSessionId && state.appiumSessionId !== sessionId) {
|
|
327225
|
+
stopAllMirrorClients();
|
|
327226
|
+
}
|
|
327227
|
+
state.appiumSessionId = sessionId;
|
|
327228
|
+
state.platform = platform3;
|
|
327229
|
+
mirrorSessionOwner = "runner";
|
|
327230
|
+
mirrorNullTicks = 0;
|
|
327231
|
+
mirrorClientsEmptyAt = null;
|
|
327232
|
+
ensureSessionReaper();
|
|
327233
|
+
if (state.mirrorClients.size > 0) {
|
|
327234
|
+
ensureMirrorPolling();
|
|
327235
|
+
void pollAndBroadcastFrame();
|
|
327236
|
+
}
|
|
327237
|
+
}
|
|
327238
|
+
function detachMirrorSession(sessionId) {
|
|
327239
|
+
if (sessionId && state.appiumSessionId && state.appiumSessionId !== sessionId) return;
|
|
327240
|
+
state.appiumSessionId = null;
|
|
327241
|
+
state.platform = null;
|
|
327242
|
+
mirrorSessionOwner = null;
|
|
327243
|
+
stopAllMirrorClients();
|
|
327244
|
+
stopSessionReaper();
|
|
327245
|
+
}
|
|
327209
327246
|
|
|
327210
327247
|
// src/services/mobile/mobile-bridge-driver.ts
|
|
327211
327248
|
var import_runner_core7 = __toESM(require_dist2());
|
|
@@ -329864,6 +329901,7 @@ ${finalVerifyResult.logs ?? ""}`;
|
|
|
329864
329901
|
deeplink: mobileTarget.deeplink
|
|
329865
329902
|
});
|
|
329866
329903
|
mobileOnLog(`Appium session created: ${session.sessionId} on device ${session.deviceId}`);
|
|
329904
|
+
attachMirrorSession(session.sessionId, platform3);
|
|
329867
329905
|
const driver = new MobileBridgeDriver({
|
|
329868
329906
|
sessionId: session.sessionId,
|
|
329869
329907
|
platform: platform3,
|
|
@@ -329904,6 +329942,7 @@ ${finalVerifyResult.logs ?? ""}`;
|
|
|
329904
329942
|
}
|
|
329905
329943
|
}
|
|
329906
329944
|
if (session) {
|
|
329945
|
+
detachMirrorSession(session.sessionId);
|
|
329907
329946
|
try {
|
|
329908
329947
|
await session.stop();
|
|
329909
329948
|
} catch {
|
package/dist/cli.mjs
CHANGED
|
@@ -7557,7 +7557,7 @@ Each entry is exactly one of:
|
|
|
7557
7557
|
const systemPrompt = context.mode === "survey" ? SURVEY_SYSTEM_PROMPT : exports.SCENARIO_SYSTEM_PROMPT;
|
|
7558
7558
|
const userPrompt = formatEvidenceForPlanner(compressed, evidence, context);
|
|
7559
7559
|
logs2.push(`AI planner: ~${Math.ceil(userPrompt.length / 3.5)} input tokens`);
|
|
7560
|
-
const aiClient = options.modelOverride ? (0, ai_provider_js_1.getClientForModel)(options.modelOverride) : (0, ai_provider_js_1.getAIClient)();
|
|
7560
|
+
const aiClient = options.aiClient ?? (options.modelOverride ? (0, ai_provider_js_1.getClientForModel)(options.modelOverride) : (0, ai_provider_js_1.getAIClient)());
|
|
7561
7561
|
const messages = [
|
|
7562
7562
|
{ role: "system", content: systemPrompt },
|
|
7563
7563
|
{ role: "user", content: userPrompt }
|
|
@@ -7769,6 +7769,7 @@ var require_mobile_discovery_prompts = __commonJS({
|
|
|
7769
7769
|
exports.formatMobileEvidenceForPlanner = formatMobileEvidenceForPlanner;
|
|
7770
7770
|
exports.buildMobileSiteMap = buildMobileSiteMap;
|
|
7771
7771
|
exports.runMobileAIPlanner = runMobileAIPlanner;
|
|
7772
|
+
var ai_provider_js_1 = require_ai_provider();
|
|
7772
7773
|
var discover_ai_planner_js_1 = require_discover_ai_planner();
|
|
7773
7774
|
exports.MOBILE_SURVEY_SYSTEM_PROMPT = `You are a feature analyst for a native mobile application (iOS or Android). You receive evidence from an AI explorer that mapped the app's screens by tapping, typing, and swiping through the live UI. Your job is to organize screens into meaningful feature groups.
|
|
7774
7775
|
|
|
@@ -8168,6 +8169,8 @@ ${constraints.join("\n")}`);
|
|
|
8168
8169
|
}
|
|
8169
8170
|
async function runMobileAIPlanner(input, options = {}) {
|
|
8170
8171
|
const planner = options.planner ?? discover_ai_planner_js_1.runAIPlanner;
|
|
8172
|
+
const shouldBuildMobileAIClient = (process.env.SERVER_URL ?? "").trim().length > 0 || !options.planner;
|
|
8173
|
+
const aiClient = options.aiClient ?? (shouldBuildMobileAIClient ? options.modelOverride ? (0, ai_provider_js_1.getMobileClientForModel)(options.modelOverride) : (0, ai_provider_js_1.getMobileAIClient)() : void 0);
|
|
8171
8174
|
const siteMap = buildMobileSiteMap(input.graph, {
|
|
8172
8175
|
projectId: input.projectId,
|
|
8173
8176
|
appId: input.appId
|
|
@@ -8193,7 +8196,8 @@ ${constraints.join("\n")}`);
|
|
|
8193
8196
|
testBudget: input.testBudget
|
|
8194
8197
|
}, {
|
|
8195
8198
|
modelOverride: options.modelOverride,
|
|
8196
|
-
onAICall: options.onAICall
|
|
8199
|
+
onAICall: options.onAICall,
|
|
8200
|
+
...aiClient ? { aiClient } : {}
|
|
8197
8201
|
});
|
|
8198
8202
|
}
|
|
8199
8203
|
}
|
|
@@ -324801,7 +324805,7 @@ var require_package4 = __commonJS({
|
|
|
324801
324805
|
"package.json"(exports, module) {
|
|
324802
324806
|
module.exports = {
|
|
324803
324807
|
name: "@validate.qa/runner",
|
|
324804
|
-
version: "1.0.
|
|
324808
|
+
version: "1.0.4",
|
|
324805
324809
|
description: "validate local test runner - execute Playwright tests on your machine, connected to validate.qa cloud.",
|
|
324806
324810
|
bin: {
|
|
324807
324811
|
"validate-runner": "dist/cli.js"
|
|
@@ -326319,6 +326323,7 @@ var polling = false;
|
|
|
326319
326323
|
var sessionStartInFlight = null;
|
|
326320
326324
|
var sessionReaperTimer = null;
|
|
326321
326325
|
var mirrorClientsEmptyAt = null;
|
|
326326
|
+
var mirrorSessionOwner = null;
|
|
326322
326327
|
var executorBusy = false;
|
|
326323
326328
|
var rateLimitBuckets = /* @__PURE__ */ new Map();
|
|
326324
326329
|
function isRateLimited(clientIp) {
|
|
@@ -326655,6 +326660,7 @@ async function startSession(validated, res) {
|
|
|
326655
326660
|
}
|
|
326656
326661
|
state.appiumSessionId = null;
|
|
326657
326662
|
state.platform = null;
|
|
326663
|
+
mirrorSessionOwner = null;
|
|
326658
326664
|
}
|
|
326659
326665
|
stopAllMirrorClients();
|
|
326660
326666
|
const realCaps = isPhysicalDevice(deviceId, targetPlatform) ? realDeviceCapabilities2(targetPlatform) : {};
|
|
@@ -326685,11 +326691,14 @@ async function startSession(validated, res) {
|
|
|
326685
326691
|
})
|
|
326686
326692
|
});
|
|
326687
326693
|
state.appiumSessionId = result?.value?.sessionId ?? result?.sessionId ?? null;
|
|
326688
|
-
state.platform = targetPlatform === "IOS" ? "IOS" : "ANDROID";
|
|
326689
326694
|
if (!state.appiumSessionId) {
|
|
326695
|
+
state.platform = null;
|
|
326696
|
+
mirrorSessionOwner = null;
|
|
326690
326697
|
sendJSON(res, 500, { error: "Appium session creation returned no session ID" });
|
|
326691
326698
|
return;
|
|
326692
326699
|
}
|
|
326700
|
+
state.platform = targetPlatform === "IOS" ? "IOS" : "ANDROID";
|
|
326701
|
+
mirrorSessionOwner = "recording";
|
|
326693
326702
|
if (launchMode === "DEEP_LINK" && deeplink) {
|
|
326694
326703
|
try {
|
|
326695
326704
|
const args = targetPlatform === "IOS" ? [{ url: deeplink, bundleId: appId }] : [{ url: deeplink, package: appId }];
|
|
@@ -326714,6 +326723,7 @@ async function handleSessionStop(_req, res) {
|
|
|
326714
326723
|
}
|
|
326715
326724
|
state.appiumSessionId = null;
|
|
326716
326725
|
state.platform = null;
|
|
326726
|
+
mirrorSessionOwner = null;
|
|
326717
326727
|
}
|
|
326718
326728
|
stopAllMirrorClients();
|
|
326719
326729
|
stopSessionReaper();
|
|
@@ -326794,6 +326804,7 @@ async function pollAndBroadcastFrame() {
|
|
|
326794
326804
|
if (!alive) {
|
|
326795
326805
|
state.appiumSessionId = null;
|
|
326796
326806
|
state.platform = null;
|
|
326807
|
+
mirrorSessionOwner = null;
|
|
326797
326808
|
stopAllMirrorClients();
|
|
326798
326809
|
return;
|
|
326799
326810
|
}
|
|
@@ -326864,6 +326875,7 @@ async function reapIdleSession() {
|
|
|
326864
326875
|
const sessionId = state.appiumSessionId;
|
|
326865
326876
|
state.appiumSessionId = null;
|
|
326866
326877
|
state.platform = null;
|
|
326878
|
+
mirrorSessionOwner = null;
|
|
326867
326879
|
mirrorClientsEmptyAt = null;
|
|
326868
326880
|
stopSessionReaper();
|
|
326869
326881
|
try {
|
|
@@ -327174,6 +327186,7 @@ async function stopMobileBridge() {
|
|
|
327174
327186
|
}
|
|
327175
327187
|
state.appiumSessionId = null;
|
|
327176
327188
|
state.platform = null;
|
|
327189
|
+
mirrorSessionOwner = null;
|
|
327177
327190
|
}
|
|
327178
327191
|
if (ngrokProcess) {
|
|
327179
327192
|
try {
|
|
@@ -327204,13 +327217,37 @@ function getBridgeState() {
|
|
|
327204
327217
|
tunnelUrl: state.tunnelUrl,
|
|
327205
327218
|
tunnelToken: state.tunnelToken,
|
|
327206
327219
|
hasActiveSession: !!state.appiumSessionId,
|
|
327207
|
-
recordingActive: !!state.appiumSessionId,
|
|
327220
|
+
recordingActive: !!state.appiumSessionId && mirrorSessionOwner === "recording",
|
|
327208
327221
|
platform: state.platform
|
|
327209
327222
|
};
|
|
327210
327223
|
}
|
|
327211
327224
|
function setExecutorBusy(busy) {
|
|
327212
327225
|
executorBusy = busy;
|
|
327213
327226
|
}
|
|
327227
|
+
function attachMirrorSession(sessionId, platform3) {
|
|
327228
|
+
validateSessionId(sessionId);
|
|
327229
|
+
if (state.appiumSessionId && state.appiumSessionId !== sessionId) {
|
|
327230
|
+
stopAllMirrorClients();
|
|
327231
|
+
}
|
|
327232
|
+
state.appiumSessionId = sessionId;
|
|
327233
|
+
state.platform = platform3;
|
|
327234
|
+
mirrorSessionOwner = "runner";
|
|
327235
|
+
mirrorNullTicks = 0;
|
|
327236
|
+
mirrorClientsEmptyAt = null;
|
|
327237
|
+
ensureSessionReaper();
|
|
327238
|
+
if (state.mirrorClients.size > 0) {
|
|
327239
|
+
ensureMirrorPolling();
|
|
327240
|
+
void pollAndBroadcastFrame();
|
|
327241
|
+
}
|
|
327242
|
+
}
|
|
327243
|
+
function detachMirrorSession(sessionId) {
|
|
327244
|
+
if (sessionId && state.appiumSessionId && state.appiumSessionId !== sessionId) return;
|
|
327245
|
+
state.appiumSessionId = null;
|
|
327246
|
+
state.platform = null;
|
|
327247
|
+
mirrorSessionOwner = null;
|
|
327248
|
+
stopAllMirrorClients();
|
|
327249
|
+
stopSessionReaper();
|
|
327250
|
+
}
|
|
327214
327251
|
|
|
327215
327252
|
// src/services/mobile/mobile-bridge-driver.ts
|
|
327216
327253
|
var import_runner_core7 = __toESM(require_dist2());
|
|
@@ -329872,6 +329909,7 @@ ${finalVerifyResult.logs ?? ""}`;
|
|
|
329872
329909
|
deeplink: mobileTarget.deeplink
|
|
329873
329910
|
});
|
|
329874
329911
|
mobileOnLog(`Appium session created: ${session.sessionId} on device ${session.deviceId}`);
|
|
329912
|
+
attachMirrorSession(session.sessionId, platform3);
|
|
329875
329913
|
const driver = new MobileBridgeDriver({
|
|
329876
329914
|
sessionId: session.sessionId,
|
|
329877
329915
|
platform: platform3,
|
|
@@ -329912,6 +329950,7 @@ ${finalVerifyResult.logs ?? ""}`;
|
|
|
329912
329950
|
}
|
|
329913
329951
|
}
|
|
329914
329952
|
if (session) {
|
|
329953
|
+
detachMirrorSession(session.sessionId);
|
|
329915
329954
|
try {
|
|
329916
329955
|
await session.stop();
|
|
329917
329956
|
} catch {
|
package/package.json
CHANGED