@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.
Files changed (160) hide show
  1. package/.mcp.json +2 -2
  2. package/README.md +182 -0
  3. package/dist/{chunk-TAODYZ52.js → chunk-3QRQEDWR.js} +510 -213
  4. package/dist/{chunk-L4SA5F5W.js → chunk-4L76GPRC.js} +1162 -58
  5. package/dist/chunk-6EGBXRDK.js +30 -0
  6. package/dist/{chunk-I6YD3QFM.js → chunk-FIL7IWEL.js} +5 -3
  7. package/dist/{chunk-4KLG6DDE.js → chunk-FNUN7EPB.js} +6 -6
  8. package/dist/chunk-GAKEFJ5T.js +481 -0
  9. package/dist/chunk-LB3RNE3O.js +109 -0
  10. package/dist/chunk-N6JJ2RGV.js +2680 -0
  11. package/dist/{chunk-XUKWS2CE.js → chunk-VRM42PML.js} +3546 -926
  12. package/dist/{chunk-TJ3H23LL.js → chunk-VVIOB362.js} +3 -1
  13. package/dist/{chunk-W3WJGYR6.js → chunk-XFVDP332.js} +8 -2
  14. package/dist/{chunk-QJXXHOV7.js → chunk-XKX6NBHF.js} +5 -1
  15. package/dist/cli.js +405 -11
  16. package/dist/{db-ADBEBNH6.js → db-6WLEVKUV.js} +3 -1
  17. package/dist/esvp-GSISVXLC.js +52 -0
  18. package/dist/esvp-mobile-GC7MAGMI.js +20 -0
  19. package/dist/index.d.ts +123 -1
  20. package/dist/index.html +11689 -8690
  21. package/dist/index.js +67 -11
  22. package/dist/{ocr-UTWC7537.js → ocr-QDYNCSPE.js} +1 -1
  23. package/dist/{playwright-R7Y5HREH.js → playwright-VZ7PXDC5.js} +2 -2
  24. package/dist/runtime/esvp-host-runtime/darwin-arm64/esvp-host-runtime +0 -0
  25. package/dist/runtime/esvp-host-runtime/manifest.json +10 -0
  26. package/dist/{server-3FBHBA7L.js → server-6N3KIEGP.js} +2 -1
  27. package/dist/server-FO3UVUZU.js +22 -0
  28. package/dist/{setup-27CQAX6K.js → setup-2SQC5UHJ.js} +4 -3
  29. package/dist/{tools-L6PKKQPY.js → tools-OCRMOQ4U.js} +63 -8
  30. package/package.json +36 -5
  31. package/dist/chunk-22OCFYHG.js +0 -6283
  32. package/dist/chunk-24VARQVO.js +0 -7818
  33. package/dist/chunk-2OGZX6C4.js +0 -588
  34. package/dist/chunk-2WCNIFRO.js +0 -6191
  35. package/dist/chunk-43U6UYV7.js +0 -590
  36. package/dist/chunk-4H2E3K2G.js +0 -7638
  37. package/dist/chunk-4MS6YW2B.js +0 -6490
  38. package/dist/chunk-4NNTRJOI.js +0 -7791
  39. package/dist/chunk-5F76VWME.js +0 -6397
  40. package/dist/chunk-5NEFN42O.js +0 -7791
  41. package/dist/chunk-63MEQ6UH.js +0 -7673
  42. package/dist/chunk-6H3NXFX3.js +0 -6861
  43. package/dist/chunk-7IDQLLBW.js +0 -311
  44. package/dist/chunk-7NP64TGJ.js +0 -6822
  45. package/dist/chunk-AATLY4KT.js +0 -6505
  46. package/dist/chunk-C7QUR7XX.js +0 -6397
  47. package/dist/chunk-CGKCE6MC.js +0 -6279
  48. package/dist/chunk-D25V6IWE.js +0 -6487
  49. package/dist/chunk-EQOZSXAT.js +0 -6822
  50. package/dist/chunk-FPHD7HSQ.js +0 -6812
  51. package/dist/chunk-GGJJUCFK.js +0 -7160
  52. package/dist/chunk-GLHOY3NN.js +0 -7805
  53. package/dist/chunk-GML5MKQA.js +0 -6398
  54. package/dist/chunk-GOL6FUJL.js +0 -6045
  55. package/dist/chunk-GSWHWEYC.js +0 -1346
  56. package/dist/chunk-HDKEQOF5.js +0 -7788
  57. package/dist/chunk-HZGSWVVS.js +0 -7111
  58. package/dist/chunk-IGZ5TICZ.js +0 -334
  59. package/dist/chunk-IRKQG33A.js +0 -7054
  60. package/dist/chunk-JFTBF4JR.js +0 -6040
  61. package/dist/chunk-JVLVBPUJ.js +0 -6180
  62. package/dist/chunk-JY3KC67R.js +0 -6504
  63. package/dist/chunk-KUFBCBNJ.js +0 -6815
  64. package/dist/chunk-KV7KDJ43.js +0 -7639
  65. package/dist/chunk-L5IJZV5F.js +0 -6822
  66. package/dist/chunk-MFFPQLU4.js +0 -7102
  67. package/dist/chunk-MJS2YKNR.js +0 -6397
  68. package/dist/chunk-MN6LCZHZ.js +0 -1320
  69. package/dist/chunk-NBAUZ7X2.js +0 -1336
  70. package/dist/chunk-NDBW6ELQ.js +0 -7638
  71. package/dist/chunk-O2HBSDI2.js +0 -6175
  72. package/dist/chunk-OFFIUYMG.js +0 -6341
  73. package/dist/chunk-OVCQGF2J.js +0 -1321
  74. package/dist/chunk-P4S7ZY6G.js +0 -7638
  75. package/dist/chunk-PBHUHSC3.js +0 -6002
  76. package/dist/chunk-PC4LR4ZI.js +0 -6359
  77. package/dist/chunk-PMTGGZ7R.js +0 -6397
  78. package/dist/chunk-PTXSB3UV.js +0 -497
  79. package/dist/chunk-PYUCY3U6.js +0 -1340
  80. package/dist/chunk-RDZDSOAL.js +0 -7750
  81. package/dist/chunk-RLW2OI2L.js +0 -6383
  82. package/dist/chunk-RUGHHO4K.js +0 -6395
  83. package/dist/chunk-SIOQVM2E.js +0 -6819
  84. package/dist/chunk-SR67SRIT.js +0 -1336
  85. package/dist/chunk-SSRXIO2V.js +0 -6822
  86. package/dist/chunk-SWSEKFON.js +0 -6487
  87. package/dist/chunk-TBG76CYG.js +0 -6395
  88. package/dist/chunk-V3CBINLD.js +0 -6812
  89. package/dist/chunk-VPYSLEGM.js +0 -6710
  90. package/dist/chunk-VY3BLXBW.js +0 -329
  91. package/dist/chunk-WTFOGVJQ.js +0 -6365
  92. package/dist/chunk-X64SFUT5.js +0 -6099
  93. package/dist/chunk-XIBF5LBD.js +0 -6395
  94. package/dist/chunk-Y5VDMSYC.js +0 -6701
  95. package/dist/chunk-YUBL36H4.js +0 -6605
  96. package/dist/chunk-YWVXFVSW.js +0 -6456
  97. package/dist/chunk-ZXZACOLD.js +0 -6822
  98. package/dist/db-IWIL65EX.js +0 -33
  99. package/dist/gridCompositor-ENKLFPWR.js +0 -409
  100. package/dist/playwright-A3OGSDRG.js +0 -38
  101. package/dist/playwright-ATDC4NYW.js +0 -38
  102. package/dist/playwright-E6EUFIJG.js +0 -38
  103. package/dist/server-2DXLKLFM.js +0 -13
  104. package/dist/server-2ICEWJVK.js +0 -13
  105. package/dist/server-2MQV3FNY.js +0 -13
  106. package/dist/server-2NGD7GE3.js +0 -13
  107. package/dist/server-2VKO76UK.js +0 -14
  108. package/dist/server-3BK2VFU7.js +0 -13
  109. package/dist/server-4LDOB3NX.js +0 -13
  110. package/dist/server-4YI44KDR.js +0 -13
  111. package/dist/server-64XMXA5P.js +0 -13
  112. package/dist/server-6IPHVUYT.js +0 -14
  113. package/dist/server-73ORHMJN.js +0 -13
  114. package/dist/server-73P7M3QB.js +0 -14
  115. package/dist/server-BPVRW5LJ.js +0 -14
  116. package/dist/server-BW4RKZIX.js +0 -13
  117. package/dist/server-CFS5SM5K.js +0 -13
  118. package/dist/server-DX7VYHHM.js +0 -13
  119. package/dist/server-F3YPX6ET.js +0 -13
  120. package/dist/server-FUXTR33I.js +0 -13
  121. package/dist/server-G2SY3DOS.js +0 -13
  122. package/dist/server-G32U7VOQ.js +0 -13
  123. package/dist/server-IOOZK4NP.js +0 -14
  124. package/dist/server-J52LMTBT.js +0 -13
  125. package/dist/server-JG7UKFGK.js +0 -14
  126. package/dist/server-JSCHEBOD.js +0 -13
  127. package/dist/server-K6KC4ZOM.js +0 -13
  128. package/dist/server-KJVRGWFE.js +0 -13
  129. package/dist/server-LCPB2L4U.js +0 -13
  130. package/dist/server-M7LDYKAJ.js +0 -13
  131. package/dist/server-MKVK6ZQQ.js +0 -13
  132. package/dist/server-MU52LCXT.js +0 -13
  133. package/dist/server-NM5CKDUU.js +0 -13
  134. package/dist/server-NPZN3FWO.js +0 -14
  135. package/dist/server-O5FIAHSY.js +0 -14
  136. package/dist/server-OESJUEYC.js +0 -13
  137. package/dist/server-ONSKQO4W.js +0 -13
  138. package/dist/server-P27BZXBL.js +0 -14
  139. package/dist/server-Q4FBWQUA.js +0 -13
  140. package/dist/server-RNQ7VUAL.js +0 -13
  141. package/dist/server-S6B5WUBT.js +0 -14
  142. package/dist/server-SRYNSGSP.js +0 -14
  143. package/dist/server-SUN3W2YK.js +0 -13
  144. package/dist/server-UA62LHZB.js +0 -13
  145. package/dist/server-UJB44EW5.js +0 -13
  146. package/dist/server-X3TLP6DX.js +0 -14
  147. package/dist/server-YT2UGEZK.js +0 -13
  148. package/dist/server-ZBPQ33V6.js +0 -14
  149. package/dist/setup-AQX4JQVR.js +0 -17
  150. package/dist/setup-EQTU7FI6.js +0 -17
  151. package/dist/tools-2KPB37GK.js +0 -178
  152. package/dist/tools-3H6IOWXV.js +0 -178
  153. package/dist/tools-3KYHPDCJ.js +0 -178
  154. package/dist/tools-75BAPCUM.js +0 -177
  155. package/dist/tools-BUVCUCRL.js +0 -178
  156. package/dist/tools-HDNODRS6.js +0 -178
  157. package/dist/tools-HP5MNY3D.js +0 -177
  158. package/dist/tools-N5N2IO7V.js +0 -178
  159. package/dist/tools-NFJEZ2FF.js +0 -177
  160. package/dist/tools-TLCKABUW.js +0 -178
