@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.
Files changed (172) hide show
  1. package/.mcp.json +2 -2
  2. package/README.md +182 -0
  3. package/dist/{chunk-YEZ26ENO.js → chunk-3QRQEDWR.js} +313 -192
  4. package/dist/{chunk-E3N3P2AG.js → chunk-4L76GPRC.js} +1124 -51
  5. package/dist/{chunk-I6YD3QFM.js → chunk-FIL7IWEL.js} +5 -3
  6. package/dist/{chunk-G524UVBK.js → chunk-FNUN7EPB.js} +5 -5
  7. package/dist/chunk-GAKEFJ5T.js +481 -0
  8. package/dist/chunk-LB3RNE3O.js +109 -0
  9. package/dist/chunk-N6JJ2RGV.js +2680 -0
  10. package/dist/{chunk-7HZEDTS7.js → chunk-VRM42PML.js} +3471 -848
  11. package/dist/{chunk-TJ3H23LL.js → chunk-VVIOB362.js} +3 -1
  12. package/dist/{chunk-W3WJGYR6.js → chunk-XFVDP332.js} +8 -2
  13. package/dist/cli.js +397 -9
  14. package/dist/{db-ADBEBNH6.js → db-6WLEVKUV.js} +3 -1
  15. package/dist/esvp-GSISVXLC.js +52 -0
  16. package/dist/esvp-mobile-GC7MAGMI.js +20 -0
  17. package/dist/index.d.ts +123 -1
  18. package/dist/index.html +11689 -8690
  19. package/dist/index.js +67 -12
  20. package/dist/{ocr-UTWC7537.js → ocr-QDYNCSPE.js} +1 -1
  21. package/dist/{playwright-R7Y5HREH.js → playwright-VZ7PXDC5.js} +2 -2
  22. package/dist/runtime/esvp-host-runtime/darwin-arm64/esvp-host-runtime +0 -0
  23. package/dist/runtime/esvp-host-runtime/manifest.json +10 -0
  24. package/dist/server-FO3UVUZU.js +22 -0
  25. package/dist/{setup-B5YPNUE4.js → setup-2SQC5UHJ.js} +2 -2
  26. package/dist/{tools-YS4QHOTQ.js → tools-OCRMOQ4U.js} +61 -6
  27. package/package.json +36 -5
  28. package/dist/chunk-22OCFYHG.js +0 -6283
  29. package/dist/chunk-24VARQVO.js +0 -7818
  30. package/dist/chunk-2OGZX6C4.js +0 -588
  31. package/dist/chunk-2WCNIFRO.js +0 -6191
  32. package/dist/chunk-43U6UYV7.js +0 -590
  33. package/dist/chunk-4H2E3K2G.js +0 -7638
  34. package/dist/chunk-4KLG6DDE.js +0 -334
  35. package/dist/chunk-4MS6YW2B.js +0 -6490
  36. package/dist/chunk-4NNTRJOI.js +0 -7791
  37. package/dist/chunk-5F76VWME.js +0 -6397
  38. package/dist/chunk-5NEFN42O.js +0 -7791
  39. package/dist/chunk-63MEQ6UH.js +0 -7673
  40. package/dist/chunk-6H3NXFX3.js +0 -6861
  41. package/dist/chunk-7DOG2W4O.js +0 -6428
  42. package/dist/chunk-7IDQLLBW.js +0 -311
  43. package/dist/chunk-7NP64TGJ.js +0 -6822
  44. package/dist/chunk-AATLY4KT.js +0 -6505
  45. package/dist/chunk-C7QUR7XX.js +0 -6397
  46. package/dist/chunk-CGKCE6MC.js +0 -6279
  47. package/dist/chunk-D25V6IWE.js +0 -6487
  48. package/dist/chunk-EQOZSXAT.js +0 -6822
  49. package/dist/chunk-FPHD7HSQ.js +0 -6812
  50. package/dist/chunk-GGJJUCFK.js +0 -7160
  51. package/dist/chunk-GLHOY3NN.js +0 -7805
  52. package/dist/chunk-GML5MKQA.js +0 -6398
  53. package/dist/chunk-GOL6FUJL.js +0 -6045
  54. package/dist/chunk-GSWHWEYC.js +0 -1346
  55. package/dist/chunk-HDKEQOF5.js +0 -7788
  56. package/dist/chunk-HZGSWVVS.js +0 -7111
  57. package/dist/chunk-IGZ5TICZ.js +0 -334
  58. package/dist/chunk-IRKQG33A.js +0 -7054
  59. package/dist/chunk-JFTBF4JR.js +0 -6040
  60. package/dist/chunk-JVLVBPUJ.js +0 -6180
  61. package/dist/chunk-JY3KC67R.js +0 -6504
  62. package/dist/chunk-KUFBCBNJ.js +0 -6815
  63. package/dist/chunk-KV7KDJ43.js +0 -7639
  64. package/dist/chunk-L4SA5F5W.js +0 -6397
  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-QJXXHOV7.js +0 -205
  81. package/dist/chunk-RDZDSOAL.js +0 -7750
  82. package/dist/chunk-RLW2OI2L.js +0 -6383
  83. package/dist/chunk-RUGHHO4K.js +0 -6395
  84. package/dist/chunk-SIOQVM2E.js +0 -6819
  85. package/dist/chunk-SR67SRIT.js +0 -1336
  86. package/dist/chunk-SSRXIO2V.js +0 -6822
  87. package/dist/chunk-SWSEKFON.js +0 -6487
  88. package/dist/chunk-TAODYZ52.js +0 -1393
  89. package/dist/chunk-TBG76CYG.js +0 -6395
  90. package/dist/chunk-V3CBINLD.js +0 -6812
  91. package/dist/chunk-VPYSLEGM.js +0 -6710
  92. package/dist/chunk-VY3BLXBW.js +0 -329
  93. package/dist/chunk-WTFOGVJQ.js +0 -6365
  94. package/dist/chunk-X64SFUT5.js +0 -6099
  95. package/dist/chunk-XIBF5LBD.js +0 -6395
  96. package/dist/chunk-XUKWS2CE.js +0 -7805
  97. package/dist/chunk-XZZKFF5V.js +0 -7787
  98. package/dist/chunk-Y5VDMSYC.js +0 -6701
  99. package/dist/chunk-YUBL36H4.js +0 -6605
  100. package/dist/chunk-YWVXFVSW.js +0 -6456
  101. package/dist/chunk-ZJFWMSZF.js +0 -7883
  102. package/dist/chunk-ZXZACOLD.js +0 -6822
  103. package/dist/db-IWIL65EX.js +0 -33
  104. package/dist/gridCompositor-ENKLFPWR.js +0 -409
  105. package/dist/playwright-A3OGSDRG.js +0 -38
  106. package/dist/playwright-ATDC4NYW.js +0 -38
  107. package/dist/playwright-E6EUFIJG.js +0 -38
  108. package/dist/server-2DXLKLFM.js +0 -13
  109. package/dist/server-2ICEWJVK.js +0 -13
  110. package/dist/server-2MQV3FNY.js +0 -13
  111. package/dist/server-2NGD7GE3.js +0 -13
  112. package/dist/server-2VKO76UK.js +0 -14
  113. package/dist/server-3BK2VFU7.js +0 -13
  114. package/dist/server-3FBHBA7L.js +0 -15
  115. package/dist/server-4LDOB3NX.js +0 -13
  116. package/dist/server-4YI44KDR.js +0 -13
  117. package/dist/server-64XMXA5P.js +0 -13
  118. package/dist/server-6IPHVUYT.js +0 -14
  119. package/dist/server-73ORHMJN.js +0 -13
  120. package/dist/server-73P7M3QB.js +0 -14
  121. package/dist/server-BPVRW5LJ.js +0 -14
  122. package/dist/server-BW4RKZIX.js +0 -13
  123. package/dist/server-CFS5SM5K.js +0 -13
  124. package/dist/server-DX7VYHHM.js +0 -13
  125. package/dist/server-F3YPX6ET.js +0 -13
  126. package/dist/server-FUXTR33I.js +0 -13
  127. package/dist/server-G2SY3DOS.js +0 -13
  128. package/dist/server-G32U7VOQ.js +0 -13
  129. package/dist/server-HKRIY7FP.js +0 -14
  130. package/dist/server-HON66OES.js +0 -15
  131. package/dist/server-IOOZK4NP.js +0 -14
  132. package/dist/server-IZEO7OJJ.js +0 -14
  133. package/dist/server-J52LMTBT.js +0 -13
  134. package/dist/server-JG7UKFGK.js +0 -14
  135. package/dist/server-JSCHEBOD.js +0 -13
  136. package/dist/server-K6KC4ZOM.js +0 -13
  137. package/dist/server-KJVRGWFE.js +0 -13
  138. package/dist/server-LCPB2L4U.js +0 -13
  139. package/dist/server-M7LDYKAJ.js +0 -13
  140. package/dist/server-MKVK6ZQQ.js +0 -13
  141. package/dist/server-MU52LCXT.js +0 -13
  142. package/dist/server-NM5CKDUU.js +0 -13
  143. package/dist/server-NPZN3FWO.js +0 -14
  144. package/dist/server-O5FIAHSY.js +0 -14
  145. package/dist/server-OESJUEYC.js +0 -13
  146. package/dist/server-ONSKQO4W.js +0 -13
  147. package/dist/server-P27BZXBL.js +0 -14
  148. package/dist/server-Q4FBWQUA.js +0 -13
  149. package/dist/server-RNQ7VUAL.js +0 -13
  150. package/dist/server-S6B5WUBT.js +0 -14
  151. package/dist/server-SRYNSGSP.js +0 -14
  152. package/dist/server-SUN3W2YK.js +0 -13
  153. package/dist/server-UA62LHZB.js +0 -13
  154. package/dist/server-UJB44EW5.js +0 -13
  155. package/dist/server-X3TLP6DX.js +0 -14
  156. package/dist/server-YT2UGEZK.js +0 -13
  157. package/dist/server-ZBPQ33V6.js +0 -14
  158. package/dist/setup-27CQAX6K.js +0 -17
  159. package/dist/setup-AQX4JQVR.js +0 -17
  160. package/dist/setup-EQTU7FI6.js +0 -17
  161. package/dist/tools-2KPB37GK.js +0 -178
  162. package/dist/tools-3H6IOWXV.js +0 -178
  163. package/dist/tools-3KYHPDCJ.js +0 -178
  164. package/dist/tools-75BAPCUM.js +0 -177
  165. package/dist/tools-BUVCUCRL.js +0 -178
  166. package/dist/tools-HDNODRS6.js +0 -178
  167. package/dist/tools-HP5MNY3D.js +0 -177
  168. package/dist/tools-L6PKKQPY.js +0 -179
  169. package/dist/tools-N5N2IO7V.js +0 -178
  170. package/dist/tools-NFJEZ2FF.js +0 -177
  171. package/dist/tools-OPULIER6.js +0 -178
  172. 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-YEZ26ENO.js";
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-43U6UYV7.js";
33
+ } from "./chunk-FIL7IWEL.js";
27
34
  import {
28
- analyzeText,
29
- getAvailableOCREngines,
30
- recognizeText,
31
- recognizeTextBatch
32
- } 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";
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-TJ3H23LL.js";
70
+ } from "./chunk-VVIOB362.js";
44
71
  import {
45
- createErrorResult,
46
- createJsonResult,
47
- createTextResult
48
- } from "./chunk-XKX6NBHF.js";
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((resolve) => {
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
- resolve({ success: true, filePath: outputPath });
373
+ resolve2({ success: true, filePath: outputPath });
346
374
  } else {
347
- resolve({ success: false, error: `screencapture exited with code ${code}` });
375
+ resolve2({ success: false, error: `screencapture exited with code ${code}` });
348
376
  }
349
377
  });
