@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,12 +1,83 @@
1
1
  import {
2
- PROJECTS_DIR
3
- } from "./chunk-TJ3H23LL.js";
2
+ PROJECTS_DIR,
3
+ TEMPLATES_DIR
4
+ } from "./chunk-VVIOB362.js";
5
+
6
+ // src/core/templates/loader.ts
7
+ import { existsSync, readFileSync } from "fs";
8
+ import { join, dirname } from "path";
9
+ import { fileURLToPath } from "url";
10
+ var MANIFEST_FILE = "manifest.json";
11
+ var BUNDLE_DIR = "bundle";
12
+ var __dirname = dirname(fileURLToPath(import.meta.url));
13
+ var BUNDLED_TEMPLATES_DIR = join(__dirname, "..", "..", "templates");
14
+ var cachedManifest = null;
15
+ var cachedTemplatesDir = null;
16
+ var cachedAt = 0;
17
+ var CACHE_TTL = 3e4;
18
+ function resolveTemplatesDir() {
19
+ const localManifest = join(TEMPLATES_DIR, MANIFEST_FILE);
20
+ const localBundle = join(TEMPLATES_DIR, BUNDLE_DIR);
21
+ if (existsSync(localManifest) && existsSync(localBundle)) {
22
+ return TEMPLATES_DIR;
23
+ }
24
+ const bundledManifest = join(BUNDLED_TEMPLATES_DIR, MANIFEST_FILE);
25
+ const bundledBundle = join(BUNDLED_TEMPLATES_DIR, BUNDLE_DIR);
26
+ if (existsSync(bundledManifest) && existsSync(bundledBundle)) {
27
+ return BUNDLED_TEMPLATES_DIR;
28
+ }
29
+ return null;
30
+ }
31
+ function loadManifest() {
32
+ const now = Date.now();
33
+ if (cachedManifest && now - cachedAt < CACHE_TTL) {
34
+ return cachedManifest;
35
+ }
36
+ const dir = resolveTemplatesDir();
37
+ if (!dir) {
38
+ cachedManifest = null;
39
+ cachedTemplatesDir = null;
40
+ cachedAt = now;
41
+ return null;
42
+ }
43
+ try {
44
+ const raw = readFileSync(join(dir, MANIFEST_FILE), "utf-8");
45
+ const manifest = JSON.parse(raw);
46
+ cachedManifest = manifest;
47
+ cachedTemplatesDir = dir;
48
+ cachedAt = now;
49
+ return manifest;
50
+ } catch {
51
+ cachedManifest = null;
52
+ cachedTemplatesDir = null;
53
+ cachedAt = now;
54
+ return null;
55
+ }
56
+ }
57
+ function isTemplatesInstalled() {
58
+ return loadManifest() !== null;
59
+ }
60
+ function getAvailableTemplates() {
61
+ const manifest = loadManifest();
62
+ return manifest?.templates ?? [];
63
+ }
64
+ function getTemplate(id) {
65
+ const templates = getAvailableTemplates();
66
+ return templates.find((t) => t.id === id) ?? null;
67
+ }
68
+ function getBundlePath() {
69
+ loadManifest();
70
+ if (!cachedTemplatesDir) return null;
71
+ const bundlePath = join(cachedTemplatesDir, BUNDLE_DIR);
72
+ if (!existsSync(bundlePath)) return null;
73
+ return bundlePath;
74
+ }
4
75
 
5
76
  // src/core/android/adb.ts
6
77
  import { execSync } from "child_process";
7
- import { existsSync } from "fs";
78
+ import { existsSync as existsSync2 } from "fs";
8
79
  import { homedir } from "os";
9
- import { join } from "path";
80
+ import { join as join2 } from "path";
10
81
  var ADB_COMMAND_CACHE_SUCCESS_TTL_MS = 5 * 60 * 1e3;
11
82
  var ADB_COMMAND_CACHE_FAILURE_TTL_MS = 5 * 1e3;
12
83
  var adbCommandCache = null;
@@ -25,19 +96,19 @@ function findAndroidSdkPath() {
25
96
  process.env.ANDROID_SDK
26
97
  ].filter((value) => typeof value === "string" && value.trim().length > 0);