@@ -1,15 +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,
11
+ getAdbCommand,
12
+ getAvailableTemplates,
6
13
  getMaestroVersion,
7
14
  isMaestroInstalled,
15
+ isTemplatesInstalled,
8
16
  listMaestroDevices,
9
17
  runMaestroTest,
10
18
  runMaestroWithCapture,
11
19
  startMaestroStudio
12
- } from "./chunk-GSWHWEYC.js";
20
+ } from "./chunk-3QRQEDWR.js";
13
21
  import {
14
22
  createFormSubmissionScript,
15
23
  createLoginScript,
@@ -22,13 +30,33 @@ import {
22
30
  savePlaywrightScript,
23
31
  showPlaywrightReport,
24
32
  startPlaywrightCodegen
25
- } from "./chunk-43U6UYV7.js";
33
+ } from "./chunk-FIL7IWEL.js";
26
34
  import {
27
- analyzeText,
28
- getAvailableOCREngines,
29
- recognizeText,
30
- recognizeTextBatch
31
- } from "./chunk-W3WJGYR6.js";
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";
32
60
  import {
33
61
  DATA_DIR,
34
62
  EXPORTS_DIR,
@@ -39,12 +67,13 @@ import {
39
67
  projectExports,
40
68
  projects,
41
69
  testVariables
42
- } from "./chunk-TJ3H23LL.js";
70
+ } from "./chunk-VVIOB362.js";
43
71
  import {
44
- createErrorResult,
45
- createJsonResult,
46
- createTextResult
47
- } from "./chunk-QJXXHOV7.js";
72
+ analyzeText,
73
+ getAvailableOCREngines,
74
+ recognizeText,
75
+ recognizeTextBatch
76
+ } from "./chunk-XFVDP332.js";
48
77
 