350
378
  proc.on("error", (err) => {
351
- resolve({ success: false, error: err.message });
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((resolve) => {
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
- resolve({ success: true, filePath: outputPath });
395
+ resolve2({ success: true, filePath: outputPath });
368
396
  } else {
369
- resolve({ success: false, error: `Screenshot failed with code ${code}` });
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((resolve) => {
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
- resolve({ success: true, filePath: outputPath });
416
+ resolve2({ success: true, filePath: outputPath });
389
417
  } else {
390
- resolve({ success: false, error: `PowerShell screenshot failed with code ${code}` });
418
+ resolve2({ success: false, error: `PowerShell screenshot failed with code ${code}` });
391
419
  }
392
420
  });
393
421
  proc.on("error", (err) => {
394
- resolve({ success: false, error: err.message });
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((resolve) => {
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
- resolve({
542
+ resolve2({
515
543
  success: true,
516
544
  filePath: session.outputPath,
517
545
  duration
518
546
  });
519
547
  } else {
520
- resolve({ success: false, error: "Recording file not found" });
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((resolve) => {
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
- resolve({ success: true, filePath: outputPath });
686
+ resolve2({ success: true, filePath: outputPath });
659
687
  } else {
660
- resolve({ success: false, error: stderr || `xcrun simctl failed with code ${code}` });
688
+ resolve2({ success: false, error: stderr || `xcrun simctl failed with code ${code}` });
661
689
  }
662
690
  });
663
691
  proc.on("error", (err) => {
664
- resolve({ success: false, error: err.message });
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((resolve) => {
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
- resolve({ success: true, filePath: session.outputPath });
733
+ resolve2({ success: true, filePath: session.outputPath });
706
734
  } else {
707
- resolve({ success: false, error: "Recording file not found" });
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((resolve) => {
793
+ return new Promise((resolve2) => {
766
794
  let adbCommand;
767
795
  try {
768
796
  adbCommand = getAdbCommandOrThrow();
769
797
  } catch (error) {
770
- resolve({ success: false, error: error instanceof Error ? error.message : String(error) });
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
- resolve({ success: false, error: `screencap failed with code ${captureCode}` });
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
- resolve({ success: true, filePath: outputPath });
811
+ resolve2({ success: true, filePath: outputPath });
784
812
  } else {
785
- resolve({ success: false, error: `adb pull failed with code ${pullCode}` });
813
+ resolve2({ success: false, error: `adb pull failed with code ${pullCode}` });
786
814
  }
787
815
  });
788
816
  pullProc.on("error", (err) => {
789
- resolve({ success: false, error: err.message });
817
+ resolve2({ success: false, error: err.message });
790
818
  });
791
819
  });
792
820
  captureProc.on("error", (err) => {
793
- resolve({ success: false, error: err.message });
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((resolve) => {
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
- resolve({ success: true, filePath: session.outputPath });
870
+ resolve2({ success: true, filePath: session.outputPath });
843
871
  } else {
844
- resolve({ success: false, error: "Failed to pull recording file" });
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
- resolve({ success: false, error: err.message });
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((resolve) => {
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
- resolve({ success: false, error: `FFmpeg failed: ${stderr.slice(-500)}` });
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
- resolve({
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
- resolve({ success: false, error: err.message });
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((resolve, reject) => {
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
- resolve();
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
  };