27
98
  for (const envPath of envPaths) {
28
- if (existsSync(join(envPath, "platform-tools", "adb"))) {
99
+ if (existsSync2(join2(envPath, "platform-tools", "adb"))) {
29
100
  return envPath;
30
101
  }
31
102
  }
32
103
  const home = homedir();
33
104
  const commonPaths = [
34
- join(home, "Library", "Android", "sdk"),
35
- join(home, "Android", "Sdk"),
105
+ join2(home, "Library", "Android", "sdk"),
106
+ join2(home, "Android", "Sdk"),
36
107
  "/opt/android-sdk",
37
108
  "/usr/local/android-sdk"
38
109
  ];
39
110
  for (const sdkPath of commonPaths) {
40
- if (existsSync(join(sdkPath, "platform-tools", "adb"))) {
111
+ if (existsSync2(join2(sdkPath, "platform-tools", "adb"))) {
41
112
  return sdkPath;
42
113
  }
43
114
  }
@@ -46,14 +117,14 @@ function findAndroidSdkPath() {
46
117
  function getAdbPath() {
47
118
  const sdkPath = findAndroidSdkPath();
48
119
  if (!sdkPath) return null;
49
- const adbPath = join(sdkPath, "platform-tools", "adb");
50
- return existsSync(adbPath) ? adbPath : null;
120
+ const adbPath = join2(sdkPath, "platform-tools", "adb");
121
+ return existsSync2(adbPath) ? adbPath : null;
51
122
  }
52
123
  function getEmulatorPath() {
53
124
  const sdkPath = findAndroidSdkPath();
54
125
  if (!sdkPath) return null;
55
- const emulatorPath = join(sdkPath, "emulator", "emulator");
56
- return existsSync(emulatorPath) ? emulatorPath : null;
126
+ const emulatorPath = join2(sdkPath, "emulator", "emulator");
127
+ return existsSync2(emulatorPath) ? emulatorPath : null;
57
128
  }
58
129
  function getAdbCommand(options) {
59
130
  const forceRefresh = options?.forceRefresh === true;
@@ -74,7 +145,7 @@ function getAdbCommand(options) {
74
145
  try {
75
146
  if (candidate === "adb") {
76
147
  execSync("which adb", { stdio: "pipe", timeout: 2e3 });
77
- } else if (!existsSync(candidate)) {
148
+ } else if (!existsSync2(candidate)) {
78
149
  continue;
79
150
  }
80
151
  adbCommandCache = { value: candidate, checkedAt: Date.now() };
@@ -662,6 +733,212 @@ function createNavigationTestFlow(appId, tabs) {
662
733
  steps
663
734
  };
664
735
  }
736
+ function parseMaestroActionsFromYaml(yamlContent) {
737
+ const actions = [];
738
+ const lines = yamlContent.split("\n");
739
+ let currentAction = null;
740
+ let actionIndex = 0;
741
+ const nextId = () => `action_${String(++actionIndex).padStart(3, "0")}`;
742
+ const stripInlineComment = (value) => {
743
+ let inSingle = false;
744
+ let inDouble = false;
745
+ let escaped = false;
746
+ for (let index = 0; index < value.length; index += 1) {
747
+ const char = value[index];
748
+ if (escaped) {
749
+ escaped = false;
750
+ continue;
751
+ }
752
+ if (char === "\\") {
753
+ escaped = true;
754
+ continue;
755
+ }
756
+ if (char === '"' && !inSingle) {
757
+ inDouble = !inDouble;
758
+ continue;
759
+ }
760
+ if (char === "'" && !inDouble) {
761
+ inSingle = !inSingle;
762
+ continue;
763
+ }
764
+ if (char === "#" && !inSingle && !inDouble) {
765
+ return value.slice(0, index).trimEnd();
766
+ }
767
+ }
768
+ return value;
769
+ };
770
+ const cleanValue = (value) => stripInlineComment(value).trim().replace(/^["']|["']$/g, "");
771
+ const pushAction = (action) => {
772
+ actions.push({
773
+ id: action.id || nextId(),
774
+ type: action.type || "tap",
775
+ timestamp: action.timestamp || Date.now(),
776
+ description: action.description || action.type || "Action",
777
+ x: action.x,
778
+ y: action.y,
779
+ endX: action.endX,
780
+ endY: action.endY,
781
+ text: action.text,
782
+ direction: action.direction,
783
+ seconds: action.seconds,
784
+ appId: action.appId,
785
+ duration: action.duration,
786
+ screenshotPath: action.screenshotPath
787
+ });
788
+ };
789
+ for (const line of lines) {
790
+ const trimmed = line.trim();
791
+ if (trimmed.startsWith("#") || trimmed === "" || trimmed === "---") {
792
+ continue;
793
+ }
794
+ if (trimmed.startsWith("appId:")) {
795
+ continue;
796
+ }
797
+ if (trimmed.startsWith("- tapOn:")) {
798
+ const inlineValue = cleanValue(trimmed.replace("- tapOn:", ""));
799
+ if (inlineValue) {
800
+ pushAction({
801
+ type: "tap",
802
+ description: `Tap on "${inlineValue}"`,
803
+ text: inlineValue
804
+ });
805
+ continue;
806
+ }
807
+ currentAction = { type: "tap", description: "Tap" };
808
+ } else if (trimmed.startsWith("- tap:")) {
809
+ currentAction = { type: "tap", description: "Tap" };
810
+ } else if (trimmed.startsWith("- swipe:")) {
811
+ currentAction = { type: "swipe", description: "Swipe" };
812
+ } else if (trimmed.startsWith("- scroll:")) {
813
+ currentAction = { type: "scroll", description: "Scroll" };
814
+ } else if (trimmed.startsWith("- scrollUntilVisible:")) {
815
+ currentAction = { type: "scroll", description: "Scroll" };
816
+ } else if (trimmed.startsWith("- inputText:")) {
817
+ const text = cleanValue(trimmed.replace("- inputText:", ""));
818
+ pushAction({
819
+ type: "input",
820
+ description: `Input: ${text.slice(0, 20)}${text.length > 20 ? "..." : ""}`,
821
+ text
822
+ });
823
+ continue;
824
+ } else if (trimmed.startsWith("- launchApp:")) {
825
+ const appId = cleanValue(trimmed.replace("- launchApp:", ""));
826
+ pushAction({
827
+ type: "launch",
828
+ description: `Launch: ${appId}`,
829
+ text: appId,
830
+ appId
831
+ });
832
+ continue;
833
+ } else if (trimmed === "- launchApp") {
834
+ pushAction({
835
+ type: "launch",
836
+ description: "Launch app"
837
+ });
838
+ continue;
839
+ } else if (trimmed.startsWith("- assertVisible:")) {
840
+ const inlineValue = cleanValue(trimmed.replace("- assertVisible:", ""));
841
+ if (inlineValue) {
842
+ pushAction({
843
+ type: "assert",
844
+ description: `Assert visible "${inlineValue}"`,
845
+ text: inlineValue
846
+ });
847
+ continue;
848
+ }
849
+ currentAction = { type: "assert", description: "Assert visible" };
850
+ } else if (trimmed.startsWith("- extendedWaitUntil:")) {
851
+ currentAction = { type: "wait", description: "Wait" };
852
+ } else if (trimmed.startsWith("- pressKey:")) {
853
+ const key = cleanValue(trimmed.replace("- pressKey:", "")).toLowerCase();
854
+ if (key === "back") {
855
+ pushAction({ type: "back", description: "Back button" });
856
+ } else if (key === "home") {
857
+ pushAction({ type: "home", description: "Home button" });
858
+ } else {
859
+ pushAction({
860
+ type: "pressKey",
861
+ description: `Press: ${key}`,
862
+ text: key
863
+ });
864
+ }
865
+ continue;
866
+ } else if (trimmed.startsWith("- back")) {
867
+ pushAction({ type: "back", description: "Back button" });
868
+ continue;
869
+ }
870
+ if (currentAction && trimmed.startsWith("point:")) {
871
+ const point = cleanValue(trimmed.replace("point:", ""));
872
+ const [x, y] = point.split(",").map((n) => parseInt(n.trim()));
873
+ if (!isNaN(x) && !isNaN(y)) {
874
+ currentAction.x = x;
875
+ currentAction.y = y;
876
+ currentAction.description = `Tap at (${x}, ${y})`;
877
+ pushAction(currentAction);
878
+ currentAction = null;
879
+ continue;
880
+ }
881
+ }
882
+ if (currentAction && trimmed.startsWith("text:")) {
883
+ const text = cleanValue(trimmed.replace("text:", ""));
884
+ currentAction.text = text;
885
+ if (currentAction.type === "assert") {
886
+ currentAction.description = `Assert visible "${text}"`;
887
+ } else {
888
+ currentAction.description = `Tap on "${text}"`;
889
+ }
890
+ pushAction(currentAction);
891
+ currentAction = null;
892
+ continue;
893
+ }
894
+ if (currentAction && trimmed.startsWith("id:")) {
895
+ const id = cleanValue(trimmed.replace("id:", ""));
896
+ currentAction.text = id;
897
+ currentAction.description = `Tap on id: ${id}`;
898
+ pushAction(currentAction);
899
+ currentAction = null;
900
+ continue;
901
+ }
902
+ if (currentAction && (currentAction.type === "swipe" || currentAction.type === "scroll") && trimmed.startsWith("direction:")) {
903
+ const direction = cleanValue(trimmed.replace("direction:", "")).toLowerCase();
904
+ currentAction.direction = direction;
905
+ currentAction.description = currentAction.type === "swipe" ? `Swipe ${direction}` : `Scroll ${direction}`;
906
+ pushAction(currentAction);
907
+ currentAction = null;
908
+ continue;
909
+ }
910
+ if (currentAction && currentAction.type === "wait" && trimmed.startsWith("timeout:")) {
911
+ const timeoutMs = parseInt(cleanValue(trimmed.replace("timeout:", "")), 10);
912
+ const seconds = Number.isFinite(timeoutMs) && timeoutMs > 0 ? Math.max(1, Math.round(timeoutMs / 1e3)) : 3;
913
+ currentAction.seconds = seconds;
914
+ currentAction.description = `Wait ${seconds}s`;
915
+ pushAction(currentAction);
916
+ currentAction = null;
917
+ continue;
918
+ }
919
+ if (currentAction && currentAction.type === "swipe") {
920
+ if (trimmed.startsWith("start:")) {
921
+ const point = cleanValue(trimmed.replace("start:", ""));
922
+ const [x, y] = point.split(",").map((n) => parseInt(n.trim()));
923
+ if (!isNaN(x) && !isNaN(y)) {
924
+ currentAction.x = x;
925
+ currentAction.y = y;
926
+ }
927
+ } else if (trimmed.startsWith("end:")) {
928
+ const point = cleanValue(trimmed.replace("end:", ""));
929
+ const [x, y] = point.split(",").map((n) => parseInt(n.trim()));
930
+ if (!isNaN(x) && !isNaN(y)) {
931
+ currentAction.endX = x;
932
+ currentAction.endY = y;
933
+ currentAction.description = `Swipe from (${currentAction.x}, ${currentAction.y}) to (${x}, ${y})`;
934
+ pushAction(currentAction);
935
+ currentAction = null;
936
+ }
937
+ }
938
+ }
939
+ }
940
+ return actions;
941
+ }
665
942
  var MaestroRecorder = class extends EventEmitter {
666
943
  session = null;
667
944
  adbProcess = null;
@@ -1198,6 +1475,18 @@ var MaestroRecorder = class extends EventEmitter {
1198
1475
  console.log("[MaestroRecorder] Generated flow YAML from recorded actions");
1199
1476
  }
1200
1477
  }
1478
+ if (this.session.actions.length === 0 && this.session.flowPath && fs.existsSync(this.session.flowPath)) {
1479
+ try {
1480
+ const fallbackYaml = await fs.promises.readFile(this.session.flowPath, "utf-8");
1481
+ const parsedActions = parseMaestroActionsFromYaml(fallbackYaml);
1482
+ if (parsedActions.length > 0) {
1483
+ this.session.actions = parsedActions;
1484
+ console.log(`[MaestroRecorder] Rehydrated ${parsedActions.length} actions from YAML for manual capture`);
1485
+ }
1486
+ } catch (error) {
1487
+ console.error("[MaestroRecorder] Failed to rehydrate actions from YAML:", error);
1488
+ }
1489
+ }
1201
1490
  const metadataPath = path.join(this.session.screenshotsDir, "..", "session.json");
1202
1491
  await fs.promises.writeFile(metadataPath, JSON.stringify(this.session, null, 2));
1203
1492
  this.clearPendingSession();
@@ -1211,186 +1500,13 @@ var MaestroRecorder = class extends EventEmitter {
1211
1500
  * Parse actions from Maestro YAML content
1212
1501
  */
1213
1502
  parseActionsFromYaml(yamlContent) {
1214
- const actions = [];
1215
- const lines = yamlContent.split("\n");
1216
- let currentAction = null;
1217
- let actionIndex = 0;
1218
- const nextId = () => `action_${String(++actionIndex).padStart(3, "0")}`;
1219
- const cleanValue = (value) => value.trim().replace(/^["']|["']$/g, "");
1220
- const pushAction = (action) => {
1221
- actions.push({
1222
- id: action.id || nextId(),
1223
- type: action.type || "tap",
1224
- timestamp: action.timestamp || Date.now(),
1225
- description: action.description || action.type || "Action",
1226
- x: action.x,
1227
- y: action.y,
1228
- endX: action.endX,
1229
- endY: action.endY,
1230
- text: action.text,
1231
- direction: action.direction,
1232
- seconds: action.seconds,
1233
- appId: action.appId,
1234
- duration: action.duration,
1235
- screenshotPath: action.screenshotPath
1236
- });
1237
- };
1238
- for (const line of lines) {
1239
- const trimmed = line.trim();
1240
- if (trimmed.startsWith("#") || trimmed === "" || trimmed === "---") {
1241
- continue;
1242
- }
1243
- if (trimmed.startsWith("appId:")) {
1244
- const parsedAppId = cleanValue(trimmed.replace("appId:", ""));
1245
- if (this.session && parsedAppId && !this.session.appId) {
1246
- this.session.appId = parsedAppId;
1247
- }
1248
- continue;
1249
- }
1250
- if (trimmed.startsWith("- tapOn:")) {
1251
- const inlineValue = cleanValue(trimmed.replace("- tapOn:", ""));
1252
- if (inlineValue) {
1253
- pushAction({
1254
- type: "tap",
1255
- description: `Tap on "${inlineValue}"`,
1256
- text: inlineValue
1257
- });
1258
- continue;
1259
- }
1260
- currentAction = { type: "tap", description: "Tap" };
1261
- } else if (trimmed.startsWith("- tap:")) {
1262
- currentAction = { type: "tap", description: "Tap" };
1263
- } else if (trimmed.startsWith("- swipe:")) {
1264
- currentAction = { type: "swipe", description: "Swipe" };
1265
- } else if (trimmed.startsWith("- scroll:")) {
1266
- currentAction = { type: "scroll", description: "Scroll" };
1267
- } else if (trimmed.startsWith("- scrollUntilVisible:")) {
1268
- currentAction = { type: "scroll", description: "Scroll" };
1269
- } else if (trimmed.startsWith("- inputText:")) {
1270
- const text = cleanValue(trimmed.replace("- inputText:", ""));
1271
- pushAction({
1272
- type: "input",
1273
- description: `Input: ${text.slice(0, 20)}${text.length > 20 ? "..." : ""}`,
1274
- text
1275
- });
1276
- continue;
1277
- } else if (trimmed.startsWith("- launchApp:")) {
1278
- const appId = cleanValue(trimmed.replace("- launchApp:", ""));
1279
- pushAction({
1280
- type: "launch",
1281
- description: `Launch: ${appId}`,
1282
- text: appId,
1283
- appId
1284
- });
1285
- continue;
1286
- } else if (trimmed === "- launchApp") {
1287
- pushAction({
1288
- type: "launch",
1289
- description: "Launch app"
1290
- });
1291
- continue;
1292
- } else if (trimmed.startsWith("- assertVisible:")) {
1293
- const inlineValue = cleanValue(trimmed.replace("- assertVisible:", ""));
1294
- if (inlineValue) {
1295
- pushAction({
1296
- type: "assert",
1297
- description: `Assert visible "${inlineValue}"`,
1298
- text: inlineValue
1299
- });
1300
- continue;
1301
- }
1302
- currentAction = { type: "assert", description: "Assert visible" };
1303
- } else if (trimmed.startsWith("- extendedWaitUntil:")) {
1304
- currentAction = { type: "wait", description: "Wait" };
1305
- } else if (trimmed.startsWith("- pressKey:")) {
1306
- const key = cleanValue(trimmed.replace("- pressKey:", "")).toLowerCase();
1307
- if (key === "back") {
1308
- pushAction({ type: "back", description: "Back button" });
1309
- } else if (key === "home") {
1310
- pushAction({ type: "home", description: "Home button" });
1311
- } else {
1312
- pushAction({
1313
- type: "pressKey",
1314
- description: `Press: ${key}`,
1315
- text: key
1316
- });
1317
- }
1318
- continue;
1319
- } else if (trimmed.startsWith("- back")) {
1320
- pushAction({ type: "back", description: "Back button" });
1321
- continue;
1322
- }
1323
- if (currentAction && trimmed.startsWith("point:")) {
1324
- const point = cleanValue(trimmed.replace("point:", ""));
1325
- const [x, y] = point.split(",").map((n) => parseInt(n.trim()));
1326
- if (!isNaN(x) && !isNaN(y)) {
1327
- currentAction.x = x;
1328
- currentAction.y = y;
1329
- currentAction.description = `Tap at (${x}, ${y})`;
1330
- pushAction(currentAction);
1331
- currentAction = null;
1332
- continue;
1333
- }
1334
- }
1335
- if (currentAction && trimmed.startsWith("text:")) {
1336
- const text = cleanValue(trimmed.replace("text:", ""));
1337
- currentAction.text = text;
1338
- if (currentAction.type === "assert") {
1339
- currentAction.description = `Assert visible "${text}"`;
1340
- } else {
1341
- currentAction.description = `Tap on "${text}"`;
1342
- }
1343
- pushAction(currentAction);
1344
- currentAction = null;
1345
- continue;
1346
- }
1347
- if (currentAction && trimmed.startsWith("id:")) {
1348
- const id = cleanValue(trimmed.replace("id:", ""));
1349
- currentAction.text = id;
1350
- currentAction.description = `Tap on id: ${id}`;
1351
- pushAction(currentAction);
1352
- currentAction = null;
1353
- continue;
1354
- }
1355
- if (currentAction && (currentAction.type === "swipe" || currentAction.type === "scroll") && trimmed.startsWith("direction:")) {
1356
- const direction = cleanValue(trimmed.replace("direction:", "")).toLowerCase();
1357
- currentAction.direction = direction;
1358
- currentAction.description = currentAction.type === "swipe" ? `Swipe ${direction}` : `Scroll ${direction}`;
1359
- pushAction(currentAction);
1360
- currentAction = null;
1361
- continue;
1362
- }
1363
- if (currentAction && currentAction.type === "wait" && trimmed.startsWith("timeout:")) {
1364
- const timeoutMs = parseInt(cleanValue(trimmed.replace("timeout:", "")), 10);
1365
- const seconds = Number.isFinite(timeoutMs) && timeoutMs > 0 ? Math.max(1, Math.round(timeoutMs / 1e3)) : 3;
1366
- currentAction.seconds = seconds;
1367
- currentAction.description = `Wait ${seconds}s`;
1368
- pushAction(currentAction);
1369
- currentAction = null;
1370
- continue;
1371
- }
1372
- if (currentAction && currentAction.type === "swipe") {
1373
- if (trimmed.startsWith("start:")) {
1374
- const point = cleanValue(trimmed.replace("start:", ""));
1375
- const [x, y] = point.split(",").map((n) => parseInt(n.trim()));
1376
- if (!isNaN(x) && !isNaN(y)) {
1377
- currentAction.x = x;
1378
- currentAction.y = y;
1379
- }
1380
- } else if (trimmed.startsWith("end:")) {
1381
- const point = cleanValue(trimmed.replace("end:", ""));
1382
- const [x, y] = point.split(",").map((n) => parseInt(n.trim()));
1383
- if (!isNaN(x) && !isNaN(y)) {
1384
- currentAction.endX = x;
1385
- currentAction.endY = y;
1386
- currentAction.description = `Swipe from (${currentAction.x}, ${currentAction.y}) to (${x}, ${y})`;
1387
- pushAction(currentAction);
1388
- currentAction = null;
1389
- }
1390
- }
1391
- }
1503
+ const parsedActions = parseMaestroActionsFromYaml(yamlContent);
1504
+ const appIdMatch = yamlContent.match(/^\s*appId:\s*([^\n#]+)/m);
1505
+ const parsedAppId = appIdMatch?.[1]?.trim().replace(/^["']|["']$/g, "") || "";
1506
+ if (this.session && parsedAppId && !this.session.appId) {
1507
+ this.session.appId = parsedAppId;
1392
1508
  }
1393
- return actions;
1509
+ return parsedActions;
1394
1510
  }
1395
1511
  mergeParsedActionsWithRecorded(parsedActions, recordedActions) {
1396
1512
  if (parsedActions.length === 0) return recordedActions;
@@ -1547,6 +1663,10 @@ function getMaestroRecorder() {
1547
1663
  }
1548
1664
 
1549
1665
  export {
1666
+ isTemplatesInstalled,
1667
+ getAvailableTemplates,
1668
+ getTemplate,
1669
+ getBundlePath,
1550
1670
  findAndroidSdkPath,
1551
1671
  getEmulatorPath,
1552
1672
  getAdbCommand,
@@ -1565,5 +1685,6 @@ export {
1565
1685
  createLoginFlow,
1566
1686
  createOnboardingFlow,
1567
1687
  createNavigationTestFlow,
1688
+ parseMaestroActionsFromYaml,
1568
1689
  getMaestroRecorder
1569
1690
  };