49
78
  // src/mcp/tools/ui.ts
50
79
  import { z } from "zod";
@@ -337,17 +366,17 @@ async function captureMacScreenshot(outputPath, options) {
337
366
  args.push("-R", `${x},${y},${width},${height}`);
338
367
  }
339
368
  args.push(outputPath);
340
- return new Promise((resolve) => {
369
+ return new Promise((resolve2) => {
341
370
  const proc = spawn("screencapture", args);
342
371
  proc.on("close", (code) => {
343
372
  if (code === 0 && existsSync(outputPath)) {
344
- resolve({ success: true, filePath: outputPath });
373
+ resolve2({ success: true, filePath: outputPath });
345
374
  } else {
346
- resolve({ success: false, error: `screencapture exited with code ${code}` });
375
+ resolve2({ success: false, error: `screencapture exited with code ${code}` });
347
376
  }
348
377
  });
349
378
  proc.on("error", (err) => {
350
- resolve({ success: false, error: err.message });
379
+ resolve2({ success: false, error: err.message });
351
380
  });
352
381
  });
353
382
  }
@@ -356,16 +385,16 @@ async function captureLinuxScreenshot(outputPath, options) {
356
385
  if (options.windowId) {
357
386
  args.push("-w");
358
387
  }
359
- return new Promise((resolve) => {
388
+ return new Promise((resolve2) => {
360
389
  let proc = spawn("gnome-screenshot", args);
361
390
  proc.on("error", () => {
362
391
  proc = spawn("scrot", [outputPath]);
363
392
  });
364
393
  proc.on("close", (code) => {
365
394
  if (code === 0 && existsSync(outputPath)) {
366
- resolve({ success: true, filePath: outputPath });
395
+ resolve2({ success: true, filePath: outputPath });
367
396
  } else {
368
- resolve({ success: false, error: `Screenshot failed with code ${code}` });
397
+ resolve2({ success: false, error: `Screenshot failed with code ${code}` });
369
398
  }
370
399
  });
371
400
  });
@@ -380,17 +409,17 @@ async function captureWindowsScreenshot(outputPath, _options) {
380
409
  $bitmap.Save('${outputPath.replace(/\\/g, "\\\\")}')
381
410
  }
382
411
  `;
383
- return new Promise((resolve) => {
412
+ return new Promise((resolve2) => {
384
413
  const proc = spawn("powershell", ["-Command", psScript]);
385
414
  proc.on("close", (code) => {
386
415
  if (code === 0 && existsSync(outputPath)) {
387
- resolve({ success: true, filePath: outputPath });
416
+ resolve2({ success: true, filePath: outputPath });
388
417
  } else {
389
- resolve({ success: false, error: `PowerShell screenshot failed with code ${code}` });
418
+ resolve2({ success: false, error: `PowerShell screenshot failed with code ${code}` });
390
419
  }
391
420
  });
392
421
  proc.on("error", (err) => {
393
- resolve({ success: false, error: err.message });
422
+ resolve2({ success: false, error: err.message });
394
423
  });
395
424
  });
396
425
  }
@@ -497,7 +526,7 @@ async function stopRecording(sessionId) {
497
526
  if (!session) {
498
527
  return { success: false, error: `Recording session not found: ${sessionId}` };
499
528
  }
500
- return new Promise((resolve) => {
529
+ return new Promise((resolve2) => {
501
530
  if (session.process.stdin) {
502
531
  session.process.stdin.write("q");
503
532
  session.process.stdin.end();
@@ -510,13 +539,13 @@ async function stopRecording(sessionId) {
510
539
  activeRecordings.delete(sessionId);
511
540
  const duration = (Date.now() - session.startTime.getTime()) / 1e3;
512
541
  if (existsSync(session.outputPath)) {
513
- resolve({
542
+ resolve2({
514
543
  success: true,
515
544
  filePath: session.outputPath,
516
545
  duration
517
546
  });
518
547
  } else {
519
- resolve({ success: false, error: "Recording file not found" });
548
+ resolve2({ success: false, error: "Recording file not found" });
520
549
  }
521
550
  });
522
551
  });
@@ -645,7 +674,7 @@ async function captureIOSSimulatorScreenshot(options) {
645
674
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
646
675
  const filename = `ios-screenshot-${timestamp}.png`;
647
676
  const outputPath = join2(projectDir, filename);
648
- return new Promise((resolve) => {
677
+ return new Promise((resolve2) => {
649
678
  const args = ["simctl", "io", options.deviceId, "screenshot", outputPath];
650
679
  const proc = spawn2("xcrun", args);
651
680
  let stderr = "";
@@ -654,13 +683,13 @@ async function captureIOSSimulatorScreenshot(options) {
654
683
  });
655
684
  proc.on("close", (code) => {
656
685
  if (code === 0 && existsSync2(outputPath)) {
657
- resolve({ success: true, filePath: outputPath });
686
+ resolve2({ success: true, filePath: outputPath });
658
687
  } else {
659
- resolve({ success: false, error: stderr || `xcrun simctl failed with code ${code}` });
688
+ resolve2({ success: false, error: stderr || `xcrun simctl failed with code ${code}` });
660
689
  }
661
690
  });
662
691
  proc.on("error", (err) => {
663
- resolve({ success: false, error: err.message });
692
+ resolve2({ success: false, error: err.message });
664
693
  });
665
694
  });
666
695
  }
@@ -692,7 +721,7 @@ async function stopIOSSimulatorRecording(sessionId) {
692
721
  if (!session) {
693
722
  return { success: false, error: `Recording session not found: ${sessionId}` };
694
723
  }
695
- return new Promise((resolve) => {
724
+ return new Promise((resolve2) => {
696
725
  session.process.kill("SIGINT");
697
726
  const timeout = setTimeout(() => {
698
727
  session.process.kill("SIGKILL");
@@ -701,16 +730,30 @@ async function stopIOSSimulatorRecording(sessionId) {
701
730
  clearTimeout(timeout);
702
731
  iosRecordingSessions.delete(sessionId);
703
732
  if (existsSync2(session.outputPath)) {
704
- resolve({ success: true, filePath: session.outputPath });
733
+ resolve2({ success: true, filePath: session.outputPath });
705
734
  } else {
706
- resolve({ success: false, error: "Recording file not found" });
735
+ resolve2({ success: false, error: "Recording file not found" });
707
736
  }
708
737
  });
709
738
  });
710
739
  }
740
+ function quoteCommand(cmd) {
741
+ return cmd.includes(" ") ? `"${cmd}"` : cmd;
742
+ }
743
+ function getAdbCommandOrThrow() {
744
+ const adbCommand = getAdbCommand();
745
+ if (!adbCommand) {
746
+ throw new Error("ADB not found. Set ANDROID_HOME/ANDROID_SDK_ROOT or add adb to PATH.");
747
+ }
748
+ return adbCommand;
749
+ }
711
750
  function listAndroidEmulators() {
712
751
  try {
713
- const output = execSync2("adb devices -l", { encoding: "utf-8" });
752
+ const adbCommand = getAdbCommand();
753
+ if (!adbCommand) {
754
+ return [];
755
+ }
756
+ const output = execSync2(`${quoteCommand(adbCommand)} devices -l`, { encoding: "utf-8" });
714
757
  const lines = output.split("\n").slice(1);
715
758
  const devices3 = [];
716
759
  for (const line of lines) {
@@ -747,28 +790,35 @@ async function captureAndroidEmulatorScreenshot(options) {
747
790
  const filename = `android-screenshot-${timestamp}.png`;
748
791
  const outputPath = join2(projectDir, filename);
749
792
  const tempPath = "/sdcard/screenshot.png";
750
- return new Promise((resolve) => {
751
- const captureProc = spawn2("adb", ["-s", options.deviceId, "shell", "screencap", "-p", tempPath]);
793
+ return new Promise((resolve2) => {
794
+ let adbCommand;
795
+ try {
796
+ adbCommand = getAdbCommandOrThrow();
797
+ } catch (error) {
798
+ resolve2({ success: false, error: error instanceof Error ? error.message : String(error) });
799
+ return;
800
+ }
801
+ const captureProc = spawn2(adbCommand, ["-s", options.deviceId, "shell", "screencap", "-p", tempPath]);
752
802
  captureProc.on("close", (captureCode) => {
753
803
  if (captureCode !== 0) {
754
- resolve({ success: false, error: `screencap failed with code ${captureCode}` });
804
+ resolve2({ success: false, error: `screencap failed with code ${captureCode}` });
755
805
  return;
756
806
  }
757
- const pullProc = spawn2("adb", ["-s", options.deviceId, "pull", tempPath, outputPath]);
807
+ const pullProc = spawn2(adbCommand, ["-s", options.deviceId, "pull", tempPath, outputPath]);
758
808
  pullProc.on("close", (pullCode) => {
759
- spawn2("adb", ["-s", options.deviceId, "shell", "rm", tempPath]);
809
+ spawn2(adbCommand, ["-s", options.deviceId, "shell", "rm", tempPath]);
760
810
  if (pullCode === 0 && existsSync2(outputPath)) {
761
- resolve({ success: true, filePath: outputPath });
811
+ resolve2({ success: true, filePath: outputPath });
762
812
  } else {
763
- resolve({ success: false, error: `adb pull failed with code ${pullCode}` });
813
+ resolve2({ success: false, error: `adb pull failed with code ${pullCode}` });
764
814
  }
765
815
  });
766
816
  pullProc.on("error", (err) => {
767
- resolve({ success: false, error: err.message });
817
+ resolve2({ success: false, error: err.message });
768
818
  });
769
819
  });
770
820
  captureProc.on("error", (err) => {
771
- resolve({ success: false, error: err.message });
821
+ resolve2({ success: false, error: err.message });
772
822
  });
773
823
  });
774
824
  }
@@ -782,14 +832,21 @@ async function startAndroidEmulatorRecording(options) {
782
832
  const filename = `android-recording-${timestamp}.mp4`;
783
833
  const outputPath = join2(projectDir, filename);
784
834
  const tempPath = "/sdcard/recording.mp4";
835
+ let adbCommand;
836
+ try {
837
+ adbCommand = getAdbCommandOrThrow();
838
+ } catch (error) {
839
+ return { error: error instanceof Error ? error.message : String(error) };
840
+ }
785
841
  const args = ["-s", options.deviceId, "shell", "screenrecord"];
786
842
  if (options.duration) {
787
843
  args.push("--time-limit", Math.min(options.duration, 180).toString());
788
844
  }
789
845
  args.push(tempPath);
790
- const proc = spawn2("adb", args, { stdio: ["pipe", "pipe", "pipe"] });
846
+ const proc = spawn2(adbCommand, args, { stdio: ["pipe", "pipe", "pipe"] });
791
847
  androidRecordingSessions.set(sessionId, {
792
848
  process: proc,
849
+ adbCommand,
793
850
  deviceId: options.deviceId,
794
851
  tempPath,
795
852
  outputPath
@@ -802,22 +859,22 @@ async function stopAndroidEmulatorRecording(sessionId) {
802
859
  if (!session) {
803
860
  return { success: false, error: `Recording session not found: ${sessionId}` };
804
861
  }
805
- return new Promise((resolve) => {
862
+ return new Promise((resolve2) => {
806
863
  session.process.kill("SIGINT");
807
864
  setTimeout(() => {
808
- const pullProc = spawn2("adb", ["-s", session.deviceId, "pull", session.tempPath, session.outputPath]);
865
+ const pullProc = spawn2(session.adbCommand, ["-s", session.deviceId, "pull", session.tempPath, session.outputPath]);
809
866
  pullProc.on("close", (pullCode) => {
810
- spawn2("adb", ["-s", session.deviceId, "shell", "rm", session.tempPath]);
867
+ spawn2(session.adbCommand, ["-s", session.deviceId, "shell", "rm", session.tempPath]);
811
868
  androidRecordingSessions.delete(sessionId);
812
869
  if (pullCode === 0 && existsSync2(session.outputPath)) {
813
- resolve({ success: true, filePath: session.outputPath });
870
+ resolve2({ success: true, filePath: session.outputPath });
814
871
  } else {
815
- resolve({ success: false, error: "Failed to pull recording file" });
872
+ resolve2({ success: false, error: "Failed to pull recording file" });
816
873
  }
817
874
  });
818
875
  pullProc.on("error", (err) => {
819
876
  androidRecordingSessions.delete(sessionId);
820
- resolve({ success: false, error: err.message });
877
+ resolve2({ success: false, error: err.message });
821
878
  });
822
879
  }, 1e3);
823
880
  });
@@ -875,7 +932,9 @@ async function stopEmulatorRecording(sessionId, platformHint) {
875
932
  }
876
933
  function checkADB() {
877
934
  try {
878
- execSync2("adb version", { stdio: "ignore" });
935
+ const adbCommand = getAdbCommand();
936
+ if (!adbCommand) return false;
937
+ execSync2(`${quoteCommand(adbCommand)} version`, { stdio: "ignore" });
879
938
  return true;
880
939
  } catch {
881
940
  return false;
@@ -1197,7 +1256,7 @@ async function extractFrames(options) {
1197
1256
  return { success: false, error: "Failed to read video information" };
1198
1257
  }
1199
1258
  const args = buildFFmpegArgs(options, framesDir, videoInfo, outputFormat);
1200
- return new Promise((resolve) => {
1259
+ return new Promise((resolve2) => {
1201
1260
  const proc = spawn3("ffmpeg", args);
1202
1261
  let stderr = "";
1203
1262
  proc.stderr.on("data", (data) => {
@@ -1205,11 +1264,11 @@ async function extractFrames(options) {
1205
1264
  });
1206
1265
  proc.on("close", (code) => {
1207
1266
  if (code !== 0) {
1208
- resolve({ success: false, error: `FFmpeg failed: ${stderr.slice(-500)}` });
1267
+ resolve2({ success: false, error: `FFmpeg failed: ${stderr.slice(-500)}` });
1209
1268
  return;
1210
1269
  }
1211
1270
  const frames2 = listExtractedFrames(framesDir, videoInfo.fps, options.fps || 1);
1212
- resolve({
1271
+ resolve2({
1213
1272
  success: true,
1214
1273
  framesDir,
1215
1274
  frameCount: frames2.length,
@@ -1217,7 +1276,7 @@ async function extractFrames(options) {
1217
1276
  });
1218
1277
  });
1219
1278
  proc.on("error", (err) => {
1220
- resolve({ success: false, error: err.message });
1279
+ resolve2({ success: false, error: err.message });
1221
1280
  });
1222
1281
  });
1223
1282
  }
@@ -2959,7 +3018,7 @@ function buildOverlayFilter(overlay) {
2959
3018
  return null;
2960
3019
  }
2961
3020
  async function runFFmpegWithProgress(args, onProgress) {
2962
- return new Promise((resolve, reject) => {
3021
+ return new Promise((resolve2, reject) => {
2963
3022
  const ffmpeg = spawn4("ffmpeg", args, { stdio: ["pipe", "pipe", "pipe"] });
2964
3023
  ffmpeg.stderr?.on("data", (data) => {
2965
3024
  const output = data.toString();
@@ -2981,7 +3040,7 @@ async function runFFmpegWithProgress(args, onProgress) {
2981
3040
  });
2982
3041
  ffmpeg.on("close", (code) => {
2983
3042
  if (code === 0) {
2984
- resolve();
3043
+ resolve2();
2985
3044
  } else {
2986
3045
  reject(new Error(`FFmpeg exited with code ${code}`));
2987
3046
  }
@@ -6314,6 +6373,1025 @@ var taskHubTools = [
6314
6373
  taskHubTestMapToggleTool
6315
6374
  ];
6316
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
+
6317
7395
  export {
6318
7396
  uiOpenTool,
6319
7397
  uiStatusTool,
@@ -6393,5 +7471,31 @@ export {
6393
7471
  taskHubRequirementsGetTool,
6394
7472
  taskHubTestMapGetTool,
6395
7473
  taskHubTestMapToggleTool,
6396
- 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
6397
7501
  };