@veolab/discoverylab 1.2.2 → 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-YEZ26ENO.js → chunk-3QRQEDWR.js} +313 -192
- package/dist/{chunk-E3N3P2AG.js → chunk-4L76GPRC.js} +1124 -51
- package/dist/{chunk-I6YD3QFM.js → chunk-FIL7IWEL.js} +5 -3
- package/dist/{chunk-G524UVBK.js → chunk-FNUN7EPB.js} +5 -5
- package/dist/chunk-GAKEFJ5T.js +481 -0
- package/dist/chunk-LB3RNE3O.js +109 -0
- package/dist/chunk-N6JJ2RGV.js +2680 -0
- package/dist/{chunk-7HZEDTS7.js → chunk-VRM42PML.js} +3471 -848
- package/dist/{chunk-TJ3H23LL.js → chunk-VVIOB362.js} +3 -1
- package/dist/{chunk-W3WJGYR6.js → chunk-XFVDP332.js} +8 -2
- package/dist/cli.js +397 -9
- 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 -12
- 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-FO3UVUZU.js +22 -0
- package/dist/{setup-B5YPNUE4.js → setup-2SQC5UHJ.js} +2 -2
- package/dist/{tools-YS4QHOTQ.js → tools-OCRMOQ4U.js} +61 -6
- 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-4KLG6DDE.js +0 -334
- 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-7DOG2W4O.js +0 -6428
- 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-L4SA5F5W.js +0 -6397
- 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-QJXXHOV7.js +0 -205
- 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-TAODYZ52.js +0 -1393
- 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-XUKWS2CE.js +0 -7805
- package/dist/chunk-XZZKFF5V.js +0 -7787
- package/dist/chunk-Y5VDMSYC.js +0 -6701
- package/dist/chunk-YUBL36H4.js +0 -6605
- package/dist/chunk-YWVXFVSW.js +0 -6456
- package/dist/chunk-ZJFWMSZF.js +0 -7883
- 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-3FBHBA7L.js +0 -15
- 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-HKRIY7FP.js +0 -14
- package/dist/server-HON66OES.js +0 -15
- package/dist/server-IOOZK4NP.js +0 -14
- package/dist/server-IZEO7OJJ.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-27CQAX6K.js +0 -17
- 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-L6PKKQPY.js +0 -179
- package/dist/tools-N5N2IO7V.js +0 -178
- package/dist/tools-NFJEZ2FF.js +0 -177
- package/dist/tools-OPULIER6.js +0 -178
- package/dist/tools-TLCKABUW.js +0 -178
|
@@ -1,16 +1,23 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createErrorResult,
|
|
3
|
+
createJsonResult,
|
|
4
|
+
createTextResult
|
|
5
|
+
} from "./chunk-XKX6NBHF.js";
|
|
1
6
|
import {
|
|
2
7
|
createLoginFlow,
|
|
3
8
|
createNavigationTestFlow,
|
|
4
9
|
createOnboardingFlow,
|
|
5
10
|
generateMaestroFlow,
|
|
6
11
|
getAdbCommand,
|
|
12
|
+
getAvailableTemplates,
|
|
7
13
|
getMaestroVersion,
|
|
8
14
|
isMaestroInstalled,
|
|
15
|
+
isTemplatesInstalled,
|
|
9
16
|
listMaestroDevices,
|
|
10
17
|
runMaestroTest,
|
|
11
18
|
runMaestroWithCapture,
|
|
12
19
|
startMaestroStudio
|
|
13
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-3QRQEDWR.js";
|
|
14
21
|
import {
|
|
15
22
|
createFormSubmissionScript,
|
|
16
23
|
createLoginScript,
|
|
@@ -23,13 +30,33 @@ import {
|
|
|
23
30
|
savePlaywrightScript,
|
|
24
31
|
showPlaywrightReport,
|
|
25
32
|
startPlaywrightCodegen
|
|
26
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-FIL7IWEL.js";
|
|
27
34
|
import {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
35
|
+
buildAppLabNetworkProfile
|
|
36
|
+
} from "./chunk-LB3RNE3O.js";
|
|
37
|
+
import {
|
|
38
|
+
attachESVPNetworkTrace,
|
|
39
|
+
captureESVPCheckpoint,
|
|
40
|
+
clearESVPNetwork,
|
|
41
|
+
configureESVPNetwork,
|
|
42
|
+
createESVPSession,
|
|
43
|
+
finishESVPSession,
|
|
44
|
+
getESVPArtifactContent,
|
|
45
|
+
getESVPConnection,
|
|
46
|
+
getESVPHealth,
|
|
47
|
+
getESVPReplayConsistency,
|
|
48
|
+
getESVPSession,
|
|
49
|
+
getESVPSessionNetwork,
|
|
50
|
+
getESVPTranscript,
|
|
51
|
+
inspectESVPSession,
|
|
52
|
+
listESVPArtifacts,
|
|
53
|
+
listESVPDevices,
|
|
54
|
+
listESVPSessions,
|
|
55
|
+
replayESVPSession,
|
|
56
|
+
runESVPActions,
|
|
57
|
+
runESVPPreflight,
|
|
58
|
+
validateESVPReplay
|
|
59
|
+
} from "./chunk-GAKEFJ5T.js";
|
|
33
60
|
import {
|
|
34
61
|
DATA_DIR,
|
|
35
62
|
EXPORTS_DIR,
|
|
@@ -40,12 +67,13 @@ import {
|
|
|
40
67
|
projectExports,
|
|
41
68
|
projects,
|
|
42
69
|
testVariables
|
|
43
|
-
} from "./chunk-
|
|
70
|
+
} from "./chunk-VVIOB362.js";
|
|
44
71
|
import {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
72
|
+
analyzeText,
|
|
73
|
+
getAvailableOCREngines,
|
|
74
|
+
recognizeText,
|
|
75
|
+
recognizeTextBatch
|
|
76
|
+
} from "./chunk-XFVDP332.js";
|
|
49
77
|
|
|
50
78
|
// src/mcp/tools/ui.ts
|
|
51
79
|
import { z } from "zod";
|
|
@@ -338,17 +366,17 @@ async function captureMacScreenshot(outputPath, options) {
|
|
|
338
366
|
args.push("-R", `${x},${y},${width},${height}`);
|
|
339
367
|
}
|
|
340
368
|
args.push(outputPath);
|
|
341
|
-
return new Promise((
|
|
369
|
+
return new Promise((resolve2) => {
|
|
342
370
|
const proc = spawn("screencapture", args);
|
|
343
371
|
proc.on("close", (code) => {
|
|
344
372
|
if (code === 0 && existsSync(outputPath)) {
|
|
345
|
-
|
|
373
|
+
resolve2({ success: true, filePath: outputPath });
|
|
346
374
|
} else {
|
|
347
|
-
|
|
375
|
+
resolve2({ success: false, error: `screencapture exited with code ${code}` });
|
|
348
376
|
}
|
|
349
377
|
});
|
|
350
378
|
proc.on("error", (err) => {
|
|
351
|
-
|
|
379
|
+
resolve2({ success: false, error: err.message });
|
|
352
380
|
});
|
|
353
381
|
});
|
|
354
382
|
}
|
|
@@ -357,16 +385,16 @@ async function captureLinuxScreenshot(outputPath, options) {
|
|
|
357
385
|
if (options.windowId) {
|
|
358
386
|
args.push("-w");
|
|
359
387
|
}
|
|
360
|
-
return new Promise((
|
|
388
|
+
return new Promise((resolve2) => {
|
|
361
389
|
let proc = spawn("gnome-screenshot", args);
|
|
362
390
|
proc.on("error", () => {
|
|
363
391
|
proc = spawn("scrot", [outputPath]);
|
|
364
392
|
});
|
|
365
393
|
proc.on("close", (code) => {
|
|
366
394
|
if (code === 0 && existsSync(outputPath)) {
|
|
367
|
-
|
|
395
|
+
resolve2({ success: true, filePath: outputPath });
|
|
368
396
|
} else {
|
|
369
|
-
|
|
397
|
+
resolve2({ success: false, error: `Screenshot failed with code ${code}` });
|
|
370
398
|
}
|
|
371
399
|
});
|
|
372
400
|
});
|
|
@@ -381,17 +409,17 @@ async function captureWindowsScreenshot(outputPath, _options) {
|
|
|
381
409
|
$bitmap.Save('${outputPath.replace(/\\/g, "\\\\")}')
|
|
382
410
|
}
|
|
383
411
|
`;
|
|
384
|
-
return new Promise((
|
|
412
|
+
return new Promise((resolve2) => {
|
|
385
413
|
const proc = spawn("powershell", ["-Command", psScript]);
|
|
386
414
|
proc.on("close", (code) => {
|
|
387
415
|
if (code === 0 && existsSync(outputPath)) {
|
|
388
|
-
|
|
416
|
+
resolve2({ success: true, filePath: outputPath });
|
|
389
417
|
} else {
|
|
390
|
-
|
|
418
|
+
resolve2({ success: false, error: `PowerShell screenshot failed with code ${code}` });
|
|
391
419
|
}
|
|
392
420
|
});
|
|
393
421
|
proc.on("error", (err) => {
|
|
394
|
-
|
|
422
|
+
resolve2({ success: false, error: err.message });
|
|
395
423
|
});
|
|
396
424
|
});
|
|
397
425
|
}
|
|
@@ -498,7 +526,7 @@ async function stopRecording(sessionId) {
|
|
|
498
526
|
if (!session) {
|
|
499
527
|
return { success: false, error: `Recording session not found: ${sessionId}` };
|
|
500
528
|
}
|
|
501
|
-
return new Promise((
|
|
529
|
+
return new Promise((resolve2) => {
|
|
502
530
|
if (session.process.stdin) {
|
|
503
531
|
session.process.stdin.write("q");
|
|
504
532
|
session.process.stdin.end();
|
|
@@ -511,13 +539,13 @@ async function stopRecording(sessionId) {
|
|
|
511
539
|
activeRecordings.delete(sessionId);
|
|
512
540
|
const duration = (Date.now() - session.startTime.getTime()) / 1e3;
|
|
513
541
|
if (existsSync(session.outputPath)) {
|
|
514
|
-
|
|
542
|
+
resolve2({
|
|
515
543
|
success: true,
|
|
516
544
|
filePath: session.outputPath,
|
|
517
545
|
duration
|
|
518
546
|
});
|
|
519
547
|
} else {
|
|
520
|
-
|
|
548
|
+
resolve2({ success: false, error: "Recording file not found" });
|
|
521
549
|
}
|
|
522
550
|
});
|
|
523
551
|
});
|
|
@@ -646,7 +674,7 @@ async function captureIOSSimulatorScreenshot(options) {
|
|
|
646
674
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
647
675
|
const filename = `ios-screenshot-${timestamp}.png`;
|
|
648
676
|
const outputPath = join2(projectDir, filename);
|
|
649
|
-
return new Promise((
|
|
677
|
+
return new Promise((resolve2) => {
|
|
650
678
|
const args = ["simctl", "io", options.deviceId, "screenshot", outputPath];
|
|
651
679
|
const proc = spawn2("xcrun", args);
|
|
652
680
|
let stderr = "";
|
|
@@ -655,13 +683,13 @@ async function captureIOSSimulatorScreenshot(options) {
|
|
|
655
683
|
});
|
|
656
684
|
proc.on("close", (code) => {
|
|
657
685
|
if (code === 0 && existsSync2(outputPath)) {
|
|
658
|
-
|
|
686
|
+
resolve2({ success: true, filePath: outputPath });
|
|
659
687
|
} else {
|
|
660
|
-
|
|
688
|
+
resolve2({ success: false, error: stderr || `xcrun simctl failed with code ${code}` });
|
|
661
689
|
}
|
|
662
690
|
});
|
|
663
691
|
proc.on("error", (err) => {
|
|
664
|
-
|
|
692
|
+
resolve2({ success: false, error: err.message });
|
|
665
693
|
});
|
|
666
694
|
});
|
|
667
695
|
}
|
|
@@ -693,7 +721,7 @@ async function stopIOSSimulatorRecording(sessionId) {
|
|
|
693
721
|
if (!session) {
|
|
694
722
|
return { success: false, error: `Recording session not found: ${sessionId}` };
|
|
695
723
|
}
|
|
696
|
-
return new Promise((
|
|
724
|
+
return new Promise((resolve2) => {
|
|
697
725
|
session.process.kill("SIGINT");
|
|
698
726
|
const timeout = setTimeout(() => {
|
|
699
727
|
session.process.kill("SIGKILL");
|
|
@@ -702,9 +730,9 @@ async function stopIOSSimulatorRecording(sessionId) {
|
|
|
702
730
|
clearTimeout(timeout);
|
|
703
731
|
iosRecordingSessions.delete(sessionId);
|
|
704
732
|
if (existsSync2(session.outputPath)) {
|
|
705
|
-
|
|
733
|
+
resolve2({ success: true, filePath: session.outputPath });
|
|
706
734
|
} else {
|
|
707
|
-
|
|
735
|
+
resolve2({ success: false, error: "Recording file not found" });
|
|
708
736
|
}
|
|
709
737
|
});
|
|
710
738
|
});
|
|
@@ -762,35 +790,35 @@ async function captureAndroidEmulatorScreenshot(options) {
|
|
|
762
790
|
const filename = `android-screenshot-${timestamp}.png`;
|
|
763
791
|
const outputPath = join2(projectDir, filename);
|
|
764
792
|
const tempPath = "/sdcard/screenshot.png";
|
|
765
|
-
return new Promise((
|
|
793
|
+
return new Promise((resolve2) => {
|
|
766
794
|
let adbCommand;
|
|
767
795
|
try {
|
|
768
796
|
adbCommand = getAdbCommandOrThrow();
|
|
769
797
|
} catch (error) {
|
|
770
|
-
|
|
798
|
+
resolve2({ success: false, error: error instanceof Error ? error.message : String(error) });
|
|
771
799
|
return;
|
|
772
800
|
}
|
|
773
801
|
const captureProc = spawn2(adbCommand, ["-s", options.deviceId, "shell", "screencap", "-p", tempPath]);
|
|
774
802
|
captureProc.on("close", (captureCode) => {
|
|
775
803
|
if (captureCode !== 0) {
|
|
776
|
-
|
|
804
|
+
resolve2({ success: false, error: `screencap failed with code ${captureCode}` });
|
|
777
805
|
return;
|
|
778
806
|
}
|
|
779
807
|
const pullProc = spawn2(adbCommand, ["-s", options.deviceId, "pull", tempPath, outputPath]);
|
|
780
808
|
pullProc.on("close", (pullCode) => {
|
|
781
809
|
spawn2(adbCommand, ["-s", options.deviceId, "shell", "rm", tempPath]);
|
|
782
810
|
if (pullCode === 0 && existsSync2(outputPath)) {
|
|
783
|
-
|
|
811
|
+
resolve2({ success: true, filePath: outputPath });
|
|
784
812
|
} else {
|
|
785
|
-
|
|
813
|
+
resolve2({ success: false, error: `adb pull failed with code ${pullCode}` });
|
|
786
814
|
}
|
|
787
815
|
});
|
|
788
816
|
pullProc.on("error", (err) => {
|
|
789
|
-
|
|
817
|
+
resolve2({ success: false, error: err.message });
|
|
790
818
|
});
|
|
791
819
|
});
|
|
792
820
|
captureProc.on("error", (err) => {
|
|
793
|
-
|
|
821
|
+
resolve2({ success: false, error: err.message });
|
|
794
822
|
});
|
|
795
823
|
});
|
|
796
824
|
}
|
|
@@ -831,7 +859,7 @@ async function stopAndroidEmulatorRecording(sessionId) {
|
|
|
831
859
|
if (!session) {
|
|
832
860
|
return { success: false, error: `Recording session not found: ${sessionId}` };
|
|
833
861
|
}
|
|
834
|
-
return new Promise((
|
|
862
|
+
return new Promise((resolve2) => {
|
|
835
863
|
session.process.kill("SIGINT");
|
|
836
864
|
setTimeout(() => {
|
|
837
865
|
const pullProc = spawn2(session.adbCommand, ["-s", session.deviceId, "pull", session.tempPath, session.outputPath]);
|
|
@@ -839,14 +867,14 @@ async function stopAndroidEmulatorRecording(sessionId) {
|
|
|
839
867
|
spawn2(session.adbCommand, ["-s", session.deviceId, "shell", "rm", session.tempPath]);
|
|
840
868
|
androidRecordingSessions.delete(sessionId);
|
|
841
869
|
if (pullCode === 0 && existsSync2(session.outputPath)) {
|
|
842
|
-
|
|
870
|
+
resolve2({ success: true, filePath: session.outputPath });
|
|
843
871
|
} else {
|
|
844
|
-
|
|
872
|
+
resolve2({ success: false, error: "Failed to pull recording file" });
|
|
845
873
|
}
|
|
846
874
|
});
|
|
847
875
|
pullProc.on("error", (err) => {
|
|
848
876
|
androidRecordingSessions.delete(sessionId);
|
|
849
|
-
|
|
877
|
+
resolve2({ success: false, error: err.message });
|
|
850
878
|
});
|
|
851
879
|
}, 1e3);
|
|
852
880
|
});
|
|
@@ -1228,7 +1256,7 @@ async function extractFrames(options) {
|
|
|
1228
1256
|
return { success: false, error: "Failed to read video information" };
|
|
1229
1257
|
}
|
|
1230
1258
|
const args = buildFFmpegArgs(options, framesDir, videoInfo, outputFormat);
|
|
1231
|
-
return new Promise((
|
|
1259
|
+
return new Promise((resolve2) => {
|
|
1232
1260
|
const proc = spawn3("ffmpeg", args);
|
|
1233
1261
|
let stderr = "";
|
|
1234
1262
|
proc.stderr.on("data", (data) => {
|
|
@@ -1236,11 +1264,11 @@ async function extractFrames(options) {
|
|
|
1236
1264
|
});
|
|
1237
1265
|
proc.on("close", (code) => {
|
|
1238
1266
|
if (code !== 0) {
|
|
1239
|
-
|
|
1267
|
+
resolve2({ success: false, error: `FFmpeg failed: ${stderr.slice(-500)}` });
|
|
1240
1268
|
return;
|
|
1241
1269
|
}
|
|
1242
1270
|
const frames2 = listExtractedFrames(framesDir, videoInfo.fps, options.fps || 1);
|
|
1243
|
-
|
|
1271
|
+
resolve2({
|
|
1244
1272
|
success: true,
|
|
1245
1273
|
framesDir,
|
|
1246
1274
|
frameCount: frames2.length,
|
|
@@ -1248,7 +1276,7 @@ async function extractFrames(options) {
|
|
|
1248
1276
|
});
|
|
1249
1277
|
});
|
|
1250
1278
|
proc.on("error", (err) => {
|
|
1251
|
-
|
|
1279
|
+
resolve2({ success: false, error: err.message });
|
|
1252
1280
|
});
|
|
1253
1281
|
});
|
|
1254
1282
|
}
|
|
@@ -2990,7 +3018,7 @@ function buildOverlayFilter(overlay) {
|
|
|
2990
3018
|
return null;
|
|
2991
3019
|
}
|
|
2992
3020
|
async function runFFmpegWithProgress(args, onProgress) {
|
|
2993
|
-
return new Promise((
|
|
3021
|
+
return new Promise((resolve2, reject) => {
|
|
2994
3022
|
const ffmpeg = spawn4("ffmpeg", args, { stdio: ["pipe", "pipe", "pipe"] });
|
|
2995
3023
|
ffmpeg.stderr?.on("data", (data) => {
|
|
2996
3024
|
const output = data.toString();
|
|
@@ -3012,7 +3040,7 @@ async function runFFmpegWithProgress(args, onProgress) {
|
|
|
3012
3040
|
});
|
|
3013
3041
|
ffmpeg.on("close", (code) => {
|
|
3014
3042
|
if (code === 0) {
|
|
3015
|
-
|
|
3043
|
+
resolve2();
|
|
3016
3044
|
} else {
|
|
3017
3045
|
reject(new Error(`FFmpeg exited with code ${code}`));
|
|
3018
3046
|
}
|
|
@@ -6345,6 +6373,1025 @@ var taskHubTools = [
|
|
|
6345
6373
|
taskHubTestMapToggleTool
|
|
6346
6374
|
];
|
|
6347
6375
|
|
|
6376
|
+
// src/mcp/tools/esvp.ts
|
|
6377
|
+
import { readFile } from "fs/promises";
|
|
6378
|
+
import { join as join13, resolve } from "path";
|
|
6379
|
+
import { z as z10 } from "zod";
|
|
6380
|
+
var jsonObjectSchema = z10.record(z10.string(), z10.any());
|
|
6381
|
+
var actionSchema = z10.object({
|
|
6382
|
+
name: z10.string().min(1).describe("ESVP action name"),
|
|
6383
|
+
args: jsonObjectSchema.optional().describe("Action arguments"),
|
|
6384
|
+
checkpointAfter: z10.boolean().optional(),
|
|
6385
|
+
checkpointLabel: z10.string().optional()
|
|
6386
|
+
});
|
|
6387
|
+
var crashClipSchema = z10.object({
|
|
6388
|
+
enabled: z10.boolean().optional(),
|
|
6389
|
+
pre_seconds: z10.number().optional(),
|
|
6390
|
+
post_seconds: z10.number().optional(),
|
|
6391
|
+
chunk_seconds: z10.number().optional()
|
|
6392
|
+
});
|
|
6393
|
+
var proxySchema = z10.object({
|
|
6394
|
+
host: z10.string(),
|
|
6395
|
+
port: z10.number(),
|
|
6396
|
+
protocol: z10.string().optional(),
|
|
6397
|
+
bypass: z10.array(z10.string()).optional()
|
|
6398
|
+
});
|
|
6399
|
+
var projectRecordingSchema = z10.object({
|
|
6400
|
+
recordingId: z10.string().min(1).describe("Mobile recording / project ID inside ~/.discoverylab/projects/maestro-recordings")
|
|
6401
|
+
});
|
|
6402
|
+
var projectValidationProfileIdSchema = z10.enum([
|
|
6403
|
+
"standard",
|
|
6404
|
+
"app-http-trace",
|
|
6405
|
+
"mitm-simulator",
|
|
6406
|
+
"inject-503",
|
|
6407
|
+
"timeout",
|
|
6408
|
+
"delay-1200"
|
|
6409
|
+
]);
|
|
6410
|
+
var projectValidationNetworkSchema = z10.object({
|
|
6411
|
+
enabled: z10.boolean().optional(),
|
|
6412
|
+
mode: z10.enum(["managed-proxy", "external-proxy", "external-mitm", "app-http-trace"]).optional(),
|
|
6413
|
+
profile: z10.string().optional(),
|
|
6414
|
+
label: z10.string().optional(),
|
|
6415
|
+
connectivity: z10.enum(["online", "offline", "reset"]).optional(),
|
|
6416
|
+
proxy: jsonObjectSchema.optional(),
|
|
6417
|
+
capture: jsonObjectSchema.optional(),
|
|
6418
|
+
faults: jsonObjectSchema.optional()
|
|
6419
|
+
}).nullable();
|
|
6420
|
+
function getMobileRecordingDir(recordingId) {
|
|
6421
|
+
return join13(PROJECTS_DIR, "maestro-recordings", recordingId);
|
|
6422
|
+
}
|
|
6423
|
+
function getMobileRecordingSessionPath(recordingId) {
|
|
6424
|
+
return join13(getMobileRecordingDir(recordingId), "session.json");
|
|
6425
|
+
}
|
|
6426
|
+
async function readMobileRecordingSession(recordingId) {
|
|
6427
|
+
const sessionPath = getMobileRecordingSessionPath(recordingId);
|
|
6428
|
+
const raw = await readFile(sessionPath, "utf8").catch(() => null);
|
|
6429
|
+
if (!raw) {
|
|
6430
|
+
throw new Error(`Recording not found: ${recordingId}`);
|
|
6431
|
+
}
|
|
6432
|
+
return JSON.parse(raw);
|
|
6433
|
+
}
|
|
6434
|
+
function resolveProjectRecordingESVPState(session) {
|
|
6435
|
+
return session?.esvp && typeof session.esvp === "object" ? session.esvp : null;
|
|
6436
|
+
}
|
|
6437
|
+
function resolveProjectRecordingESVPSourceSessionId(session) {
|
|
6438
|
+
const esvp = resolveProjectRecordingESVPState(session);
|
|
6439
|
+
if (!esvp) return null;
|
|
6440
|
+
const validation = esvp.validation && typeof esvp.validation === "object" ? esvp.validation : null;
|
|
6441
|
+
const network = esvp.network && typeof esvp.network === "object" ? esvp.network : null;
|
|
6442
|
+
const validationId = typeof validation?.sourceSessionId === "string" ? validation.sourceSessionId.trim() : "";
|
|
6443
|
+
const networkId = typeof network?.sourceSessionId === "string" ? network.sourceSessionId.trim() : "";
|
|
6444
|
+
const directId = typeof esvp.currentSessionId === "string" ? esvp.currentSessionId.trim() : "";
|
|
6445
|
+
return validationId || networkId || directId || null;
|
|
6446
|
+
}
|
|
6447
|
+
function resolveProjectRecordingReplaySessionId(session) {
|
|
6448
|
+
const esvp = resolveProjectRecordingESVPState(session);
|
|
6449
|
+
const validation = esvp?.validation && typeof esvp.validation === "object" ? esvp.validation : null;
|
|
6450
|
+
const replayId = typeof validation?.replaySessionId === "string" ? validation.replaySessionId.trim() : "";
|
|
6451
|
+
return replayId || null;
|
|
6452
|
+
}
|
|
6453
|
+
function resolveProjectRecordingESVPServerUrl(session) {
|
|
6454
|
+
const esvp = resolveProjectRecordingESVPState(session);
|
|
6455
|
+
if (!esvp || typeof esvp.serverUrl !== "string") return void 0;
|
|
6456
|
+
const serverUrl = esvp.serverUrl.trim();
|
|
6457
|
+
return serverUrl || void 0;
|
|
6458
|
+
}
|
|
6459
|
+
function resolveAppLabBaseUrl(appLabUrl) {
|
|
6460
|
+
const raw = String(appLabUrl || process.env.DISCOVERYLAB_APP_URL || "http://127.0.0.1:3847").trim();
|
|
6461
|
+
return raw.replace(/\/+$/, "");
|
|
6462
|
+
}
|
|
6463
|
+
async function callAppLabJson(path10, init = {}, appLabUrl) {
|
|
6464
|
+
const baseUrl = resolveAppLabBaseUrl(appLabUrl);
|
|
6465
|
+
const targetUrl = `${baseUrl}${path10.startsWith("/") ? path10 : `/${path10}`}`;
|
|
6466
|
+
const response = await fetch(targetUrl, init).catch((error) => {
|
|
6467
|
+
throw new Error(`Failed to reach App Lab at ${baseUrl}. Start the local App Lab server before using project-scoped ESVP tools. ${error instanceof Error ? error.message : String(error)}`);
|
|
6468
|
+
});
|
|
6469
|
+
const text = await response.text();
|
|
6470
|
+
let payload = null;
|
|
6471
|
+
if (text.trim()) {
|
|
6472
|
+
try {
|
|
6473
|
+
payload = JSON.parse(text);
|
|
6474
|
+
} catch {
|
|
6475
|
+
payload = { raw: text };
|
|
6476
|
+
}
|
|
6477
|
+
}
|
|
6478
|
+
if (!response.ok) {
|
|
6479
|
+
const message = payload?.error || payload?.message || `App Lab request failed (${response.status} ${response.statusText})`;
|
|
6480
|
+
throw new Error(String(message));
|
|
6481
|
+
}
|
|
6482
|
+
return {
|
|
6483
|
+
appLabUrl: baseUrl,
|
|
6484
|
+
payload
|
|
6485
|
+
};
|
|
6486
|
+
}
|
|
6487
|
+
function buildProjectValidationNetwork(profileId, network) {
|
|
6488
|
+
if (network) return network;
|
|
6489
|
+
switch (profileId) {
|
|
6490
|
+
case "app-http-trace":
|
|
6491
|
+
return {
|
|
6492
|
+
enabled: true,
|
|
6493
|
+
profile: "applab-app-http-trace",
|
|
6494
|
+
label: "App Lab App HTTP Trace",
|
|
6495
|
+
mode: "app-http-trace"
|
|
6496
|
+
};
|
|
6497
|
+
case "mitm-simulator":
|
|
6498
|
+
return {
|
|
6499
|
+
enabled: true,
|
|
6500
|
+
profile: "applab-mitm-beta",
|
|
6501
|
+
label: "App Lab MITM Beta",
|
|
6502
|
+
mode: "external-mitm"
|
|
6503
|
+
};
|
|
6504
|
+
case "inject-503":
|
|
6505
|
+
return {
|
|
6506
|
+
enabled: true,
|
|
6507
|
+
profile: "applab-inject-503",
|
|
6508
|
+
label: "App Lab Inject 503",
|
|
6509
|
+
mode: "managed-proxy",
|
|
6510
|
+
faults: {
|
|
6511
|
+
status_code: 503,
|
|
6512
|
+
body_patch: {
|
|
6513
|
+
error: "Injected by ESVP"
|
|
6514
|
+
}
|
|
6515
|
+
}
|
|
6516
|
+
};
|
|
6517
|
+
case "timeout":
|
|
6518
|
+
return {
|
|
6519
|
+
enabled: true,
|
|
6520
|
+
profile: "applab-timeout",
|
|
6521
|
+
label: "App Lab Timeout",
|
|
6522
|
+
mode: "managed-proxy",
|
|
6523
|
+
faults: {
|
|
6524
|
+
timeout: true
|
|
6525
|
+
}
|
|
6526
|
+
};
|
|
6527
|
+
case "delay-1200":
|
|
6528
|
+
return {
|
|
6529
|
+
enabled: true,
|
|
6530
|
+
profile: "applab-delay-1200",
|
|
6531
|
+
label: "App Lab Delay 1200ms",
|
|
6532
|
+
mode: "managed-proxy",
|
|
6533
|
+
faults: {
|
|
6534
|
+
delay_ms: 1200
|
|
6535
|
+
}
|
|
6536
|
+
};
|
|
6537
|
+
case "standard":
|
|
6538
|
+
default:
|
|
6539
|
+
return {
|
|
6540
|
+
enabled: true,
|
|
6541
|
+
profile: "applab-standard",
|
|
6542
|
+
label: "App Lab Standard Capture",
|
|
6543
|
+
mode: "external-proxy"
|
|
6544
|
+
};
|
|
6545
|
+
}
|
|
6546
|
+
}
|
|
6547
|
+
function resolveDefaultDeviceId(executor) {
|
|
6548
|
+
if (executor === "fake") return void 0;
|
|
6549
|
+
const wantedPlatform = executor === "ios-sim" || executor === "maestro-ios" ? "ios" : "android";
|
|
6550
|
+
const booted = listAllEmulators().find(
|
|
6551
|
+
(device) => device.platform === wantedPlatform && device.state === "booted"
|
|
6552
|
+
);
|
|
6553
|
+
return booted?.id;
|
|
6554
|
+
}
|
|
6555
|
+
function executorToPlatform(executor) {
|
|
6556
|
+
if (executor === "ios-sim" || executor === "maestro-ios") return "ios";
|
|
6557
|
+
if (executor === "adb") return "android";
|
|
6558
|
+
return void 0;
|
|
6559
|
+
}
|
|
6560
|
+
async function makeBaseResult(serverUrl) {
|
|
6561
|
+
const connection = await getESVPConnection(serverUrl);
|
|
6562
|
+
return {
|
|
6563
|
+
serverUrl: connection.serverUrl,
|
|
6564
|
+
connectionMode: connection.mode
|
|
6565
|
+
};
|
|
6566
|
+
}
|
|
6567
|
+
function normalizeActions(actions) {
|
|
6568
|
+
return actions.map((action) => ({
|
|
6569
|
+
name: action.name,
|
|
6570
|
+
...action.args ? { args: action.args } : {},
|
|
6571
|
+
...action.checkpointAfter !== void 0 ? { checkpointAfter: action.checkpointAfter } : {},
|
|
6572
|
+
...action.checkpointLabel ? { checkpointLabel: action.checkpointLabel } : {}
|
|
6573
|
+
}));
|
|
6574
|
+
}
|
|
6575
|
+
async function resolveTracePayload(params) {
|
|
6576
|
+
if (params.payload !== void 0) return params.payload;
|
|
6577
|
+
if (!params.traceFilePath) {
|
|
6578
|
+
throw new Error("payload ou traceFilePath \xE9 obrigat\xF3rio");
|
|
6579
|
+
}
|
|
6580
|
+
const absPath = params.traceFilePath.startsWith("/") ? params.traceFilePath : resolve(process.cwd(), params.traceFilePath);
|
|
6581
|
+
const raw = await readFile(absPath, "utf8");
|
|
6582
|
+
try {
|
|
6583
|
+
return JSON.parse(raw);
|
|
6584
|
+
} catch {
|
|
6585
|
+
return raw;
|
|
6586
|
+
}
|
|
6587
|
+
}
|
|
6588
|
+
var esvpStatusTool = {
|
|
6589
|
+
name: "dlab.esvp.status",
|
|
6590
|
+
description: "Check if an ESVP control-plane is reachable and return its health payload.",
|
|
6591
|
+
inputSchema: z10.object({
|
|
6592
|
+
serverUrl: z10.string().url().optional().describe("ESVP control-plane base URL")
|
|
6593
|
+
}),
|
|
6594
|
+
handler: async (params) => {
|
|
6595
|
+
try {
|
|
6596
|
+
const health = await getESVPHealth(params.serverUrl);
|
|
6597
|
+
return createJsonResult({
|
|
6598
|
+
...await makeBaseResult(params.serverUrl),
|
|
6599
|
+
health
|
|
6600
|
+
});
|
|
6601
|
+
} catch (error) {
|
|
6602
|
+
return createErrorResult(error instanceof Error ? error.message : String(error));
|
|
6603
|
+
}
|
|
6604
|
+
}
|
|
6605
|
+
};
|
|
6606
|
+
var esvpDevicesTool = {
|
|
6607
|
+
name: "dlab.esvp.devices",
|
|
6608
|
+
description: "List ESVP-visible ADB devices and/or iOS Simulators from the public control-plane.",
|
|
6609
|
+
inputSchema: z10.object({
|
|
6610
|
+
serverUrl: z10.string().url().optional().describe("ESVP control-plane base URL"),
|
|
6611
|
+
platform: z10.enum(["adb", "ios-sim", "maestro-ios", "all"]).optional().describe("Which device family to query")
|
|
6612
|
+
}),
|
|
6613
|
+
handler: async (params) => {
|
|
6614
|
+
try {
|
|
6615
|
+
const devices3 = await listESVPDevices(params.platform || "all", params.serverUrl);
|
|
6616
|
+
return createJsonResult({
|
|
6617
|
+
...await makeBaseResult(params.serverUrl),
|
|
6618
|
+
devices: devices3
|
|
6619
|
+
});
|
|
6620
|
+
} catch (error) {
|
|
6621
|
+
return createErrorResult(error instanceof Error ? error.message : String(error));
|
|
6622
|
+
}
|
|
6623
|
+
}
|
|
6624
|
+
};
|
|
6625
|
+
var esvpSessionsListTool = {
|
|
6626
|
+
name: "dlab.esvp.sessions.list",
|
|
6627
|
+
description: "List public ESVP sessions from the configured server.",
|
|
6628
|
+
inputSchema: z10.object({
|
|
6629
|
+
serverUrl: z10.string().url().optional().describe("ESVP control-plane base URL")
|
|
6630
|
+
}),
|
|
6631
|
+
handler: async (params) => {
|
|
6632
|
+
try {
|
|
6633
|
+
const sessions = await listESVPSessions(params.serverUrl);
|
|
6634
|
+
return createJsonResult({
|
|
6635
|
+
...await makeBaseResult(params.serverUrl),
|
|
6636
|
+
...sessions
|
|
6637
|
+
});
|
|
6638
|
+
} catch (error) {
|
|
6639
|
+
return createErrorResult(error instanceof Error ? error.message : String(error));
|
|
6640
|
+
}
|
|
6641
|
+
}
|
|
6642
|
+
};
|
|
6643
|
+
var esvpSessionCreateTool = {
|
|
6644
|
+
name: "dlab.esvp.session.create",
|
|
6645
|
+
description: "Create an ESVP session using the public contract. Auto-selects a booted emulator/simulator when possible. Use withNetwork to auto-configure the default App Lab external-proxy profile.",
|
|
6646
|
+
inputSchema: z10.object({
|
|
6647
|
+
serverUrl: z10.string().url().optional().describe("ESVP control-plane base URL"),
|
|
6648
|
+
executor: z10.enum(["fake", "adb", "ios-sim", "maestro-ios"]).describe("Public ESVP executor"),
|
|
6649
|
+
deviceId: z10.string().optional().describe("Device ID. Optional for fake and for booted local emulators/simulators"),
|
|
6650
|
+
meta: jsonObjectSchema.optional().describe("Session metadata"),
|
|
6651
|
+
crashClip: crashClipSchema.optional().describe("Optional crash clip config"),
|
|
6652
|
+
withNetwork: z10.boolean().optional().describe("Auto-configure the default App Lab external-proxy profile after creating the session")
|
|
6653
|
+
}),
|
|
6654
|
+
handler: async (params) => {
|
|
6655
|
+
try {
|
|
6656
|
+
const resolvedDeviceId = params.deviceId || resolveDefaultDeviceId(params.executor);
|
|
6657
|
+
const response = await createESVPSession(
|
|
6658
|
+
{
|
|
6659
|
+
executor: params.executor,
|
|
6660
|
+
...resolvedDeviceId ? { deviceId: resolvedDeviceId } : {},
|
|
6661
|
+
meta: {
|
|
6662
|
+
source: "applab-discovery",
|
|
6663
|
+
...params.meta || {}
|
|
6664
|
+
},
|
|
6665
|
+
...params.crashClip ? {
|
|
6666
|
+
crash_clip: params.crashClip
|
|
6667
|
+
} : {}
|
|
6668
|
+
},
|
|
6669
|
+
params.serverUrl
|
|
6670
|
+
);
|
|
6671
|
+
let networkConfigured = null;
|
|
6672
|
+
if (params.withNetwork) {
|
|
6673
|
+
const sessionId = String(response?.session?.id || response?.id || "");
|
|
6674
|
+
if (sessionId) {
|
|
6675
|
+
networkConfigured = await configureESVPNetwork(
|
|
6676
|
+
sessionId,
|
|
6677
|
+
buildAppLabNetworkProfile(
|
|
6678
|
+
{
|
|
6679
|
+
enabled: true,
|
|
6680
|
+
mode: "external-proxy",
|
|
6681
|
+
profile: "applab-standard-capture",
|
|
6682
|
+
label: "App Lab Standard Capture"
|
|
6683
|
+
},
|
|
6684
|
+
{
|
|
6685
|
+
platform: executorToPlatform(params.executor),
|
|
6686
|
+
deviceId: resolvedDeviceId
|
|
6687
|
+
}
|
|
6688
|
+
) || {},
|
|
6689
|
+
params.serverUrl
|
|
6690
|
+
).catch((err) => ({ error: err instanceof Error ? err.message : String(err) }));
|
|
6691
|
+
}
|
|
6692
|
+
}
|
|
6693
|
+
return createJsonResult({
|
|
6694
|
+
...await makeBaseResult(params.serverUrl),
|
|
6695
|
+
autoSelectedDeviceId: resolvedDeviceId || null,
|
|
6696
|
+
...response,
|
|
6697
|
+
...networkConfigured ? { networkConfigured } : {}
|
|
6698
|
+
});
|
|
6699
|
+
} catch (error) {
|
|
6700
|
+
return createErrorResult(error instanceof Error ? error.message : String(error));
|
|
6701
|
+
}
|
|
6702
|
+
}
|
|
6703
|
+
};
|
|
6704
|
+
var esvpSessionInspectTool = {
|
|
6705
|
+
name: "dlab.esvp.session.inspect",
|
|
6706
|
+
description: "Inspect an ESVP session and optionally include transcript and artifacts.",
|
|
6707
|
+
inputSchema: z10.object({
|
|
6708
|
+
serverUrl: z10.string().url().optional().describe("ESVP control-plane base URL"),
|
|
6709
|
+
sessionId: z10.string().describe("ESVP session ID"),
|
|
6710
|
+
includeTranscript: z10.boolean().optional(),
|
|
6711
|
+
includeArtifacts: z10.boolean().optional()
|
|
6712
|
+
}),
|
|
6713
|
+
handler: async (params) => {
|
|
6714
|
+
try {
|
|
6715
|
+
const inspection = await inspectESVPSession(
|
|
6716
|
+
params.sessionId,
|
|
6717
|
+
{
|
|
6718
|
+
includeTranscript: params.includeTranscript === true,
|
|
6719
|
+
includeArtifacts: params.includeArtifacts === true
|
|
6720
|
+
},
|
|
6721
|
+
params.serverUrl
|
|
6722
|
+
);
|
|
6723
|
+
return createJsonResult({
|
|
6724
|
+
...await makeBaseResult(params.serverUrl),
|
|
6725
|
+
...inspection
|
|
6726
|
+
});
|
|
6727
|
+
} catch (error) {
|
|
6728
|
+
return createErrorResult(error instanceof Error ? error.message : String(error));
|
|
6729
|
+
}
|
|
6730
|
+
}
|
|
6731
|
+
};
|
|
6732
|
+
var esvpSessionTranscriptTool = {
|
|
6733
|
+
name: "dlab.esvp.session.transcript",
|
|
6734
|
+
description: "Fetch the canonical public transcript for an ESVP session.",
|
|
6735
|
+
inputSchema: z10.object({
|
|
6736
|
+
serverUrl: z10.string().url().optional().describe("ESVP control-plane base URL"),
|
|
6737
|
+
sessionId: z10.string().describe("ESVP session ID")
|
|
6738
|
+
}),
|
|
6739
|
+
handler: async (params) => {
|
|
6740
|
+
try {
|
|
6741
|
+
const transcript = await getESVPTranscript(params.sessionId, params.serverUrl);
|
|
6742
|
+
return createJsonResult({
|
|
6743
|
+
...await makeBaseResult(params.serverUrl),
|
|
6744
|
+
sessionId: params.sessionId,
|
|
6745
|
+
transcript: transcript?.events || []
|
|
6746
|
+
});
|
|
6747
|
+
} catch (error) {
|
|
6748
|
+
return createErrorResult(error instanceof Error ? error.message : String(error));
|
|
6749
|
+
}
|
|
6750
|
+
}
|
|
6751
|
+
};
|
|
6752
|
+
var esvpSessionArtifactsListTool = {
|
|
6753
|
+
name: "dlab.esvp.session.artifacts.list",
|
|
6754
|
+
description: "List public artifacts for an ESVP session.",
|
|
6755
|
+
inputSchema: z10.object({
|
|
6756
|
+
serverUrl: z10.string().url().optional().describe("ESVP control-plane base URL"),
|
|
6757
|
+
sessionId: z10.string().describe("ESVP session ID")
|
|
6758
|
+
}),
|
|
6759
|
+
handler: async (params) => {
|
|
6760
|
+
try {
|
|
6761
|
+
const result = await listESVPArtifacts(params.sessionId, params.serverUrl);
|
|
6762
|
+
return createJsonResult({
|
|
6763
|
+
...await makeBaseResult(params.serverUrl),
|
|
6764
|
+
sessionId: params.sessionId,
|
|
6765
|
+
artifacts: result?.artifacts || []
|
|
6766
|
+
});
|
|
6767
|
+
} catch (error) {
|
|
6768
|
+
return createErrorResult(error instanceof Error ? error.message : String(error));
|
|
6769
|
+
}
|
|
6770
|
+
}
|
|
6771
|
+
};
|
|
6772
|
+
var esvpSessionArtifactGetTool = {
|
|
6773
|
+
name: "dlab.esvp.session.artifact.get",
|
|
6774
|
+
description: "Fetch the contents of a public ESVP artifact.",
|
|
6775
|
+
inputSchema: z10.object({
|
|
6776
|
+
serverUrl: z10.string().url().optional().describe("ESVP control-plane base URL"),
|
|
6777
|
+
sessionId: z10.string().describe("ESVP session ID"),
|
|
6778
|
+
artifactPath: z10.string().describe("Artifact relative path returned by artifacts.list")
|
|
6779
|
+
}),
|
|
6780
|
+
handler: async (params) => {
|
|
6781
|
+
try {
|
|
6782
|
+
const content = await getESVPArtifactContent(params.sessionId, params.artifactPath, params.serverUrl);
|
|
6783
|
+
return createJsonResult({
|
|
6784
|
+
...await makeBaseResult(params.serverUrl),
|
|
6785
|
+
sessionId: params.sessionId,
|
|
6786
|
+
artifactPath: params.artifactPath,
|
|
6787
|
+
content
|
|
6788
|
+
});
|
|
6789
|
+
} catch (error) {
|
|
6790
|
+
return createErrorResult(error instanceof Error ? error.message : String(error));
|
|
6791
|
+
}
|
|
6792
|
+
}
|
|
6793
|
+
};
|
|
6794
|
+
var esvpSessionActionsTool = {
|
|
6795
|
+
name: "dlab.esvp.session.actions",
|
|
6796
|
+
description: "Run public ESVP actions in an existing session. Use withNetwork to auto-configure the default App Lab external-proxy profile if not already active.",
|
|
6797
|
+
inputSchema: z10.object({
|
|
6798
|
+
serverUrl: z10.string().url().optional().describe("ESVP control-plane base URL"),
|
|
6799
|
+
sessionId: z10.string().describe("ESVP session ID"),
|
|
6800
|
+
actions: z10.array(actionSchema).min(1).describe("Public ESVP actions"),
|
|
6801
|
+
finish: z10.boolean().optional().describe("Finish the session after running the actions"),
|
|
6802
|
+
captureLogcat: z10.boolean().optional().describe("Capture logcat on finish when supported"),
|
|
6803
|
+
checkpointAfterEach: z10.boolean().optional().describe("Enable checkpointAfter for every action"),
|
|
6804
|
+
withNetwork: z10.boolean().optional().describe("Auto-configure the default App Lab external-proxy profile before running actions if not already configured")
|
|
6805
|
+
}),
|
|
6806
|
+
handler: async (params) => {
|
|
6807
|
+
try {
|
|
6808
|
+
let networkConfigured = null;
|
|
6809
|
+
if (params.withNetwork) {
|
|
6810
|
+
const networkState = await getESVPSessionNetwork(params.sessionId, params.serverUrl).catch(() => null);
|
|
6811
|
+
const hasActiveProfile = networkState?.network?.active_profile || networkState?.network?.effective_profile;
|
|
6812
|
+
if (!hasActiveProfile) {
|
|
6813
|
+
networkConfigured = await configureESVPNetwork(
|
|
6814
|
+
params.sessionId,
|
|
6815
|
+
buildAppLabNetworkProfile(
|
|
6816
|
+
{
|
|
6817
|
+
enabled: true,
|
|
6818
|
+
mode: "external-proxy",
|
|
6819
|
+
profile: "applab-standard-capture",
|
|
6820
|
+
label: "App Lab Standard Capture"
|
|
6821
|
+
},
|
|
6822
|
+
{
|
|
6823
|
+
platform: executorToPlatform(typeof networkState?.session?.executor === "string" ? networkState.session.executor : void 0),
|
|
6824
|
+
deviceId: typeof networkState?.session?.device_id === "string" ? networkState.session.device_id : void 0
|
|
6825
|
+
}
|
|
6826
|
+
) || {},
|
|
6827
|
+
params.serverUrl
|
|
6828
|
+
).catch((err) => ({ error: err instanceof Error ? err.message : String(err) }));
|
|
6829
|
+
}
|
|
6830
|
+
}
|
|
6831
|
+
const result = await runESVPActions(
|
|
6832
|
+
params.sessionId,
|
|
6833
|
+
{
|
|
6834
|
+
actions: normalizeActions(params.actions),
|
|
6835
|
+
finish: params.finish === true,
|
|
6836
|
+
captureLogcat: params.captureLogcat,
|
|
6837
|
+
checkpointAfterEach: params.checkpointAfterEach
|
|
6838
|
+
},
|
|
6839
|
+
params.serverUrl
|
|
6840
|
+
);
|
|
6841
|
+
return createJsonResult({
|
|
6842
|
+
...await makeBaseResult(params.serverUrl),
|
|
6843
|
+
...networkConfigured ? { networkConfigured } : {},
|
|
6844
|
+
...result
|
|
6845
|
+
});
|
|
6846
|
+
} catch (error) {
|
|
6847
|
+
return createErrorResult(error instanceof Error ? error.message : String(error));
|
|
6848
|
+
}
|
|
6849
|
+
}
|
|
6850
|
+
};
|
|
6851
|
+
var esvpSessionCheckpointTool = {
|
|
6852
|
+
name: "dlab.esvp.session.checkpoint",
|
|
6853
|
+
description: "Capture a public ESVP checkpoint for an existing session.",
|
|
6854
|
+
inputSchema: z10.object({
|
|
6855
|
+
serverUrl: z10.string().url().optional().describe("ESVP control-plane base URL"),
|
|
6856
|
+
sessionId: z10.string().describe("ESVP session ID"),
|
|
6857
|
+
label: z10.string().optional().describe("Optional checkpoint label")
|
|
6858
|
+
}),
|
|
6859
|
+
handler: async (params) => {
|
|
6860
|
+
try {
|
|
6861
|
+
const result = await captureESVPCheckpoint(
|
|
6862
|
+
params.sessionId,
|
|
6863
|
+
{
|
|
6864
|
+
...params.label ? { label: params.label } : {}
|
|
6865
|
+
},
|
|
6866
|
+
params.serverUrl
|
|
6867
|
+
);
|
|
6868
|
+
return createJsonResult({
|
|
6869
|
+
...await makeBaseResult(params.serverUrl),
|
|
6870
|
+
...result
|
|
6871
|
+
});
|
|
6872
|
+
} catch (error) {
|
|
6873
|
+
return createErrorResult(error instanceof Error ? error.message : String(error));
|
|
6874
|
+
}
|
|
6875
|
+
}
|
|
6876
|
+
};
|
|
6877
|
+
var esvpSessionFinishTool = {
|
|
6878
|
+
name: "dlab.esvp.session.finish",
|
|
6879
|
+
description: "Finish an ESVP session.",
|
|
6880
|
+
inputSchema: z10.object({
|
|
6881
|
+
serverUrl: z10.string().url().optional().describe("ESVP control-plane base URL"),
|
|
6882
|
+
sessionId: z10.string().describe("ESVP session ID"),
|
|
6883
|
+
captureLogcat: z10.boolean().optional().describe("Capture logcat on finish when supported")
|
|
6884
|
+
}),
|
|
6885
|
+
handler: async (params) => {
|
|
6886
|
+
try {
|
|
6887
|
+
const result = await finishESVPSession(
|
|
6888
|
+
params.sessionId,
|
|
6889
|
+
{
|
|
6890
|
+
captureLogcat: params.captureLogcat
|
|
6891
|
+
},
|
|
6892
|
+
params.serverUrl
|
|
6893
|
+
);
|
|
6894
|
+
return createJsonResult({
|
|
6895
|
+
...await makeBaseResult(params.serverUrl),
|
|
6896
|
+
...result
|
|
6897
|
+
});
|
|
6898
|
+
} catch (error) {
|
|
6899
|
+
return createErrorResult(error instanceof Error ? error.message : String(error));
|
|
6900
|
+
}
|
|
6901
|
+
}
|
|
6902
|
+
};
|
|
6903
|
+
var esvpReplayRunTool = {
|
|
6904
|
+
name: "dlab.esvp.replay.run",
|
|
6905
|
+
description: "Replay an ESVP session to a new session using the public replay endpoint.",
|
|
6906
|
+
inputSchema: z10.object({
|
|
6907
|
+
serverUrl: z10.string().url().optional().describe("ESVP control-plane base URL"),
|
|
6908
|
+
sessionId: z10.string().describe("Base ESVP session ID"),
|
|
6909
|
+
executor: z10.enum(["fake", "adb", "ios-sim", "maestro-ios"]).optional().describe("Replay executor"),
|
|
6910
|
+
deviceId: z10.string().optional().describe("Replay device ID"),
|
|
6911
|
+
captureLogcat: z10.boolean().optional(),
|
|
6912
|
+
meta: jsonObjectSchema.optional()
|
|
6913
|
+
}),
|
|
6914
|
+
handler: async (params) => {
|
|
6915
|
+
try {
|
|
6916
|
+
const result = await replayESVPSession(
|
|
6917
|
+
params.sessionId,
|
|
6918
|
+
{
|
|
6919
|
+
executor: params.executor,
|
|
6920
|
+
deviceId: params.deviceId,
|
|
6921
|
+
captureLogcat: params.captureLogcat,
|
|
6922
|
+
meta: {
|
|
6923
|
+
source: "applab-discovery",
|
|
6924
|
+
...params.meta || {}
|
|
6925
|
+
}
|
|
6926
|
+
},
|
|
6927
|
+
params.serverUrl
|
|
6928
|
+
);
|
|
6929
|
+
const consistency = result?.replay_session?.id ? await getESVPReplayConsistency(result.replay_session.id, params.serverUrl).catch(() => null) : null;
|
|
6930
|
+
return createJsonResult({
|
|
6931
|
+
...await makeBaseResult(params.serverUrl),
|
|
6932
|
+
...result,
|
|
6933
|
+
replayConsistency: consistency?.replay_consistency || null
|
|
6934
|
+
});
|
|
6935
|
+
} catch (error) {
|
|
6936
|
+
return createErrorResult(error instanceof Error ? error.message : String(error));
|
|
6937
|
+
}
|
|
6938
|
+
}
|
|
6939
|
+
};
|
|
6940
|
+
var esvpNetworkConfigureTool = {
|
|
6941
|
+
name: "dlab.esvp.network.configure",
|
|
6942
|
+
description: "Configure an ESVP network profile through the public network contract.",
|
|
6943
|
+
inputSchema: z10.object({
|
|
6944
|
+
serverUrl: z10.string().url().optional().describe("ESVP control-plane base URL"),
|
|
6945
|
+
sessionId: z10.string().describe("ESVP session ID"),
|
|
6946
|
+
profile: z10.string().optional(),
|
|
6947
|
+
label: z10.string().optional(),
|
|
6948
|
+
connectivity: z10.enum(["online", "offline", "reset"]).optional(),
|
|
6949
|
+
proxy: proxySchema.optional(),
|
|
6950
|
+
faults: jsonObjectSchema.optional(),
|
|
6951
|
+
capture: jsonObjectSchema.optional(),
|
|
6952
|
+
clear: z10.boolean().optional().describe("Clear the active network profile instead of applying one")
|
|
6953
|
+
}),
|
|
6954
|
+
handler: async (params) => {
|
|
6955
|
+
try {
|
|
6956
|
+
if (params.clear === true) {
|
|
6957
|
+
const cleared = await clearESVPNetwork(params.sessionId, params.serverUrl);
|
|
6958
|
+
return createJsonResult({
|
|
6959
|
+
...await makeBaseResult(params.serverUrl),
|
|
6960
|
+
...cleared
|
|
6961
|
+
});
|
|
6962
|
+
}
|
|
6963
|
+
const result = await configureESVPNetwork(
|
|
6964
|
+
params.sessionId,
|
|
6965
|
+
{
|
|
6966
|
+
...params.profile ? { profile: params.profile } : {},
|
|
6967
|
+
...params.label ? { label: params.label } : {},
|
|
6968
|
+
...params.connectivity ? { connectivity: params.connectivity } : {},
|
|
6969
|
+
...params.proxy ? { proxy: params.proxy } : {},
|
|
6970
|
+
...params.faults ? { faults: params.faults } : {},
|
|
6971
|
+
...params.capture ? { capture: params.capture } : {}
|
|
6972
|
+
},
|
|
6973
|
+
params.serverUrl
|
|
6974
|
+
);
|
|
6975
|
+
return createJsonResult({
|
|
6976
|
+
...await makeBaseResult(params.serverUrl),
|
|
6977
|
+
...result
|
|
6978
|
+
});
|
|
6979
|
+
} catch (error) {
|
|
6980
|
+
return createErrorResult(error instanceof Error ? error.message : String(error));
|
|
6981
|
+
}
|
|
6982
|
+
}
|
|
6983
|
+
};
|
|
6984
|
+
var esvpSessionNetworkTool = {
|
|
6985
|
+
name: "dlab.esvp.session.network",
|
|
6986
|
+
description: "Read the public network state for an ESVP session.",
|
|
6987
|
+
inputSchema: z10.object({
|
|
6988
|
+
serverUrl: z10.string().url().optional().describe("ESVP control-plane base URL"),
|
|
6989
|
+
sessionId: z10.string().describe("ESVP session ID")
|
|
6990
|
+
}),
|
|
6991
|
+
handler: async (params) => {
|
|
6992
|
+
try {
|
|
6993
|
+
const result = await getESVPSessionNetwork(params.sessionId, params.serverUrl);
|
|
6994
|
+
return createJsonResult({
|
|
6995
|
+
...await makeBaseResult(params.serverUrl),
|
|
6996
|
+
...result
|
|
6997
|
+
});
|
|
6998
|
+
} catch (error) {
|
|
6999
|
+
return createErrorResult(error instanceof Error ? error.message : String(error));
|
|
7000
|
+
}
|
|
7001
|
+
}
|
|
7002
|
+
};
|
|
7003
|
+
var esvpNetworkTraceAttachTool = {
|
|
7004
|
+
name: "dlab.esvp.network.trace.attach",
|
|
7005
|
+
description: "Attach a network trace artifact to an ESVP session using the public contract.",
|
|
7006
|
+
inputSchema: z10.object({
|
|
7007
|
+
serverUrl: z10.string().url().optional().describe("ESVP control-plane base URL"),
|
|
7008
|
+
sessionId: z10.string().describe("ESVP session ID"),
|
|
7009
|
+
traceKind: z10.string().describe("Trace kind, e.g. http_trace or har"),
|
|
7010
|
+
label: z10.string().optional(),
|
|
7011
|
+
source: z10.string().optional(),
|
|
7012
|
+
requestId: z10.string().optional(),
|
|
7013
|
+
method: z10.string().optional(),
|
|
7014
|
+
url: z10.string().optional(),
|
|
7015
|
+
statusCode: z10.number().optional(),
|
|
7016
|
+
format: z10.string().optional(),
|
|
7017
|
+
payload: z10.any().optional().describe("Trace payload object/string"),
|
|
7018
|
+
traceFilePath: z10.string().optional().describe("Optional local file path to JSON/text trace payload")
|
|
7019
|
+
}),
|
|
7020
|
+
handler: async (params) => {
|
|
7021
|
+
try {
|
|
7022
|
+
const payload = await resolveTracePayload({
|
|
7023
|
+
payload: params.payload,
|
|
7024
|
+
traceFilePath: params.traceFilePath
|
|
7025
|
+
});
|
|
7026
|
+
const result = await attachESVPNetworkTrace(
|
|
7027
|
+
params.sessionId,
|
|
7028
|
+
{
|
|
7029
|
+
trace_kind: params.traceKind,
|
|
7030
|
+
...params.label ? { label: params.label } : {},
|
|
7031
|
+
...params.source ? { source: params.source } : {},
|
|
7032
|
+
...params.requestId ? { request_id: params.requestId } : {},
|
|
7033
|
+
...params.method ? { method: params.method } : {},
|
|
7034
|
+
...params.url ? { url: params.url } : {},
|
|
7035
|
+
...params.statusCode !== void 0 ? { status_code: params.statusCode } : {},
|
|
7036
|
+
...params.format ? { format: params.format } : {},
|
|
7037
|
+
payload
|
|
7038
|
+
},
|
|
7039
|
+
params.serverUrl
|
|
7040
|
+
);
|
|
7041
|
+
return createJsonResult({
|
|
7042
|
+
...await makeBaseResult(params.serverUrl),
|
|
7043
|
+
...result
|
|
7044
|
+
});
|
|
7045
|
+
} catch (error) {
|
|
7046
|
+
return createErrorResult(error instanceof Error ? error.message : String(error));
|
|
7047
|
+
}
|
|
7048
|
+
}
|
|
7049
|
+
};
|
|
7050
|
+
var esvpSessionGetTool = {
|
|
7051
|
+
name: "dlab.esvp.session.get",
|
|
7052
|
+
description: "Get the latest public summary for an ESVP session.",
|
|
7053
|
+
inputSchema: z10.object({
|
|
7054
|
+
serverUrl: z10.string().url().optional().describe("ESVP control-plane base URL"),
|
|
7055
|
+
sessionId: z10.string().describe("ESVP session ID")
|
|
7056
|
+
}),
|
|
7057
|
+
handler: async (params) => {
|
|
7058
|
+
try {
|
|
7059
|
+
const result = await getESVPSession(params.sessionId, params.serverUrl);
|
|
7060
|
+
return createJsonResult({
|
|
7061
|
+
...await makeBaseResult(params.serverUrl),
|
|
7062
|
+
...result
|
|
7063
|
+
});
|
|
7064
|
+
} catch (error) {
|
|
7065
|
+
return createErrorResult(error instanceof Error ? error.message : String(error));
|
|
7066
|
+
}
|
|
7067
|
+
}
|
|
7068
|
+
};
|
|
7069
|
+
var esvpReplayValidateTool = {
|
|
7070
|
+
name: "dlab.esvp.replay.validate",
|
|
7071
|
+
description: "Validate whether an ESVP session supports canonical replay and inspect the result.",
|
|
7072
|
+
inputSchema: z10.object({
|
|
7073
|
+
serverUrl: z10.string().url().optional().describe("ESVP control-plane base URL"),
|
|
7074
|
+
sessionId: z10.string().describe("ESVP session ID")
|
|
7075
|
+
}),
|
|
7076
|
+
handler: async (params) => {
|
|
7077
|
+
try {
|
|
7078
|
+
const result = await validateESVPReplay(params.sessionId, params.serverUrl);
|
|
7079
|
+
return createJsonResult({
|
|
7080
|
+
...await makeBaseResult(params.serverUrl),
|
|
7081
|
+
...result
|
|
7082
|
+
});
|
|
7083
|
+
} catch (error) {
|
|
7084
|
+
return createErrorResult(error instanceof Error ? error.message : String(error));
|
|
7085
|
+
}
|
|
7086
|
+
}
|
|
7087
|
+
};
|
|
7088
|
+
var preflightRuleSchema = z10.object({
|
|
7089
|
+
kind: z10.enum(["permission", "dismiss_dialog", "wait_for_stable", "clear_data", "set_setting"]).describe("Preflight rule kind"),
|
|
7090
|
+
permission: z10.string().optional().describe("Android permission (for kind=permission)"),
|
|
7091
|
+
action: z10.enum(["grant", "revoke"]).optional().describe("Permission action (for kind=permission)"),
|
|
7092
|
+
selector: z10.string().optional().describe("Selector to find and dismiss (for kind=dismiss_dialog)"),
|
|
7093
|
+
timeout_ms: z10.number().optional().describe("Timeout in ms (for kind=wait_for_stable/dismiss_dialog)"),
|
|
7094
|
+
poll_ms: z10.number().optional().describe("Poll interval in ms (for kind=wait_for_stable)"),
|
|
7095
|
+
namespace: z10.string().optional().describe("Settings namespace: system|secure|global (for kind=set_setting)"),
|
|
7096
|
+
key: z10.string().optional().describe("Setting key (for kind=set_setting)"),
|
|
7097
|
+
value: z10.string().optional().describe("Setting value (for kind=set_setting)")
|
|
7098
|
+
});
|
|
7099
|
+
var esvpSessionPreflightTool = {
|
|
7100
|
+
name: "dlab.esvp.session.preflight",
|
|
7101
|
+
description: "Run preflight/bootstrap rules on an ESVP session before executing actions. Supports permission grants, dialog dismissal, wait for stable UI, clear data, and system settings.",
|
|
7102
|
+
inputSchema: z10.object({
|
|
7103
|
+
serverUrl: z10.string().url().optional().describe("ESVP control-plane base URL"),
|
|
7104
|
+
sessionId: z10.string().describe("ESVP session ID"),
|
|
7105
|
+
policy: z10.string().optional().describe("Preflight policy name (e.g. fresh_install)"),
|
|
7106
|
+
appId: z10.string().optional().describe("Target app ID (e.g. com.example.app)"),
|
|
7107
|
+
rules: z10.array(preflightRuleSchema).optional().describe("Preflight rules to execute")
|
|
7108
|
+
}),
|
|
7109
|
+
handler: async (params) => {
|
|
7110
|
+
try {
|
|
7111
|
+
const config = {
|
|
7112
|
+
...params.policy ? { policy: params.policy } : {},
|
|
7113
|
+
...params.appId ? { appId: params.appId } : {},
|
|
7114
|
+
...params.rules ? { rules: params.rules } : {}
|
|
7115
|
+
};
|
|
7116
|
+
const result = await runESVPPreflight(params.sessionId, config, params.serverUrl);
|
|
7117
|
+
return createJsonResult({
|
|
7118
|
+
...await makeBaseResult(params.serverUrl),
|
|
7119
|
+
...result
|
|
7120
|
+
});
|
|
7121
|
+
} catch (error) {
|
|
7122
|
+
return createErrorResult(error instanceof Error ? error.message : String(error));
|
|
7123
|
+
}
|
|
7124
|
+
}
|
|
7125
|
+
};
|
|
7126
|
+
var projectESVPCurrentTool = {
|
|
7127
|
+
name: "dlab.project.esvp.current",
|
|
7128
|
+
description: "Read the current ESVP state stored for an App Lab mobile recording/project without requiring the web UI.",
|
|
7129
|
+
inputSchema: projectRecordingSchema,
|
|
7130
|
+
handler: async (params) => {
|
|
7131
|
+
try {
|
|
7132
|
+
const session = await readMobileRecordingSession(params.recordingId);
|
|
7133
|
+
const esvp = resolveProjectRecordingESVPState(session);
|
|
7134
|
+
const validation = esvp?.validation && typeof esvp.validation === "object" ? esvp.validation : null;
|
|
7135
|
+
const network = esvp?.network && typeof esvp.network === "object" ? esvp.network : null;
|
|
7136
|
+
return createJsonResult({
|
|
7137
|
+
recordingId: params.recordingId,
|
|
7138
|
+
recordingDir: getMobileRecordingDir(params.recordingId),
|
|
7139
|
+
sessionPath: getMobileRecordingSessionPath(params.recordingId),
|
|
7140
|
+
recording: {
|
|
7141
|
+
id: String(session.id || params.recordingId),
|
|
7142
|
+
name: String(session.name || `Recording ${params.recordingId}`),
|
|
7143
|
+
platform: session.platform === "ios" ? "ios" : "android",
|
|
7144
|
+
deviceId: typeof session.deviceId === "string" ? session.deviceId : null,
|
|
7145
|
+
deviceName: typeof session.deviceName === "string" ? session.deviceName : null,
|
|
7146
|
+
appId: typeof session.appId === "string" ? session.appId : null,
|
|
7147
|
+
actionsCount: Array.isArray(session.actions) ? session.actions.length : 0
|
|
7148
|
+
},
|
|
7149
|
+
esvp: {
|
|
7150
|
+
serverUrl: resolveProjectRecordingESVPServerUrl(session) || null,
|
|
7151
|
+
connectionMode: typeof esvp?.connectionMode === "string" ? esvp.connectionMode : null,
|
|
7152
|
+
executor: typeof esvp?.executor === "string" ? esvp.executor : null,
|
|
7153
|
+
currentSessionId: typeof esvp?.currentSessionId === "string" ? esvp.currentSessionId : null,
|
|
7154
|
+
sourceSessionId: resolveProjectRecordingESVPSourceSessionId(session),
|
|
7155
|
+
replaySessionId: resolveProjectRecordingReplaySessionId(session),
|
|
7156
|
+
validationSupported: validation?.supported === false ? false : validation ? true : null,
|
|
7157
|
+
validatedAt: typeof validation?.validatedAt === "string" ? validation.validatedAt : null,
|
|
7158
|
+
replayedAt: typeof validation?.replayedAt === "string" ? validation.replayedAt : null,
|
|
7159
|
+
replayConsistency: validation?.replayConsistency || null,
|
|
7160
|
+
checkpointComparison: validation?.checkpointComparison || null,
|
|
7161
|
+
network: {
|
|
7162
|
+
entryCount: Number.isFinite(Number(network?.entryCount)) ? Number(network?.entryCount) : 0,
|
|
7163
|
+
traceCount: Number.isFinite(Number(network?.traceCount)) ? Number(network?.traceCount) : 0,
|
|
7164
|
+
traceKinds: Array.isArray(network?.traceKinds) ? network.traceKinds : [],
|
|
7165
|
+
captureStatus: typeof network?.captureStatus === "string" ? network.captureStatus : null,
|
|
7166
|
+
networkSupported: typeof network?.networkSupported === "boolean" ? network.networkSupported : null,
|
|
7167
|
+
activeProfile: network?.activeProfile || null,
|
|
7168
|
+
effectiveProfile: network?.effectiveProfile || null,
|
|
7169
|
+
captureProxy: network?.captureProxy || null,
|
|
7170
|
+
appTraceCollector: network?.appTraceCollector || null,
|
|
7171
|
+
managedProxy: network?.managedProxy || null,
|
|
7172
|
+
syncedAt: typeof network?.syncedAt === "string" ? network.syncedAt : null
|
|
7173
|
+
}
|
|
7174
|
+
}
|
|
7175
|
+
});
|
|
7176
|
+
} catch (error) {
|
|
7177
|
+
return createErrorResult(error instanceof Error ? error.message : String(error));
|
|
7178
|
+
}
|
|
7179
|
+
}
|
|
7180
|
+
};
|
|
7181
|
+
var projectESVPValidateTool = {
|
|
7182
|
+
name: "dlab.project.esvp.validate",
|
|
7183
|
+
description: "Run the App Lab ESVP validation flow for a mobile recording/project. Requires the local App Lab server to be running.",
|
|
7184
|
+
inputSchema: projectRecordingSchema.extend({
|
|
7185
|
+
appLabUrl: z10.string().url().optional().describe("App Lab server base URL, defaults to http://127.0.0.1:3847"),
|
|
7186
|
+
serverUrl: z10.string().url().optional().describe("Optional ESVP control-plane base URL"),
|
|
7187
|
+
replay: z10.boolean().optional().describe("Run replay after source validation"),
|
|
7188
|
+
captureLogcat: z10.boolean().optional(),
|
|
7189
|
+
profileId: projectValidationProfileIdSchema.optional().describe("Convenience network profile shortcut"),
|
|
7190
|
+
network: projectValidationNetworkSchema.optional().describe("Explicit network profile payload. Overrides profileId. Pass null to validate without network capture.")
|
|
7191
|
+
}),
|
|
7192
|
+
handler: async (params) => {
|
|
7193
|
+
try {
|
|
7194
|
+
const network = params.network === null ? null : buildProjectValidationNetwork(params.profileId, params.network);
|
|
7195
|
+
const result = await callAppLabJson(
|
|
7196
|
+
`/api/testing/mobile/recordings/${encodeURIComponent(params.recordingId)}/esvp/validate`,
|
|
7197
|
+
{
|
|
7198
|
+
method: "POST",
|
|
7199
|
+
headers: { "content-type": "application/json" },
|
|
7200
|
+
body: JSON.stringify({
|
|
7201
|
+
...params.serverUrl ? { serverUrl: params.serverUrl } : {},
|
|
7202
|
+
...params.captureLogcat !== void 0 ? { captureLogcat: params.captureLogcat } : {},
|
|
7203
|
+
...params.replay !== void 0 ? { replay: params.replay } : {},
|
|
7204
|
+
...network ? { network } : {}
|
|
7205
|
+
})
|
|
7206
|
+
},
|
|
7207
|
+
params.appLabUrl
|
|
7208
|
+
);
|
|
7209
|
+
return createJsonResult({
|
|
7210
|
+
appLabUrl: result.appLabUrl,
|
|
7211
|
+
recordingId: params.recordingId,
|
|
7212
|
+
result: result.payload
|
|
7213
|
+
});
|
|
7214
|
+
} catch (error) {
|
|
7215
|
+
return createErrorResult(error instanceof Error ? error.message : String(error));
|
|
7216
|
+
}
|
|
7217
|
+
}
|
|
7218
|
+
};
|
|
7219
|
+
var projectESVPReplayTool = {
|
|
7220
|
+
name: "dlab.project.esvp.replay",
|
|
7221
|
+
description: "Replay the canonical ESVP source session already attached to a mobile recording/project. Requires the local App Lab server to be running.",
|
|
7222
|
+
inputSchema: projectRecordingSchema.extend({
|
|
7223
|
+
appLabUrl: z10.string().url().optional().describe("App Lab server base URL, defaults to http://127.0.0.1:3847"),
|
|
7224
|
+
serverUrl: z10.string().url().optional().describe("Optional ESVP control-plane base URL"),
|
|
7225
|
+
captureLogcat: z10.boolean().optional()
|
|
7226
|
+
}),
|
|
7227
|
+
handler: async (params) => {
|
|
7228
|
+
try {
|
|
7229
|
+
const result = await callAppLabJson(
|
|
7230
|
+
`/api/testing/mobile/recordings/${encodeURIComponent(params.recordingId)}/esvp/replay`,
|
|
7231
|
+
{
|
|
7232
|
+
method: "POST",
|
|
7233
|
+
headers: { "content-type": "application/json" },
|
|
7234
|
+
body: JSON.stringify({
|
|
7235
|
+
...params.serverUrl ? { serverUrl: params.serverUrl } : {},
|
|
7236
|
+
...params.captureLogcat !== void 0 ? { captureLogcat: params.captureLogcat } : {}
|
|
7237
|
+
})
|
|
7238
|
+
},
|
|
7239
|
+
params.appLabUrl
|
|
7240
|
+
);
|
|
7241
|
+
return createJsonResult({
|
|
7242
|
+
appLabUrl: result.appLabUrl,
|
|
7243
|
+
recordingId: params.recordingId,
|
|
7244
|
+
result: result.payload
|
|
7245
|
+
});
|
|
7246
|
+
} catch (error) {
|
|
7247
|
+
return createErrorResult(error instanceof Error ? error.message : String(error));
|
|
7248
|
+
}
|
|
7249
|
+
}
|
|
7250
|
+
};
|
|
7251
|
+
var projectESVPSyncNetworkTool = {
|
|
7252
|
+
name: "dlab.project.esvp.sync_network",
|
|
7253
|
+
description: "Sync the latest attached ESVP network trace into an App Lab mobile recording/project. Requires the local App Lab server to be running.",
|
|
7254
|
+
inputSchema: projectRecordingSchema.extend({
|
|
7255
|
+
appLabUrl: z10.string().url().optional().describe("App Lab server base URL, defaults to http://127.0.0.1:3847"),
|
|
7256
|
+
serverUrl: z10.string().url().optional().describe("Optional ESVP control-plane base URL"),
|
|
7257
|
+
sessionId: z10.string().optional().describe("Optional ESVP session ID override")
|
|
7258
|
+
}),
|
|
7259
|
+
handler: async (params) => {
|
|
7260
|
+
try {
|
|
7261
|
+
const result = await callAppLabJson(
|
|
7262
|
+
`/api/testing/mobile/recordings/${encodeURIComponent(params.recordingId)}/esvp/sync-network`,
|
|
7263
|
+
{
|
|
7264
|
+
method: "POST",
|
|
7265
|
+
headers: { "content-type": "application/json" },
|
|
7266
|
+
body: JSON.stringify({
|
|
7267
|
+
...params.serverUrl ? { serverUrl: params.serverUrl } : {},
|
|
7268
|
+
...params.sessionId ? { sessionId: params.sessionId } : {}
|
|
7269
|
+
})
|
|
7270
|
+
},
|
|
7271
|
+
params.appLabUrl
|
|
7272
|
+
);
|
|
7273
|
+
return createJsonResult({
|
|
7274
|
+
appLabUrl: result.appLabUrl,
|
|
7275
|
+
recordingId: params.recordingId,
|
|
7276
|
+
result: result.payload
|
|
7277
|
+
});
|
|
7278
|
+
} catch (error) {
|
|
7279
|
+
return createErrorResult(error instanceof Error ? error.message : String(error));
|
|
7280
|
+
}
|
|
7281
|
+
}
|
|
7282
|
+
};
|
|
7283
|
+
var projectESVPAppTraceBootstrapTool = {
|
|
7284
|
+
name: "dlab.project.esvp.app_trace_bootstrap",
|
|
7285
|
+
description: "Fetch the active local app_http_trace bootstrap config for an App Lab mobile recording/project. Requires the local App Lab server to be running when a collector is active.",
|
|
7286
|
+
inputSchema: projectRecordingSchema.extend({
|
|
7287
|
+
appLabUrl: z10.string().url().optional().describe("App Lab server base URL, defaults to http://127.0.0.1:3847"),
|
|
7288
|
+
appId: z10.string().optional().describe("Optional app ID override when multiple collectors are active")
|
|
7289
|
+
}),
|
|
7290
|
+
handler: async (params) => {
|
|
7291
|
+
try {
|
|
7292
|
+
const session = await readMobileRecordingSession(params.recordingId);
|
|
7293
|
+
const collector = session?.esvp?.network?.appTraceCollector || null;
|
|
7294
|
+
const searchParams = new URLSearchParams();
|
|
7295
|
+
if (params.recordingId) searchParams.set("recordingId", params.recordingId);
|
|
7296
|
+
if (params.appId) searchParams.set("appId", params.appId);
|
|
7297
|
+
const path10 = `/api/testing/mobile/app-http-trace/bootstrap?${searchParams.toString()}`;
|
|
7298
|
+
try {
|
|
7299
|
+
const result = await callAppLabJson(path10, { method: "GET" }, params.appLabUrl);
|
|
7300
|
+
return createJsonResult({
|
|
7301
|
+
appLabUrl: result.appLabUrl,
|
|
7302
|
+
recordingId: params.recordingId,
|
|
7303
|
+
result: result.payload
|
|
7304
|
+
});
|
|
7305
|
+
} catch (error) {
|
|
7306
|
+
return createJsonResult({
|
|
7307
|
+
appLabUrl: resolveAppLabBaseUrl(params.appLabUrl),
|
|
7308
|
+
recordingId: params.recordingId,
|
|
7309
|
+
activeCollector: collector,
|
|
7310
|
+
bootstrap: null,
|
|
7311
|
+
warning: error instanceof Error ? error.message : String(error)
|
|
7312
|
+
});
|
|
7313
|
+
}
|
|
7314
|
+
} catch (error) {
|
|
7315
|
+
return createErrorResult(error instanceof Error ? error.message : String(error));
|
|
7316
|
+
}
|
|
7317
|
+
}
|
|
7318
|
+
};
|
|
7319
|
+
var esvpTools = [
|
|
7320
|
+
esvpStatusTool,
|
|
7321
|
+
esvpDevicesTool,
|
|
7322
|
+
esvpSessionsListTool,
|
|
7323
|
+
esvpSessionCreateTool,
|
|
7324
|
+
esvpSessionGetTool,
|
|
7325
|
+
esvpSessionInspectTool,
|
|
7326
|
+
esvpSessionTranscriptTool,
|
|
7327
|
+
esvpSessionArtifactsListTool,
|
|
7328
|
+
esvpSessionArtifactGetTool,
|
|
7329
|
+
esvpSessionActionsTool,
|
|
7330
|
+
esvpSessionCheckpointTool,
|
|
7331
|
+
esvpSessionFinishTool,
|
|
7332
|
+
esvpSessionPreflightTool,
|
|
7333
|
+
esvpReplayRunTool,
|
|
7334
|
+
esvpReplayValidateTool,
|
|
7335
|
+
esvpSessionNetworkTool,
|
|
7336
|
+
esvpNetworkConfigureTool,
|
|
7337
|
+
esvpNetworkTraceAttachTool,
|
|
7338
|
+
projectESVPCurrentTool,
|
|
7339
|
+
projectESVPValidateTool,
|
|
7340
|
+
projectESVPReplayTool,
|
|
7341
|
+
projectESVPSyncNetworkTool,
|
|
7342
|
+
projectESVPAppTraceBootstrapTool
|
|
7343
|
+
];
|
|
7344
|
+
|
|
7345
|
+
// src/mcp/tools/templates.ts
|
|
7346
|
+
import { z as z11 } from "zod";
|
|
7347
|
+
var templateListTool = {
|
|
7348
|
+
name: "dlab.template.list",
|
|
7349
|
+
description: "List available Remotion video templates. Returns installed templates with their metadata, or indicates templates are not installed.",
|
|
7350
|
+
inputSchema: z11.object({}),
|
|
7351
|
+
handler: async () => {
|
|
7352
|
+
const installed = isTemplatesInstalled();
|
|
7353
|
+
if (!installed) {
|
|
7354
|
+
return createJsonResult({
|
|
7355
|
+
installed: false,
|
|
7356
|
+
templates: [],
|
|
7357
|
+
message: "Templates not installed. Install discoverylab-templates to ~/.discoverylab/templates/"
|
|
7358
|
+
});
|
|
7359
|
+
}
|
|
7360
|
+
const templates = getAvailableTemplates();
|
|
7361
|
+
return createJsonResult({
|
|
7362
|
+
installed: true,
|
|
7363
|
+
templates: templates.map((t) => ({
|
|
7364
|
+
id: t.id,
|
|
7365
|
+
name: t.name,
|
|
7366
|
+
description: t.description,
|
|
7367
|
+
resolution: `${t.width}x${t.height}`,
|
|
7368
|
+
fps: t.fps,
|
|
7369
|
+
durationFrames: t.durationFrames
|
|
7370
|
+
}))
|
|
7371
|
+
});
|
|
7372
|
+
}
|
|
7373
|
+
};
|
|
7374
|
+
var templateRenderTool = {
|
|
7375
|
+
name: "dlab.template.render",
|
|
7376
|
+
description: "Render a project video with a Remotion template. Starts an async render job and returns the job ID. Use the web UI to monitor progress.",
|
|
7377
|
+
inputSchema: z11.object({
|
|
7378
|
+
projectId: z11.string().describe("The project ID to render"),
|
|
7379
|
+
templateId: z11.enum(["studio", "showcase"]).describe('Template to use: "studio" (device + terminal) or "showcase" (floating device + artistic title + terminal)')
|
|
7380
|
+
}),
|
|
7381
|
+
handler: async ({ projectId, templateId }) => {
|
|
7382
|
+
if (!isTemplatesInstalled()) {
|
|
7383
|
+
return createErrorResult("Templates not installed. Install discoverylab-templates first.");
|
|
7384
|
+
}
|
|
7385
|
+
return createTextResult(
|
|
7386
|
+
`To render project "${projectId}" with template "${templateId}", use the web UI or call POST /api/templates/render with { projectId: "${projectId}", templateId: "${templateId}" }. The render runs asynchronously and progress is broadcast via WebSocket.`
|
|
7387
|
+
);
|
|
7388
|
+
}
|
|
7389
|
+
};
|
|
7390
|
+
var templateTools = [
|
|
7391
|
+
templateListTool,
|
|
7392
|
+
templateRenderTool
|
|
7393
|
+
];
|
|
7394
|
+
|
|
6348
7395
|
export {
|
|
6349
7396
|
uiOpenTool,
|
|
6350
7397
|
uiStatusTool,
|
|
@@ -6424,5 +7471,31 @@ export {
|
|
|
6424
7471
|
taskHubRequirementsGetTool,
|
|
6425
7472
|
taskHubTestMapGetTool,
|
|
6426
7473
|
taskHubTestMapToggleTool,
|
|
6427
|
-
taskHubTools
|
|
7474
|
+
taskHubTools,
|
|
7475
|
+
esvpStatusTool,
|
|
7476
|
+
esvpDevicesTool,
|
|
7477
|
+
esvpSessionsListTool,
|
|
7478
|
+
esvpSessionCreateTool,
|
|
7479
|
+
esvpSessionInspectTool,
|
|
7480
|
+
esvpSessionTranscriptTool,
|
|
7481
|
+
esvpSessionArtifactsListTool,
|
|
7482
|
+
esvpSessionArtifactGetTool,
|
|
7483
|
+
esvpSessionActionsTool,
|
|
7484
|
+
esvpSessionCheckpointTool,
|
|
7485
|
+
esvpSessionFinishTool,
|
|
7486
|
+
esvpReplayRunTool,
|
|
7487
|
+
esvpNetworkConfigureTool,
|
|
7488
|
+
esvpSessionNetworkTool,
|
|
7489
|
+
esvpNetworkTraceAttachTool,
|
|
7490
|
+
esvpSessionGetTool,
|
|
7491
|
+
esvpReplayValidateTool,
|
|
7492
|
+
projectESVPCurrentTool,
|
|
7493
|
+
projectESVPValidateTool,
|
|
7494
|
+
projectESVPReplayTool,
|
|
7495
|
+
projectESVPSyncNetworkTool,
|
|
7496
|
+
projectESVPAppTraceBootstrapTool,
|
|
7497
|
+
esvpTools,
|
|
7498
|
+
templateListTool,
|
|
7499
|
+
templateRenderTool,
|
|
7500
|
+
templateTools
|
|
6428
7501
|
};
|