@veolab/discoverylab 1.2.1 → 1.3.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/.mcp.json +2 -2
- package/README.md +182 -0
- package/dist/{chunk-TAODYZ52.js → chunk-3QRQEDWR.js} +510 -213
- package/dist/{chunk-L4SA5F5W.js → chunk-4L76GPRC.js} +1162 -58
- package/dist/chunk-6EGBXRDK.js +30 -0
- package/dist/{chunk-I6YD3QFM.js → chunk-FIL7IWEL.js} +5 -3
- package/dist/{chunk-4KLG6DDE.js → chunk-FNUN7EPB.js} +6 -6
- package/dist/chunk-GAKEFJ5T.js +481 -0
- package/dist/chunk-LB3RNE3O.js +109 -0
- package/dist/chunk-N6JJ2RGV.js +2680 -0
- package/dist/{chunk-XUKWS2CE.js → chunk-VRM42PML.js} +3546 -926
- package/dist/{chunk-TJ3H23LL.js → chunk-VVIOB362.js} +3 -1
- package/dist/{chunk-W3WJGYR6.js → chunk-XFVDP332.js} +8 -2
- package/dist/{chunk-QJXXHOV7.js → chunk-XKX6NBHF.js} +5 -1
- package/dist/cli.js +405 -11
- package/dist/{db-ADBEBNH6.js → db-6WLEVKUV.js} +3 -1
- package/dist/esvp-GSISVXLC.js +52 -0
- package/dist/esvp-mobile-GC7MAGMI.js +20 -0
- package/dist/index.d.ts +123 -1
- package/dist/index.html +11689 -8690
- package/dist/index.js +67 -11
- package/dist/{ocr-UTWC7537.js → ocr-QDYNCSPE.js} +1 -1
- package/dist/{playwright-R7Y5HREH.js → playwright-VZ7PXDC5.js} +2 -2
- package/dist/runtime/esvp-host-runtime/darwin-arm64/esvp-host-runtime +0 -0
- package/dist/runtime/esvp-host-runtime/manifest.json +10 -0
- package/dist/{server-3FBHBA7L.js → server-6N3KIEGP.js} +2 -1
- package/dist/server-FO3UVUZU.js +22 -0
- package/dist/{setup-27CQAX6K.js → setup-2SQC5UHJ.js} +4 -3
- package/dist/{tools-L6PKKQPY.js → tools-OCRMOQ4U.js} +63 -8
- package/package.json +36 -5
- package/dist/chunk-22OCFYHG.js +0 -6283
- package/dist/chunk-24VARQVO.js +0 -7818
- package/dist/chunk-2OGZX6C4.js +0 -588
- package/dist/chunk-2WCNIFRO.js +0 -6191
- package/dist/chunk-43U6UYV7.js +0 -590
- package/dist/chunk-4H2E3K2G.js +0 -7638
- package/dist/chunk-4MS6YW2B.js +0 -6490
- package/dist/chunk-4NNTRJOI.js +0 -7791
- package/dist/chunk-5F76VWME.js +0 -6397
- package/dist/chunk-5NEFN42O.js +0 -7791
- package/dist/chunk-63MEQ6UH.js +0 -7673
- package/dist/chunk-6H3NXFX3.js +0 -6861
- package/dist/chunk-7IDQLLBW.js +0 -311
- package/dist/chunk-7NP64TGJ.js +0 -6822
- package/dist/chunk-AATLY4KT.js +0 -6505
- package/dist/chunk-C7QUR7XX.js +0 -6397
- package/dist/chunk-CGKCE6MC.js +0 -6279
- package/dist/chunk-D25V6IWE.js +0 -6487
- package/dist/chunk-EQOZSXAT.js +0 -6822
- package/dist/chunk-FPHD7HSQ.js +0 -6812
- package/dist/chunk-GGJJUCFK.js +0 -7160
- package/dist/chunk-GLHOY3NN.js +0 -7805
- package/dist/chunk-GML5MKQA.js +0 -6398
- package/dist/chunk-GOL6FUJL.js +0 -6045
- package/dist/chunk-GSWHWEYC.js +0 -1346
- package/dist/chunk-HDKEQOF5.js +0 -7788
- package/dist/chunk-HZGSWVVS.js +0 -7111
- package/dist/chunk-IGZ5TICZ.js +0 -334
- package/dist/chunk-IRKQG33A.js +0 -7054
- package/dist/chunk-JFTBF4JR.js +0 -6040
- package/dist/chunk-JVLVBPUJ.js +0 -6180
- package/dist/chunk-JY3KC67R.js +0 -6504
- package/dist/chunk-KUFBCBNJ.js +0 -6815
- package/dist/chunk-KV7KDJ43.js +0 -7639
- package/dist/chunk-L5IJZV5F.js +0 -6822
- package/dist/chunk-MFFPQLU4.js +0 -7102
- package/dist/chunk-MJS2YKNR.js +0 -6397
- package/dist/chunk-MN6LCZHZ.js +0 -1320
- package/dist/chunk-NBAUZ7X2.js +0 -1336
- package/dist/chunk-NDBW6ELQ.js +0 -7638
- package/dist/chunk-O2HBSDI2.js +0 -6175
- package/dist/chunk-OFFIUYMG.js +0 -6341
- package/dist/chunk-OVCQGF2J.js +0 -1321
- package/dist/chunk-P4S7ZY6G.js +0 -7638
- package/dist/chunk-PBHUHSC3.js +0 -6002
- package/dist/chunk-PC4LR4ZI.js +0 -6359
- package/dist/chunk-PMTGGZ7R.js +0 -6397
- package/dist/chunk-PTXSB3UV.js +0 -497
- package/dist/chunk-PYUCY3U6.js +0 -1340
- package/dist/chunk-RDZDSOAL.js +0 -7750
- package/dist/chunk-RLW2OI2L.js +0 -6383
- package/dist/chunk-RUGHHO4K.js +0 -6395
- package/dist/chunk-SIOQVM2E.js +0 -6819
- package/dist/chunk-SR67SRIT.js +0 -1336
- package/dist/chunk-SSRXIO2V.js +0 -6822
- package/dist/chunk-SWSEKFON.js +0 -6487
- package/dist/chunk-TBG76CYG.js +0 -6395
- package/dist/chunk-V3CBINLD.js +0 -6812
- package/dist/chunk-VPYSLEGM.js +0 -6710
- package/dist/chunk-VY3BLXBW.js +0 -329
- package/dist/chunk-WTFOGVJQ.js +0 -6365
- package/dist/chunk-X64SFUT5.js +0 -6099
- package/dist/chunk-XIBF5LBD.js +0 -6395
- package/dist/chunk-Y5VDMSYC.js +0 -6701
- package/dist/chunk-YUBL36H4.js +0 -6605
- package/dist/chunk-YWVXFVSW.js +0 -6456
- package/dist/chunk-ZXZACOLD.js +0 -6822
- package/dist/db-IWIL65EX.js +0 -33
- package/dist/gridCompositor-ENKLFPWR.js +0 -409
- package/dist/playwright-A3OGSDRG.js +0 -38
- package/dist/playwright-ATDC4NYW.js +0 -38
- package/dist/playwright-E6EUFIJG.js +0 -38
- package/dist/server-2DXLKLFM.js +0 -13
- package/dist/server-2ICEWJVK.js +0 -13
- package/dist/server-2MQV3FNY.js +0 -13
- package/dist/server-2NGD7GE3.js +0 -13
- package/dist/server-2VKO76UK.js +0 -14
- package/dist/server-3BK2VFU7.js +0 -13
- package/dist/server-4LDOB3NX.js +0 -13
- package/dist/server-4YI44KDR.js +0 -13
- package/dist/server-64XMXA5P.js +0 -13
- package/dist/server-6IPHVUYT.js +0 -14
- package/dist/server-73ORHMJN.js +0 -13
- package/dist/server-73P7M3QB.js +0 -14
- package/dist/server-BPVRW5LJ.js +0 -14
- package/dist/server-BW4RKZIX.js +0 -13
- package/dist/server-CFS5SM5K.js +0 -13
- package/dist/server-DX7VYHHM.js +0 -13
- package/dist/server-F3YPX6ET.js +0 -13
- package/dist/server-FUXTR33I.js +0 -13
- package/dist/server-G2SY3DOS.js +0 -13
- package/dist/server-G32U7VOQ.js +0 -13
- package/dist/server-IOOZK4NP.js +0 -14
- package/dist/server-J52LMTBT.js +0 -13
- package/dist/server-JG7UKFGK.js +0 -14
- package/dist/server-JSCHEBOD.js +0 -13
- package/dist/server-K6KC4ZOM.js +0 -13
- package/dist/server-KJVRGWFE.js +0 -13
- package/dist/server-LCPB2L4U.js +0 -13
- package/dist/server-M7LDYKAJ.js +0 -13
- package/dist/server-MKVK6ZQQ.js +0 -13
- package/dist/server-MU52LCXT.js +0 -13
- package/dist/server-NM5CKDUU.js +0 -13
- package/dist/server-NPZN3FWO.js +0 -14
- package/dist/server-O5FIAHSY.js +0 -14
- package/dist/server-OESJUEYC.js +0 -13
- package/dist/server-ONSKQO4W.js +0 -13
- package/dist/server-P27BZXBL.js +0 -14
- package/dist/server-Q4FBWQUA.js +0 -13
- package/dist/server-RNQ7VUAL.js +0 -13
- package/dist/server-S6B5WUBT.js +0 -14
- package/dist/server-SRYNSGSP.js +0 -14
- package/dist/server-SUN3W2YK.js +0 -13
- package/dist/server-UA62LHZB.js +0 -13
- package/dist/server-UJB44EW5.js +0 -13
- package/dist/server-X3TLP6DX.js +0 -14
- package/dist/server-YT2UGEZK.js +0 -13
- package/dist/server-ZBPQ33V6.js +0 -14
- package/dist/setup-AQX4JQVR.js +0 -17
- package/dist/setup-EQTU7FI6.js +0 -17
- package/dist/tools-2KPB37GK.js +0 -178
- package/dist/tools-3H6IOWXV.js +0 -178
- package/dist/tools-3KYHPDCJ.js +0 -178
- package/dist/tools-75BAPCUM.js +0 -177
- package/dist/tools-BUVCUCRL.js +0 -178
- package/dist/tools-HDNODRS6.js +0 -178
- package/dist/tools-HP5MNY3D.js +0 -177
- package/dist/tools-N5N2IO7V.js +0 -178
- package/dist/tools-NFJEZ2FF.js +0 -177
- package/dist/tools-TLCKABUW.js +0 -178
|
@@ -159,8 +159,9 @@ var DB_PATH = join(DATA_DIR, "data.db");
|
|
|
159
159
|
var PROJECTS_DIR = join(DATA_DIR, "projects");
|
|
160
160
|
var EXPORTS_DIR = join(DATA_DIR, "exports");
|
|
161
161
|
var FRAMES_DIR = join(DATA_DIR, "frames");
|
|
162
|
+
var TEMPLATES_DIR = join(DATA_DIR, "templates");
|
|
162
163
|
function ensureDirectories() {
|
|
163
|
-
const dirs = [DATA_DIR, PROJECTS_DIR, EXPORTS_DIR, FRAMES_DIR];
|
|
164
|
+
const dirs = [DATA_DIR, PROJECTS_DIR, EXPORTS_DIR, FRAMES_DIR, TEMPLATES_DIR];
|
|
164
165
|
for (const dir of dirs) {
|
|
165
166
|
if (!existsSync(dir)) {
|
|
166
167
|
mkdirSync(dir, { recursive: true });
|
|
@@ -356,6 +357,7 @@ export {
|
|
|
356
357
|
PROJECTS_DIR,
|
|
357
358
|
EXPORTS_DIR,
|
|
358
359
|
FRAMES_DIR,
|
|
360
|
+
TEMPLATES_DIR,
|
|
359
361
|
getDatabase,
|
|
360
362
|
getSqlite,
|
|
361
363
|
closeDatabase
|
|
@@ -181,12 +181,18 @@ async function recognizeText(imagePath, options = {}) {
|
|
|
181
181
|
}
|
|
182
182
|
return recognizeTextWithTesseract(imagePath, options);
|
|
183
183
|
}
|
|
184
|
-
async function recognizeTextBatch(imagePaths, options = {}) {
|
|
184
|
+
async function recognizeTextBatch(imagePaths, options = {}, onProgress) {
|
|
185
185
|
const results = [];
|
|
186
186
|
const textParts = [];
|
|
187
|
-
for (const imagePath of imagePaths) {
|
|
187
|
+
for (const [index, imagePath] of imagePaths.entries()) {
|
|
188
188
|
const ocr = await recognizeText(imagePath, options);
|
|
189
189
|
results.push({ imagePath, ocr });
|
|
190
|
+
onProgress?.({
|
|
191
|
+
current: index + 1,
|
|
192
|
+
total: imagePaths.length,
|
|
193
|
+
imagePath,
|
|
194
|
+
ocr
|
|
195
|
+
});
|
|
190
196
|
if (ocr.success && ocr.text) {
|
|
191
197
|
textParts.push(ocr.text);
|
|
192
198
|
}
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
+
import {
|
|
2
|
+
APP_VERSION
|
|
3
|
+
} from "./chunk-6EGBXRDK.js";
|
|
4
|
+
|
|
1
5
|
// src/mcp/server.ts
|
|
2
6
|
import { z } from "zod";
|
|
3
7
|
var MCPServer = class {
|
|
4
8
|
tools = /* @__PURE__ */ new Map();
|
|
5
9
|
serverInfo = {
|
|
6
10
|
name: "discoverylab",
|
|
7
|
-
version:
|
|
11
|
+
version: APP_VERSION
|
|
8
12
|
};
|
|
9
13
|
registerTool(tool) {
|
|
10
14
|
this.tools.set(tool.name, tool);
|
package/dist/cli.js
CHANGED
|
@@ -1,17 +1,395 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
APP_VERSION
|
|
4
|
+
} from "./chunk-6EGBXRDK.js";
|
|
5
|
+
import {
|
|
6
|
+
buildAppLabNetworkProfile
|
|
7
|
+
} from "./chunk-LB3RNE3O.js";
|
|
8
|
+
import "./chunk-MLKGABMK.js";
|
|
2
9
|
|
|
3
10
|
// src/cli.ts
|
|
4
11
|
import { Command } from "commander";
|
|
5
12
|
import chalk from "chalk";
|
|
6
13
|
import open from "open";
|
|
7
14
|
var program = new Command();
|
|
8
|
-
|
|
9
|
-
program.
|
|
15
|
+
var binName = process.argv[1]?.replace(/.*[\\/]/, "").replace(/\.[^.]+$/, "") === "applab" ? "applab" : "discoverylab";
|
|
16
|
+
program.name(binName).description("AI-powered app testing & evidence generator - Claude Code Plugin").version(APP_VERSION);
|
|
17
|
+
function printCliOutput(value) {
|
|
18
|
+
if (typeof value === "string") {
|
|
19
|
+
console.log(value);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
console.log(JSON.stringify(value, null, 2));
|
|
23
|
+
}
|
|
24
|
+
function failCli(message) {
|
|
25
|
+
throw new Error(message);
|
|
26
|
+
}
|
|
27
|
+
async function readJsonSource(json, filePath, label = "payload") {
|
|
28
|
+
if (json && filePath) {
|
|
29
|
+
failCli(`Use either --json or --file for ${label}, not both.`);
|
|
30
|
+
}
|
|
31
|
+
if (json) {
|
|
32
|
+
try {
|
|
33
|
+
return JSON.parse(json);
|
|
34
|
+
} catch (error) {
|
|
35
|
+
failCli(`Invalid ${label} JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (filePath) {
|
|
39
|
+
const { readFile } = await import("fs/promises");
|
|
40
|
+
const { resolve } = await import("path");
|
|
41
|
+
const raw = await readFile(resolve(process.cwd(), filePath), "utf8");
|
|
42
|
+
try {
|
|
43
|
+
return JSON.parse(raw);
|
|
44
|
+
} catch {
|
|
45
|
+
return raw;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
async function withESVPCli(action) {
|
|
51
|
+
try {
|
|
52
|
+
const result = await action();
|
|
53
|
+
printCliOutput(result);
|
|
54
|
+
} catch (error) {
|
|
55
|
+
console.error(chalk.red(` ESVP command failed: ${error instanceof Error ? error.message : String(error)}`));
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async function getESVPBaseResult(serverUrl) {
|
|
60
|
+
const { getESVPConnection } = await import("./esvp-GSISVXLC.js");
|
|
61
|
+
const connection = await getESVPConnection(serverUrl);
|
|
62
|
+
return {
|
|
63
|
+
serverUrl: connection.serverUrl,
|
|
64
|
+
connectionMode: connection.mode
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function executorToPlatform(executor) {
|
|
68
|
+
if (executor === "ios-sim" || executor === "maestro-ios") return "ios";
|
|
69
|
+
if (executor === "adb") return "android";
|
|
70
|
+
return void 0;
|
|
71
|
+
}
|
|
72
|
+
var esvp = program.command("esvp").description("Access the public ESVP protocol and runtime from the CLI");
|
|
73
|
+
esvp.command("status").description("Check the configured ESVP server health").option("-s, --server <url>", "ESVP base URL").action(async (options) => {
|
|
74
|
+
await withESVPCli(async () => {
|
|
75
|
+
const { getESVPHealth } = await import("./esvp-GSISVXLC.js");
|
|
76
|
+
return {
|
|
77
|
+
...await getESVPBaseResult(options.server),
|
|
78
|
+
health: await getESVPHealth(options.server)
|
|
79
|
+
};
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
esvp.command("devices").description("List ESVP-visible devices").option("-s, --server <url>", "ESVP base URL").option("-p, --platform <platform>", "adb | ios-sim | maestro-ios | all", "all").action(async (options) => {
|
|
83
|
+
await withESVPCli(async () => {
|
|
84
|
+
const { listESVPDevices } = await import("./esvp-GSISVXLC.js");
|
|
85
|
+
return {
|
|
86
|
+
...await getESVPBaseResult(options.server),
|
|
87
|
+
devices: await listESVPDevices(options.platform, options.server)
|
|
88
|
+
};
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
esvp.command("sessions").description("List public ESVP sessions").option("-s, --server <url>", "ESVP base URL").action(async (options) => {
|
|
92
|
+
await withESVPCli(async () => {
|
|
93
|
+
const { listESVPSessions } = await import("./esvp-GSISVXLC.js");
|
|
94
|
+
return {
|
|
95
|
+
...await getESVPBaseResult(options.server),
|
|
96
|
+
...await listESVPSessions(options.server)
|
|
97
|
+
};
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
esvp.command("create").description("Create a new ESVP session").requiredOption("-e, --executor <executor>", "fake | adb | ios-sim | maestro-ios").option("-s, --server <url>", "ESVP base URL").option("-d, --device-id <id>", "Device or simulator ID").option("--meta-json <json>", "Session metadata as JSON").option("--meta-file <path>", "Path to session metadata JSON").option("--crash-clip-json <json>", "Crash clip config as JSON").option("--crash-clip-file <path>", "Path to crash clip config JSON").option("--with-network", "Auto-configure the default App Lab external-proxy profile after creating the session").action(async (options) => {
|
|
101
|
+
await withESVPCli(async () => {
|
|
102
|
+
const { createESVPSession, configureESVPNetwork } = await import("./esvp-GSISVXLC.js");
|
|
103
|
+
const meta = await readJsonSource(options.metaJson, options.metaFile, "meta");
|
|
104
|
+
const crashClip = await readJsonSource(options.crashClipJson, options.crashClipFile, "crash clip");
|
|
105
|
+
const createResult = await createESVPSession(
|
|
106
|
+
{
|
|
107
|
+
executor: options.executor,
|
|
108
|
+
...options.deviceId ? { deviceId: options.deviceId } : {},
|
|
109
|
+
...meta ? { meta } : {},
|
|
110
|
+
...crashClip ? { crash_clip: crashClip } : {}
|
|
111
|
+
},
|
|
112
|
+
options.server
|
|
113
|
+
);
|
|
114
|
+
let networkConfigured = null;
|
|
115
|
+
if (options.withNetwork) {
|
|
116
|
+
const sessionId = String(createResult?.session?.id || createResult?.id || "");
|
|
117
|
+
if (sessionId) {
|
|
118
|
+
networkConfigured = await configureESVPNetwork(
|
|
119
|
+
sessionId,
|
|
120
|
+
buildAppLabNetworkProfile(
|
|
121
|
+
{
|
|
122
|
+
enabled: true,
|
|
123
|
+
mode: "external-proxy",
|
|
124
|
+
profile: "applab-standard-capture",
|
|
125
|
+
label: "App Lab Standard Capture"
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
platform: executorToPlatform(options.executor),
|
|
129
|
+
deviceId: options.deviceId
|
|
130
|
+
}
|
|
131
|
+
) || {},
|
|
132
|
+
options.server
|
|
133
|
+
).catch((err) => ({ error: err.message }));
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
...await getESVPBaseResult(options.server),
|
|
138
|
+
...createResult,
|
|
139
|
+
...networkConfigured ? { networkConfigured } : {}
|
|
140
|
+
};
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
esvp.command("get <sessionId>").description("Get a public ESVP session summary").option("-s, --server <url>", "ESVP base URL").action(async (sessionId, options) => {
|
|
144
|
+
await withESVPCli(async () => {
|
|
145
|
+
const { getESVPSession } = await import("./esvp-GSISVXLC.js");
|
|
146
|
+
return {
|
|
147
|
+
...await getESVPBaseResult(options.server),
|
|
148
|
+
...await getESVPSession(sessionId, options.server)
|
|
149
|
+
};
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
esvp.command("inspect <sessionId>").description("Inspect a session and optionally load transcript and artifacts").option("-s, --server <url>", "ESVP base URL").option("--transcript", "Include transcript").option("--artifacts", "Include artifacts").action(async (sessionId, options) => {
|
|
153
|
+
await withESVPCli(async () => {
|
|
154
|
+
const { inspectESVPSession } = await import("./esvp-GSISVXLC.js");
|
|
155
|
+
return {
|
|
156
|
+
...await getESVPBaseResult(options.server),
|
|
157
|
+
...await inspectESVPSession(
|
|
158
|
+
sessionId,
|
|
159
|
+
{
|
|
160
|
+
includeTranscript: options.transcript === true,
|
|
161
|
+
includeArtifacts: options.artifacts === true
|
|
162
|
+
},
|
|
163
|
+
options.server
|
|
164
|
+
)
|
|
165
|
+
};
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
esvp.command("transcript <sessionId>").description("Fetch the canonical session transcript").option("-s, --server <url>", "ESVP base URL").action(async (sessionId, options) => {
|
|
169
|
+
await withESVPCli(async () => {
|
|
170
|
+
const { getESVPTranscript } = await import("./esvp-GSISVXLC.js");
|
|
171
|
+
return {
|
|
172
|
+
...await getESVPBaseResult(options.server),
|
|
173
|
+
sessionId,
|
|
174
|
+
transcript: (await getESVPTranscript(sessionId, options.server))?.events || []
|
|
175
|
+
};
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
esvp.command("artifacts <sessionId>").description("List session artifacts").option("-s, --server <url>", "ESVP base URL").action(async (sessionId, options) => {
|
|
179
|
+
await withESVPCli(async () => {
|
|
180
|
+
const { listESVPArtifacts } = await import("./esvp-GSISVXLC.js");
|
|
181
|
+
return {
|
|
182
|
+
...await getESVPBaseResult(options.server),
|
|
183
|
+
sessionId,
|
|
184
|
+
artifacts: (await listESVPArtifacts(sessionId, options.server))?.artifacts || []
|
|
185
|
+
};
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
esvp.command("artifact <sessionId> <artifactPath>").description("Read a public artifact payload").option("-s, --server <url>", "ESVP base URL").action(async (sessionId, artifactPath, options) => {
|
|
189
|
+
await withESVPCli(async () => {
|
|
190
|
+
const { getESVPArtifactContent } = await import("./esvp-GSISVXLC.js");
|
|
191
|
+
return await getESVPArtifactContent(sessionId, artifactPath, options.server);
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
esvp.command("actions <sessionId>").description("Run public ESVP actions inside a session").option("-s, --server <url>", "ESVP base URL").option("--actions-json <json>", "JSON array of ESVP actions").option("--actions-file <path>", "Path to a JSON file with ESVP actions").option("--finish", "Finish the session after actions").option("--capture-logcat", "Capture logcat on finish when supported").option("--checkpoint-after-each", "Set checkpointAfter on every action").option("--with-network", "Auto-configure the default App Lab external-proxy profile before running actions if not already configured").action(async (sessionId, options) => {
|
|
195
|
+
await withESVPCli(async () => {
|
|
196
|
+
const { runESVPActions, getESVPSessionNetwork, configureESVPNetwork } = await import("./esvp-GSISVXLC.js");
|
|
197
|
+
const actions = await readJsonSource(options.actionsJson, options.actionsFile, "actions");
|
|
198
|
+
if (!Array.isArray(actions) || actions.length === 0) {
|
|
199
|
+
failCli("Provide --actions-json or --actions-file with a non-empty array of ESVP actions.");
|
|
200
|
+
}
|
|
201
|
+
let networkConfigured = null;
|
|
202
|
+
if (options.withNetwork) {
|
|
203
|
+
const networkState = await getESVPSessionNetwork(sessionId, options.server).catch(() => null);
|
|
204
|
+
const hasActiveProfile = networkState?.network?.active_profile || networkState?.network?.effective_profile;
|
|
205
|
+
if (!hasActiveProfile) {
|
|
206
|
+
networkConfigured = await configureESVPNetwork(
|
|
207
|
+
sessionId,
|
|
208
|
+
buildAppLabNetworkProfile(
|
|
209
|
+
{
|
|
210
|
+
enabled: true,
|
|
211
|
+
mode: "external-proxy",
|
|
212
|
+
profile: "applab-standard-capture",
|
|
213
|
+
label: "App Lab Standard Capture"
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
platform: executorToPlatform(typeof networkState?.session?.executor === "string" ? networkState.session.executor : void 0),
|
|
217
|
+
deviceId: typeof networkState?.session?.device_id === "string" ? networkState.session.device_id : void 0
|
|
218
|
+
}
|
|
219
|
+
) || {},
|
|
220
|
+
options.server
|
|
221
|
+
).catch((err) => ({ error: err.message }));
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return {
|
|
225
|
+
...await getESVPBaseResult(options.server),
|
|
226
|
+
...networkConfigured ? { networkConfigured } : {},
|
|
227
|
+
...await runESVPActions(
|
|
228
|
+
sessionId,
|
|
229
|
+
{
|
|
230
|
+
actions,
|
|
231
|
+
finish: options.finish === true,
|
|
232
|
+
captureLogcat: options.captureLogcat === true,
|
|
233
|
+
checkpointAfterEach: options.checkpointAfterEach === true
|
|
234
|
+
},
|
|
235
|
+
options.server
|
|
236
|
+
)
|
|
237
|
+
};
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
esvp.command("checkpoint <sessionId>").description("Capture an ESVP checkpoint").option("-s, --server <url>", "ESVP base URL").option("-l, --label <label>", "Checkpoint label").action(async (sessionId, options) => {
|
|
241
|
+
await withESVPCli(async () => {
|
|
242
|
+
const { captureESVPCheckpoint } = await import("./esvp-GSISVXLC.js");
|
|
243
|
+
return {
|
|
244
|
+
...await getESVPBaseResult(options.server),
|
|
245
|
+
...await captureESVPCheckpoint(
|
|
246
|
+
sessionId,
|
|
247
|
+
{
|
|
248
|
+
...options.label ? { label: options.label } : {}
|
|
249
|
+
},
|
|
250
|
+
options.server
|
|
251
|
+
)
|
|
252
|
+
};
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
esvp.command("finish <sessionId>").description("Finish an ESVP session").option("-s, --server <url>", "ESVP base URL").option("--capture-logcat", "Capture logcat on finish when supported").action(async (sessionId, options) => {
|
|
256
|
+
await withESVPCli(async () => {
|
|
257
|
+
const { finishESVPSession } = await import("./esvp-GSISVXLC.js");
|
|
258
|
+
return {
|
|
259
|
+
...await getESVPBaseResult(options.server),
|
|
260
|
+
...await finishESVPSession(
|
|
261
|
+
sessionId,
|
|
262
|
+
{
|
|
263
|
+
captureLogcat: options.captureLogcat === true
|
|
264
|
+
},
|
|
265
|
+
options.server
|
|
266
|
+
)
|
|
267
|
+
};
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
esvp.command("preflight <sessionId>").description("Run preflight/bootstrap rules on an ESVP session").option("-s, --server <url>", "ESVP base URL").option("--policy <policy>", "Preflight policy name (e.g. fresh_install)").option("--app-id <appId>", "Target app ID").option("--json <json>", "Preflight config as JSON string").option("--file <path>", "Path to preflight config JSON file").action(async (sessionId, options) => {
|
|
271
|
+
await withESVPCli(async () => {
|
|
272
|
+
const { runESVPPreflight } = await import("./esvp-GSISVXLC.js");
|
|
273
|
+
const fromSource = await readJsonSource(options.json, options.file, "preflight config");
|
|
274
|
+
const config = {
|
|
275
|
+
...typeof fromSource === "object" && fromSource ? fromSource : {},
|
|
276
|
+
...options.policy ? { policy: options.policy } : {},
|
|
277
|
+
...options.appId ? { appId: options.appId } : {}
|
|
278
|
+
};
|
|
279
|
+
return {
|
|
280
|
+
...await getESVPBaseResult(options.server),
|
|
281
|
+
...await runESVPPreflight(sessionId, config, options.server)
|
|
282
|
+
};
|
|
283
|
+
});
|
|
284
|
+
});
|
|
285
|
+
esvp.command("replay-run <sessionId>").description("Replay a session to a new ESVP session").option("-s, --server <url>", "ESVP base URL").option("-e, --executor <executor>", "fake | adb | ios-sim | maestro-ios").option("-d, --device-id <id>", "Replay target device ID").option("--capture-logcat", "Capture logcat on finish when supported").option("--meta-json <json>", "Replay metadata as JSON").option("--meta-file <path>", "Path to replay metadata JSON").action(async (sessionId, options) => {
|
|
286
|
+
await withESVPCli(async () => {
|
|
287
|
+
const { replayESVPSession, getESVPReplayConsistency } = await import("./esvp-GSISVXLC.js");
|
|
288
|
+
const meta = await readJsonSource(options.metaJson, options.metaFile, "replay meta");
|
|
289
|
+
const replay = await replayESVPSession(
|
|
290
|
+
sessionId,
|
|
291
|
+
{
|
|
292
|
+
...options.executor ? { executor: options.executor } : {},
|
|
293
|
+
...options.deviceId ? { deviceId: options.deviceId } : {},
|
|
294
|
+
...options.captureLogcat === true ? { captureLogcat: true } : {},
|
|
295
|
+
...meta ? { meta } : {}
|
|
296
|
+
},
|
|
297
|
+
options.server
|
|
298
|
+
);
|
|
299
|
+
const replaySessionId = replay?.replay_session?.id;
|
|
300
|
+
const replayConsistency = replaySessionId ? (await getESVPReplayConsistency(replaySessionId, options.server)).replay_consistency : null;
|
|
301
|
+
return {
|
|
302
|
+
...await getESVPBaseResult(options.server),
|
|
303
|
+
...replay,
|
|
304
|
+
replayConsistency
|
|
305
|
+
};
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
esvp.command("replay-validate <sessionId>").description("Validate whether a session supports public replay").option("-s, --server <url>", "ESVP base URL").action(async (sessionId, options) => {
|
|
309
|
+
await withESVPCli(async () => {
|
|
310
|
+
const { validateESVPReplay } = await import("./esvp-GSISVXLC.js");
|
|
311
|
+
return {
|
|
312
|
+
...await getESVPBaseResult(options.server),
|
|
313
|
+
...await validateESVPReplay(sessionId, options.server)
|
|
314
|
+
};
|
|
315
|
+
});
|
|
316
|
+
});
|
|
317
|
+
esvp.command("replay-consistency <sessionId>").description("Inspect replay consistency for a replay session").option("-s, --server <url>", "ESVP base URL").action(async (sessionId, options) => {
|
|
318
|
+
await withESVPCli(async () => {
|
|
319
|
+
const { getESVPReplayConsistency } = await import("./esvp-GSISVXLC.js");
|
|
320
|
+
return {
|
|
321
|
+
...await getESVPBaseResult(options.server),
|
|
322
|
+
...await getESVPReplayConsistency(sessionId, options.server)
|
|
323
|
+
};
|
|
324
|
+
});
|
|
325
|
+
});
|
|
326
|
+
esvp.command("network <sessionId>").description("Read the public network state for a session").option("-s, --server <url>", "ESVP base URL").action(async (sessionId, options) => {
|
|
327
|
+
await withESVPCli(async () => {
|
|
328
|
+
const { getESVPSessionNetwork } = await import("./esvp-GSISVXLC.js");
|
|
329
|
+
return {
|
|
330
|
+
...await getESVPBaseResult(options.server),
|
|
331
|
+
...await getESVPSessionNetwork(sessionId, options.server)
|
|
332
|
+
};
|
|
333
|
+
});
|
|
334
|
+
});
|
|
335
|
+
esvp.command("network-configure <sessionId>").description("Apply a public ESVP network profile").option("-s, --server <url>", "ESVP base URL").option("--json <json>", "Raw network profile JSON").option("--file <path>", "Path to network profile JSON").option("--profile <name>", "Profile name").option("--label <label>", "Profile label").option("--connectivity <state>", "online | offline | reset").action(async (sessionId, options) => {
|
|
336
|
+
await withESVPCli(async () => {
|
|
337
|
+
const { configureESVPNetwork } = await import("./esvp-GSISVXLC.js");
|
|
338
|
+
const payload = await readJsonSource(options.json, options.file, "network profile") || {};
|
|
339
|
+
const merged = {
|
|
340
|
+
...typeof payload === "object" && payload ? payload : {},
|
|
341
|
+
...options.profile ? { profile: options.profile } : {},
|
|
342
|
+
...options.label ? { label: options.label } : {},
|
|
343
|
+
...options.connectivity ? { connectivity: options.connectivity } : {}
|
|
344
|
+
};
|
|
345
|
+
return {
|
|
346
|
+
...await getESVPBaseResult(options.server),
|
|
347
|
+
...await configureESVPNetwork(sessionId, merged, options.server)
|
|
348
|
+
};
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
esvp.command("network-clear <sessionId>").description("Clear the active ESVP network profile").option("-s, --server <url>", "ESVP base URL").action(async (sessionId, options) => {
|
|
352
|
+
await withESVPCli(async () => {
|
|
353
|
+
const { clearESVPNetwork } = await import("./esvp-GSISVXLC.js");
|
|
354
|
+
return {
|
|
355
|
+
...await getESVPBaseResult(options.server),
|
|
356
|
+
...await clearESVPNetwork(sessionId, options.server)
|
|
357
|
+
};
|
|
358
|
+
});
|
|
359
|
+
});
|
|
360
|
+
esvp.command("trace-attach <sessionId>").description("Attach a public network trace artifact to a session").requiredOption("--trace-kind <kind>", "Trace kind, e.g. http_trace or har").option("-s, --server <url>", "ESVP base URL").option("--json <json>", "Trace payload JSON").option("--file <path>", "Path to trace payload JSON/text").option("--label <label>", "Trace label").option("--source <source>", "Trace source").option("--request-id <id>", "Correlated request ID").option("--method <method>", "HTTP method").option("--url <url>", "Request URL").option("--status-code <code>", "HTTP status code").option("--format <format>", "Payload format label").action(async (sessionId, options) => {
|
|
361
|
+
await withESVPCli(async () => {
|
|
362
|
+
const { attachESVPNetworkTrace } = await import("./esvp-GSISVXLC.js");
|
|
363
|
+
const payload = await readJsonSource(options.json, options.file, "trace payload");
|
|
364
|
+
if (payload == null) {
|
|
365
|
+
failCli("Provide --json or --file with the trace payload to attach.");
|
|
366
|
+
}
|
|
367
|
+
return {
|
|
368
|
+
...await getESVPBaseResult(options.server),
|
|
369
|
+
...await attachESVPNetworkTrace(
|
|
370
|
+
sessionId,
|
|
371
|
+
{
|
|
372
|
+
trace_kind: options.traceKind,
|
|
373
|
+
...options.label ? { label: options.label } : {},
|
|
374
|
+
...options.source ? { source: options.source } : {},
|
|
375
|
+
...options.requestId ? { request_id: options.requestId } : {},
|
|
376
|
+
...options.method ? { method: options.method } : {},
|
|
377
|
+
...options.url ? { url: options.url } : {},
|
|
378
|
+
...options.statusCode ? { status_code: Number(options.statusCode) } : {},
|
|
379
|
+
...options.format ? { format: options.format } : {},
|
|
380
|
+
payload
|
|
381
|
+
},
|
|
382
|
+
options.server
|
|
383
|
+
)
|
|
384
|
+
};
|
|
385
|
+
});
|
|
386
|
+
});
|
|
387
|
+
program.command("serve").alias("server").description("Start the DiscoveryLab web UI server").option("-p, --port <number>", "Port to listen on", "3847").option("-o, --open", "Open browser automatically", false).action(async (options) => {
|
|
10
388
|
const port = parseInt(options.port, 10);
|
|
11
389
|
console.log(chalk.cyan("\n DiscoveryLab"));
|
|
12
390
|
console.log(chalk.gray(" AI-powered app testing & evidence generator\n"));
|
|
13
391
|
try {
|
|
14
|
-
const { startServer } = await import("./server-
|
|
392
|
+
const { startServer } = await import("./server-FO3UVUZU.js");
|
|
15
393
|
await startServer(port);
|
|
16
394
|
console.log(chalk.green(` Server running at http://localhost:${port}`));
|
|
17
395
|
console.log(chalk.gray(" Press Ctrl+C to stop\n"));
|
|
@@ -26,7 +404,7 @@ program.command("serve").description("Start the DiscoveryLab web UI server").opt
|
|
|
26
404
|
program.command("setup").description("Check and configure DiscoveryLab dependencies").action(async () => {
|
|
27
405
|
console.log(chalk.cyan("\n DiscoveryLab Setup\n"));
|
|
28
406
|
try {
|
|
29
|
-
const { setupStatusTool } = await import("./setup-
|
|
407
|
+
const { setupStatusTool } = await import("./setup-2SQC5UHJ.js");
|
|
30
408
|
const result = await setupStatusTool.handler({});
|
|
31
409
|
if (result.isError) {
|
|
32
410
|
console.error(chalk.red(" Setup check failed"));
|
|
@@ -62,7 +440,7 @@ program.command("setup").description("Check and configure DiscoveryLab dependenc
|
|
|
62
440
|
program.command("init").description("Initialize DiscoveryLab data directories").action(async () => {
|
|
63
441
|
console.log(chalk.cyan("\n Initializing DiscoveryLab...\n"));
|
|
64
442
|
try {
|
|
65
|
-
const { getDatabase, DATA_DIR, PROJECTS_DIR, EXPORTS_DIR } = await import("./db-
|
|
443
|
+
const { getDatabase, DATA_DIR, PROJECTS_DIR, EXPORTS_DIR } = await import("./db-6WLEVKUV.js");
|
|
66
444
|
getDatabase();
|
|
67
445
|
console.log(chalk.green(" Created directories:"));
|
|
68
446
|
console.log(chalk.gray(` ${DATA_DIR}`));
|
|
@@ -108,10 +486,22 @@ program.command("install").description("Install DiscoveryLab as Claude Code MCP
|
|
|
108
486
|
});
|
|
109
487
|
program.command("mcp").description("Run as MCP server (for Claude Code integration)").action(async () => {
|
|
110
488
|
try {
|
|
111
|
-
const { getDatabase } = await import("./db-
|
|
489
|
+
const { getDatabase } = await import("./db-6WLEVKUV.js");
|
|
112
490
|
getDatabase();
|
|
113
|
-
const { mcpServer } = await import("./server-
|
|
114
|
-
const {
|
|
491
|
+
const { mcpServer } = await import("./server-6N3KIEGP.js");
|
|
492
|
+
const {
|
|
493
|
+
uiTools,
|
|
494
|
+
projectTools,
|
|
495
|
+
setupTools,
|
|
496
|
+
captureTools,
|
|
497
|
+
analyzeTools,
|
|
498
|
+
canvasTools,
|
|
499
|
+
exportTools,
|
|
500
|
+
testingTools,
|
|
501
|
+
integrationTools,
|
|
502
|
+
taskHubTools,
|
|
503
|
+
esvpTools
|
|
504
|
+
} = await import("./tools-OCRMOQ4U.js");
|
|
115
505
|
mcpServer.registerTools([
|
|
116
506
|
...uiTools,
|
|
117
507
|
...projectTools,
|
|
@@ -121,7 +511,9 @@ program.command("mcp").description("Run as MCP server (for Claude Code integrati
|
|
|
121
511
|
...canvasTools,
|
|
122
512
|
...exportTools,
|
|
123
513
|
...testingTools,
|
|
124
|
-
...integrationTools
|
|
514
|
+
...integrationTools,
|
|
515
|
+
...taskHubTools,
|
|
516
|
+
...esvpTools
|
|
125
517
|
]);
|
|
126
518
|
await mcpServer.runStdio();
|
|
127
519
|
} catch (error) {
|
|
@@ -130,11 +522,13 @@ program.command("mcp").description("Run as MCP server (for Claude Code integrati
|
|
|
130
522
|
}
|
|
131
523
|
});
|
|
132
524
|
program.command("info").description("Show version and configuration info").action(async () => {
|
|
133
|
-
console.log(chalk.cyan(
|
|
525
|
+
console.log(chalk.cyan(`
|
|
526
|
+
DiscoveryLab v${APP_VERSION}
|
|
527
|
+
`));
|
|
134
528
|
console.log(chalk.gray(" AI-powered app testing & evidence generator"));
|
|
135
529
|
console.log(chalk.gray(" Claude Code Plugin\n"));
|
|
136
530
|
try {
|
|
137
|
-
const { DATA_DIR, DB_PATH } = await import("./db-
|
|
531
|
+
const { DATA_DIR, DB_PATH } = await import("./db-6WLEVKUV.js");
|
|
138
532
|
console.log(chalk.white(" Paths:"));
|
|
139
533
|
console.log(chalk.gray(` Data: ${DATA_DIR}`));
|
|
140
534
|
console.log(chalk.gray(` Database: ${DB_PATH}`));
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
EXPORTS_DIR,
|
|
5
5
|
FRAMES_DIR,
|
|
6
6
|
PROJECTS_DIR,
|
|
7
|
+
TEMPLATES_DIR,
|
|
7
8
|
closeDatabase,
|
|
8
9
|
exportDestinations,
|
|
9
10
|
exportRules,
|
|
@@ -14,7 +15,7 @@ import {
|
|
|
14
15
|
projects,
|
|
15
16
|
settings,
|
|
16
17
|
testVariables
|
|
17
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-VVIOB362.js";
|
|
18
19
|
import "./chunk-MLKGABMK.js";
|
|
19
20
|
export {
|
|
20
21
|
DATA_DIR,
|
|
@@ -22,6 +23,7 @@ export {
|
|
|
22
23
|
EXPORTS_DIR,
|
|
23
24
|
FRAMES_DIR,
|
|
24
25
|
PROJECTS_DIR,
|
|
26
|
+
TEMPLATES_DIR,
|
|
25
27
|
closeDatabase,
|
|
26
28
|
exportDestinations,
|
|
27
29
|
exportRules,
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import {
|
|
2
|
+
attachESVPNetworkTrace,
|
|
3
|
+
captureESVPCheckpoint,
|
|
4
|
+
clearESVPNetwork,
|
|
5
|
+
configureESVPNetwork,
|
|
6
|
+
createESVPSession,
|
|
7
|
+
finishESVPSession,
|
|
8
|
+
getESVPArtifactContent,
|
|
9
|
+
getESVPBaseUrl,
|
|
10
|
+
getESVPConnection,
|
|
11
|
+
getESVPHealth,
|
|
12
|
+
getESVPReplayConsistency,
|
|
13
|
+
getESVPSession,
|
|
14
|
+
getESVPSessionNetwork,
|
|
15
|
+
getESVPTranscript,
|
|
16
|
+
inspectESVPSession,
|
|
17
|
+
listESVPArtifacts,
|
|
18
|
+
listESVPDevices,
|
|
19
|
+
listESVPSessions,
|
|
20
|
+
replayESVPSession,
|
|
21
|
+
resolveESVPBaseUrl,
|
|
22
|
+
runESVPActions,
|
|
23
|
+
runESVPPreflight,
|
|
24
|
+
validateESVPReplay
|
|
25
|
+
} from "./chunk-GAKEFJ5T.js";
|
|
26
|
+
import "./chunk-VVIOB362.js";
|
|
27
|
+
import "./chunk-MLKGABMK.js";
|
|
28
|
+
export {
|
|
29
|
+
attachESVPNetworkTrace,
|
|
30
|
+
captureESVPCheckpoint,
|
|
31
|
+
clearESVPNetwork,
|
|
32
|
+
configureESVPNetwork,
|
|
33
|
+
createESVPSession,
|
|
34
|
+
finishESVPSession,
|
|
35
|
+
getESVPArtifactContent,
|
|
36
|
+
getESVPBaseUrl,
|
|
37
|
+
getESVPConnection,
|
|
38
|
+
getESVPHealth,
|
|
39
|
+
getESVPReplayConsistency,
|
|
40
|
+
getESVPSession,
|
|
41
|
+
getESVPSessionNetwork,
|
|
42
|
+
getESVPTranscript,
|
|
43
|
+
inspectESVPSession,
|
|
44
|
+
listESVPArtifacts,
|
|
45
|
+
listESVPDevices,
|
|
46
|
+
listESVPSessions,
|
|
47
|
+
replayESVPSession,
|
|
48
|
+
resolveESVPBaseUrl,
|
|
49
|
+
runESVPActions,
|
|
50
|
+
runESVPPreflight,
|
|
51
|
+
validateESVPReplay
|
|
52
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {
|
|
2
|
+
collectESVPSessionNetworkData,
|
|
3
|
+
createMobileNetworkCaptureMeta,
|
|
4
|
+
diagnoseESVPNetworkState,
|
|
5
|
+
translateMaestroActionsToESVP,
|
|
6
|
+
validateMaestroRecordingWithESVP
|
|
7
|
+
} from "./chunk-N6JJ2RGV.js";
|
|
8
|
+
import "./chunk-LB3RNE3O.js";
|
|
9
|
+
import "./chunk-GAKEFJ5T.js";
|
|
10
|
+
import "./chunk-SLNJEF32.js";
|
|
11
|
+
import "./chunk-VVIOB362.js";
|
|
12
|
+
import "./chunk-XFVDP332.js";
|
|
13
|
+
import "./chunk-MLKGABMK.js";
|
|
14
|
+
export {
|
|
15
|
+
collectESVPSessionNetworkData,
|
|
16
|
+
createMobileNetworkCaptureMeta,
|
|
17
|
+
diagnoseESVPNetworkState,
|
|
18
|
+
translateMaestroActionsToESVP,
|
|
19
|
+
validateMaestroRecordingWithESVP
|
|
20
|
+
};
|