waygraph 0.15.47 → 0.15.50

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 (364) hide show
  1. package/dist/analysis/graph.js +2 -2
  2. package/dist/auto-session/session.js +3 -3
  3. package/dist/cli/discover.d.ts +1 -1
  4. package/dist/cli/discover.js +1 -1
  5. package/dist/cli/flags.d.ts +7 -5
  6. package/dist/cli/flags.js +9 -32
  7. package/dist/cli/run-chain.js +1 -1
  8. package/dist/cli.js +1 -1
  9. package/dist/{agent-dive.js → commands/agent-dive-scaffold.js} +2 -2
  10. package/dist/commands/agent-dive.js +1 -1
  11. package/dist/commands/check.js +1 -1
  12. package/dist/commands/run.js +4 -4
  13. package/dist/commands/session.js +7 -7
  14. package/dist/config.d.ts +34 -0
  15. package/dist/config.js +94 -0
  16. package/dist/{engine/core.js → core/block.js} +6 -6
  17. package/dist/core/blocks/api.d.ts +54 -0
  18. package/dist/core/blocks/api.js +75 -0
  19. package/dist/{engine → core}/blocks/effect.d.ts +1 -1
  20. package/dist/{engine → core}/blocks/effect.js +1 -1
  21. package/dist/{engine → core}/blocks/method.d.ts +1 -1
  22. package/dist/{engine → core}/blocks/method.js +1 -1
  23. package/dist/{engine → core}/blocks/nav.js +1 -1
  24. package/dist/{engine → core}/blocks/page.js +1 -1
  25. package/dist/{engine → core}/branch-regression.js +2 -3
  26. package/dist/{engine → core}/compose.js +4 -4
  27. package/dist/{engine/engine-class.d.ts → core/engine.d.ts} +2 -133
  28. package/dist/core/engine.js +50 -0
  29. package/dist/{engine → core}/flow.js +5 -5
  30. package/dist/core/map-builder.d.ts +171 -0
  31. package/dist/{engine/engine-class.js → core/map-builder.js} +82 -98
  32. package/dist/{engine → core}/run-graph.js +4 -6
  33. package/dist/core.d.ts +14 -0
  34. package/dist/core.js +15 -0
  35. package/dist/env-file.d.ts +10 -0
  36. package/dist/env-file.js +58 -0
  37. package/dist/errors.d.ts +54 -20
  38. package/dist/errors.js +67 -20
  39. package/dist/highlights/run-phase.js +15 -2
  40. package/dist/highlights/stub-ctx.js +16 -0
  41. package/dist/highlights/types.d.ts +38 -0
  42. package/dist/index.d.ts +7 -3
  43. package/dist/index.js +2 -1
  44. package/dist/mem-page.js +2 -2
  45. package/dist/mem-stub.d.ts +1 -1
  46. package/dist/pilot-overlay/fixtures.js +42 -10
  47. package/dist/pilot-overlay/shell.js +23 -10
  48. package/dist/runner/banner-log.js +1 -0
  49. package/dist/runner/device-stage.js +35 -15
  50. package/dist/runner/inpage/banner.d.ts +9 -1
  51. package/dist/runner/inpage/banner.js +27 -2
  52. package/dist/runner/inpage/caption.d.ts +3 -0
  53. package/dist/runner/inpage/caption.js +23 -0
  54. package/dist/runner/inpage/core.js +32 -9
  55. package/dist/runner/inpage/network.d.ts +15 -0
  56. package/dist/runner/inpage/network.js +217 -0
  57. package/dist/runner/inpage/panel-chrome.js +41 -1
  58. package/dist/runner/inpage/swipe-zoom.js +1 -1
  59. package/dist/runner/inpage/todos.js +6 -1
  60. package/dist/runner/main.js +9 -2
  61. package/dist/runner/network-capture.d.ts +9 -0
  62. package/dist/runner/network-capture.js +126 -0
  63. package/dist/runner/overlay-css.js +71 -7
  64. package/dist/runner/overlay-install.js +39 -2
  65. package/dist/runner/overlay-stage.js +5 -0
  66. package/dist/runner/rings.js +69 -45
  67. package/dist/runner/slides.js +14 -8
  68. package/dist/runner/step-mode.js +12 -0
  69. package/dist/runner/step-panels.js +9 -3
  70. package/dist/runner/teardown.js +16 -9
  71. package/dist/session/auto-explore-run.d.ts +5 -2
  72. package/dist/session/auto-explore-run.js +52 -36
  73. package/dist/{step-overlay.d.ts → session/step-overlay.d.ts} +1 -1
  74. package/dist/{step-overlay.js → session/step-overlay.js} +1 -1
  75. package/dist/trait.d.ts +1 -0
  76. package/dist/trait.js +15 -0
  77. package/dist/traverse/run.js +3 -22
  78. package/dist/ui/components/ring.js +4 -2
  79. package/dist/ui/overlay.css +36 -3
  80. package/examples/saucedemo/.waygraph-auto/00d147d1.log +21 -0
  81. package/examples/saucedemo/.waygraph-auto/0402cfcf.log +6 -0
  82. package/examples/saucedemo/.waygraph-auto/062b581f.log +20 -0
  83. package/examples/saucedemo/.waygraph-auto/0681582b.log +6 -0
  84. package/examples/saucedemo/.waygraph-auto/07f3e964.log +6 -0
  85. package/examples/saucedemo/.waygraph-auto/0868ae4d.log +0 -0
  86. package/examples/saucedemo/.waygraph-auto/0924ddaa.log +22 -0
  87. package/examples/saucedemo/.waygraph-auto/092d6173.log +5 -0
  88. package/examples/saucedemo/.waygraph-auto/09924510.log +0 -0
  89. package/examples/saucedemo/.waygraph-auto/0998c941.log +21 -0
  90. package/examples/saucedemo/.waygraph-auto/0bf74300.log +21 -0
  91. package/examples/saucedemo/.waygraph-auto/0c01fd29.log +4 -0
  92. package/examples/saucedemo/.waygraph-auto/0c302590.log +0 -0
  93. package/examples/saucedemo/.waygraph-auto/0dee62d6.log +5 -0
  94. package/examples/saucedemo/.waygraph-auto/0eb4c081.log +5 -0
  95. package/examples/saucedemo/.waygraph-auto/10fd431c.log +0 -0
  96. package/examples/saucedemo/.waygraph-auto/13c6fe3c.log +0 -0
  97. package/examples/saucedemo/.waygraph-auto/1581b677.log +0 -0
  98. package/examples/saucedemo/.waygraph-auto/161cc8dd.log +22 -0
  99. package/examples/saucedemo/.waygraph-auto/164761a5.log +6 -0
  100. package/examples/saucedemo/.waygraph-auto/1905ceb2.log +0 -0
  101. package/examples/saucedemo/.waygraph-auto/1b1d55c6.log +0 -0
  102. package/examples/saucedemo/.waygraph-auto/1b80fd24.log +6 -0
  103. package/examples/saucedemo/.waygraph-auto/1c30a3c2.log +0 -0
  104. package/examples/saucedemo/.waygraph-auto/1d90aa9a.log +0 -0
  105. package/examples/saucedemo/.waygraph-auto/1de7d889.log +0 -0
  106. package/examples/saucedemo/.waygraph-auto/1f233a4c.log +6 -0
  107. package/examples/saucedemo/.waygraph-auto/20e66801.log +0 -0
  108. package/examples/saucedemo/.waygraph-auto/20ffdb77.log +0 -0
  109. package/examples/saucedemo/.waygraph-auto/22048fff.log +4 -0
  110. package/examples/saucedemo/.waygraph-auto/22f1a704.log +5 -0
  111. package/examples/saucedemo/.waygraph-auto/239cced3.log +20 -0
  112. package/examples/saucedemo/.waygraph-auto/25204b46.log +4 -0
  113. package/examples/saucedemo/.waygraph-auto/25e2e90f.log +0 -0
  114. package/examples/saucedemo/.waygraph-auto/2708455e.log +22 -0
  115. package/examples/saucedemo/.waygraph-auto/272a96fd.log +20 -0
  116. package/examples/saucedemo/.waygraph-auto/28d7be5d.log +0 -0
  117. package/examples/saucedemo/.waygraph-auto/2a6a8266.log +6 -0
  118. package/examples/saucedemo/.waygraph-auto/2b3401cf.log +20 -0
  119. package/examples/saucedemo/.waygraph-auto/2ceccd6d.log +0 -0
  120. package/examples/saucedemo/.waygraph-auto/2f1b0c13.log +6 -0
  121. package/examples/saucedemo/.waygraph-auto/2f8d4073.log +6 -0
  122. package/examples/saucedemo/.waygraph-auto/30739278.log +6 -0
  123. package/examples/saucedemo/.waygraph-auto/31cb2e80.log +0 -0
  124. package/examples/saucedemo/.waygraph-auto/322d63cd.log +0 -0
  125. package/examples/saucedemo/.waygraph-auto/3239aa8a.log +6 -0
  126. package/examples/saucedemo/.waygraph-auto/326d87b7.log +6 -0
  127. package/examples/saucedemo/.waygraph-auto/3351c0b6.log +0 -0
  128. package/examples/saucedemo/.waygraph-auto/33df0770.log +0 -0
  129. package/examples/saucedemo/.waygraph-auto/340d624d.log +0 -0
  130. package/examples/saucedemo/.waygraph-auto/36367ccf.log +0 -0
  131. package/examples/saucedemo/.waygraph-auto/372536a5.log +6 -0
  132. package/examples/saucedemo/.waygraph-auto/3a412f3c.log +0 -0
  133. package/examples/saucedemo/.waygraph-auto/3a859bd7.log +0 -0
  134. package/examples/saucedemo/.waygraph-auto/3cb0add7.log +0 -0
  135. package/examples/saucedemo/.waygraph-auto/3e42f0d8.log +0 -0
  136. package/examples/saucedemo/.waygraph-auto/4144071d.log +0 -0
  137. package/examples/saucedemo/.waygraph-auto/4176a3c6.log +0 -0
  138. package/examples/saucedemo/.waygraph-auto/41d0793d.log +4 -0
  139. package/examples/saucedemo/.waygraph-auto/424b4d5d.log +0 -0
  140. package/examples/saucedemo/.waygraph-auto/43253aba.log +0 -0
  141. package/examples/saucedemo/.waygraph-auto/438c6c53.log +22 -0
  142. package/examples/saucedemo/.waygraph-auto/4477db12.log +0 -0
  143. package/examples/saucedemo/.waygraph-auto/4a1258b7.log +0 -0
  144. package/examples/saucedemo/.waygraph-auto/4adcd179.log +20 -0
  145. package/examples/saucedemo/.waygraph-auto/4c9d9b16.log +21 -0
  146. package/examples/saucedemo/.waygraph-auto/4da39c36.log +6 -0
  147. package/examples/saucedemo/.waygraph-auto/4dbefa7e.log +5 -0
  148. package/examples/saucedemo/.waygraph-auto/4efa7035.log +6 -0
  149. package/examples/saucedemo/.waygraph-auto/505affdc.log +4 -0
  150. package/examples/saucedemo/.waygraph-auto/51bcb60a.log +0 -0
  151. package/examples/saucedemo/.waygraph-auto/5291bc78.log +22 -0
  152. package/examples/saucedemo/.waygraph-auto/54274c39.log +5 -0
  153. package/examples/saucedemo/.waygraph-auto/5440ce7e.log +0 -0
  154. package/examples/saucedemo/.waygraph-auto/5738175f.log +22 -0
  155. package/examples/saucedemo/.waygraph-auto/57ce5643.log +22 -0
  156. package/examples/saucedemo/.waygraph-auto/5984426b.log +6 -0
  157. package/examples/saucedemo/.waygraph-auto/5a682e7c.log +22 -0
  158. package/examples/saucedemo/.waygraph-auto/5b79320c.log +21 -0
  159. package/examples/saucedemo/.waygraph-auto/5c55aaac.log +21 -0
  160. package/examples/saucedemo/.waygraph-auto/5d285cd3.log +0 -0
  161. package/examples/saucedemo/.waygraph-auto/5ed00b16.log +4 -0
  162. package/examples/saucedemo/.waygraph-auto/60b9c066.log +6 -0
  163. package/examples/saucedemo/.waygraph-auto/610dd127.log +0 -0
  164. package/examples/saucedemo/.waygraph-auto/61105500.log +5 -0
  165. package/examples/saucedemo/.waygraph-auto/6134afe8.log +20 -0
  166. package/examples/saucedemo/.waygraph-auto/62a0bdc9.log +22 -0
  167. package/examples/saucedemo/.waygraph-auto/6376fc15.log +0 -0
  168. package/examples/saucedemo/.waygraph-auto/6599cbca.log +22 -0
  169. package/examples/saucedemo/.waygraph-auto/67aaca30.log +0 -0
  170. package/examples/saucedemo/.waygraph-auto/68b10298.log +0 -0
  171. package/examples/saucedemo/.waygraph-auto/68be5e12.log +0 -0
  172. package/examples/saucedemo/.waygraph-auto/68df05a6.log +22 -0
  173. package/examples/saucedemo/.waygraph-auto/693f67c4.log +20 -0
  174. package/examples/saucedemo/.waygraph-auto/69ae030a.log +6 -0
  175. package/examples/saucedemo/.waygraph-auto/69e73f35.log +6 -0
  176. package/examples/saucedemo/.waygraph-auto/6b2333b0.log +5 -0
  177. package/examples/saucedemo/.waygraph-auto/6c4c3817.log +0 -0
  178. package/examples/saucedemo/.waygraph-auto/6c954911.log +0 -0
  179. package/examples/saucedemo/.waygraph-auto/6d65a439.log +5 -0
  180. package/examples/saucedemo/.waygraph-auto/6d700055.log +0 -0
  181. package/examples/saucedemo/.waygraph-auto/6ead848f.log +0 -0
  182. package/examples/saucedemo/.waygraph-auto/72675b2d.log +6 -0
  183. package/examples/saucedemo/.waygraph-auto/733dd260.log +5 -0
  184. package/examples/saucedemo/.waygraph-auto/75016486.log +0 -0
  185. package/examples/saucedemo/.waygraph-auto/752b01c6.log +22 -0
  186. package/examples/saucedemo/.waygraph-auto/75675227.log +6 -0
  187. package/examples/saucedemo/.waygraph-auto/75e2e658.log +0 -0
  188. package/examples/saucedemo/.waygraph-auto/76ac1a86.log +0 -0
  189. package/examples/saucedemo/.waygraph-auto/77605295.log +0 -0
  190. package/examples/saucedemo/.waygraph-auto/792671f4.log +22 -0
  191. package/examples/saucedemo/.waygraph-auto/79915adb.log +20 -0
  192. package/examples/saucedemo/.waygraph-auto/7a398774.log +6 -0
  193. package/examples/saucedemo/.waygraph-auto/7a72f66e.log +6 -0
  194. package/examples/saucedemo/.waygraph-auto/7a984334.log +4 -0
  195. package/examples/saucedemo/.waygraph-auto/7c6ee793.log +20 -0
  196. package/examples/saucedemo/.waygraph-auto/7c726dc4.log +22 -0
  197. package/examples/saucedemo/.waygraph-auto/7c72e8a5.log +4 -0
  198. package/examples/saucedemo/.waygraph-auto/7dbee625.log +22 -0
  199. package/examples/saucedemo/.waygraph-auto/7df66956.log +0 -0
  200. package/examples/saucedemo/.waygraph-auto/7e053160.log +0 -0
  201. package/examples/saucedemo/.waygraph-auto/7fcb512f.log +22 -0
  202. package/examples/saucedemo/.waygraph-auto/802a0b5b.log +0 -0
  203. package/examples/saucedemo/.waygraph-auto/80322e0b.log +0 -0
  204. package/examples/saucedemo/.waygraph-auto/80a4978e.log +6 -0
  205. package/examples/saucedemo/.waygraph-auto/81cfe480.log +22 -0
  206. package/examples/saucedemo/.waygraph-auto/832f5add.log +0 -0
  207. package/examples/saucedemo/.waygraph-auto/8337b6ad.log +0 -0
  208. package/examples/saucedemo/.waygraph-auto/8493928e.log +0 -0
  209. package/examples/saucedemo/.waygraph-auto/84dc6480.log +6 -0
  210. package/examples/saucedemo/.waygraph-auto/853bde43.log +0 -0
  211. package/examples/saucedemo/.waygraph-auto/86350ea6.log +22 -0
  212. package/examples/saucedemo/.waygraph-auto/86bb598a.log +0 -0
  213. package/examples/saucedemo/.waygraph-auto/86d09876.log +22 -0
  214. package/examples/saucedemo/.waygraph-auto/878ad01b.log +4 -0
  215. package/examples/saucedemo/.waygraph-auto/87c88ba5.log +0 -0
  216. package/examples/saucedemo/.waygraph-auto/87cb80ff.log +0 -0
  217. package/examples/saucedemo/.waygraph-auto/880b2e78.log +6 -0
  218. package/examples/saucedemo/.waygraph-auto/88527936.log +5 -0
  219. package/examples/saucedemo/.waygraph-auto/88eda676.log +0 -0
  220. package/examples/saucedemo/.waygraph-auto/893023ea.log +5 -0
  221. package/examples/saucedemo/.waygraph-auto/89416718.log +0 -0
  222. package/examples/saucedemo/.waygraph-auto/8996a857.log +6 -0
  223. package/examples/saucedemo/.waygraph-auto/8a08b68d.log +6 -0
  224. package/examples/saucedemo/.waygraph-auto/8a64ba0f.log +6 -0
  225. package/examples/saucedemo/.waygraph-auto/8b1cc2aa.log +6 -0
  226. package/examples/saucedemo/.waygraph-auto/8b73d13e.log +6 -0
  227. package/examples/saucedemo/.waygraph-auto/8d9e5cd2.log +21 -0
  228. package/examples/saucedemo/.waygraph-auto/8ec7d260.log +0 -0
  229. package/examples/saucedemo/.waygraph-auto/8ed43279.log +0 -0
  230. package/examples/saucedemo/.waygraph-auto/93acae32.log +5 -0
  231. package/examples/saucedemo/.waygraph-auto/96321a08.log +0 -0
  232. package/examples/saucedemo/.waygraph-auto/9742b6c2.log +6 -0
  233. package/examples/saucedemo/.waygraph-auto/99cc93eb.log +6 -0
  234. package/examples/saucedemo/.waygraph-auto/9cbfbedc.log +0 -0
  235. package/examples/saucedemo/.waygraph-auto/9dc147d2.log +22 -0
  236. package/examples/saucedemo/.waygraph-auto/a215a395.log +22 -0
  237. package/examples/saucedemo/.waygraph-auto/a23b7086.log +4 -0
  238. package/examples/saucedemo/.waygraph-auto/a35bd5ec.log +0 -0
  239. package/examples/saucedemo/.waygraph-auto/a68995e9.log +22 -0
  240. package/examples/saucedemo/.waygraph-auto/a6e4f936.log +22 -0
  241. package/examples/saucedemo/.waygraph-auto/a7da862b.log +0 -0
  242. package/examples/saucedemo/.waygraph-auto/a82e2a48.log +0 -0
  243. package/examples/saucedemo/.waygraph-auto/a952eb91.log +0 -0
  244. package/examples/saucedemo/.waygraph-auto/a9559653.log +5 -0
  245. package/examples/saucedemo/.waygraph-auto/aa478de2.log +0 -0
  246. package/examples/saucedemo/.waygraph-auto/ac350fc7.log +20 -0
  247. package/examples/saucedemo/.waygraph-auto/acc1b63a.log +0 -0
  248. package/examples/saucedemo/.waygraph-auto/ad12d191.log +0 -0
  249. package/examples/saucedemo/.waygraph-auto/b04638f4.log +6 -0
  250. package/examples/saucedemo/.waygraph-auto/b48863e5.log +22 -0
  251. package/examples/saucedemo/.waygraph-auto/b56968e1.log +6 -0
  252. package/examples/saucedemo/.waygraph-auto/b64e0620.log +20 -0
  253. package/examples/saucedemo/.waygraph-auto/b86a6218.log +6 -0
  254. package/examples/saucedemo/.waygraph-auto/b8e9e956.log +22 -0
  255. package/examples/saucedemo/.waygraph-auto/b9b310ff.log +21 -0
  256. package/examples/saucedemo/.waygraph-auto/bc111745.log +22 -0
  257. package/examples/saucedemo/.waygraph-auto/bf7a77a2.log +0 -0
  258. package/examples/saucedemo/.waygraph-auto/c0d6f353.log +21 -0
  259. package/examples/saucedemo/.waygraph-auto/c0febcf2.log +20 -0
  260. package/examples/saucedemo/.waygraph-auto/c4c52998.log +6 -0
  261. package/examples/saucedemo/.waygraph-auto/c809ceb4.log +22 -0
  262. package/examples/saucedemo/.waygraph-auto/ca6de7e7.log +0 -0
  263. package/examples/saucedemo/.waygraph-auto/ca8561bc.log +0 -0
  264. package/examples/saucedemo/.waygraph-auto/cb86d45b.log +0 -0
  265. package/examples/saucedemo/.waygraph-auto/cb9a1978.log +6 -0
  266. package/examples/saucedemo/.waygraph-auto/cbbc689c.log +6 -0
  267. package/examples/saucedemo/.waygraph-auto/cd88364b.log +0 -0
  268. package/examples/saucedemo/.waygraph-auto/cd919e1d.log +0 -0
  269. package/examples/saucedemo/.waygraph-auto/cfff9eef.log +20 -0
  270. package/examples/saucedemo/.waygraph-auto/d0f59b21.log +4 -0
  271. package/examples/saucedemo/.waygraph-auto/d1195079.log +20 -0
  272. package/examples/saucedemo/.waygraph-auto/d2ef067a.log +5 -0
  273. package/examples/saucedemo/.waygraph-auto/d425471f.log +6 -0
  274. package/examples/saucedemo/.waygraph-auto/d5293921.log +0 -0
  275. package/examples/saucedemo/.waygraph-auto/d62a22c2.log +21 -0
  276. package/examples/saucedemo/.waygraph-auto/d6d1761f.log +22 -0
  277. package/examples/saucedemo/.waygraph-auto/d6d5f411.log +22 -0
  278. package/examples/saucedemo/.waygraph-auto/d6df2771.log +6 -0
  279. package/examples/saucedemo/.waygraph-auto/d7075012.log +21 -0
  280. package/examples/saucedemo/.waygraph-auto/d9ddc297.log +0 -0
  281. package/examples/saucedemo/.waygraph-auto/db4ac845.log +0 -0
  282. package/examples/saucedemo/.waygraph-auto/db6d7774.log +0 -0
  283. package/examples/saucedemo/.waygraph-auto/db839827.log +5 -0
  284. package/examples/saucedemo/.waygraph-auto/dde5e859.log +22 -0
  285. package/examples/saucedemo/.waygraph-auto/de8cac58.log +0 -0
  286. package/examples/saucedemo/.waygraph-auto/dedfcb18.log +0 -0
  287. package/examples/saucedemo/.waygraph-auto/def4d9b1.log +0 -0
  288. package/examples/saucedemo/.waygraph-auto/e1549e40.log +0 -0
  289. package/examples/saucedemo/.waygraph-auto/e1b0676d.log +21 -0
  290. package/examples/saucedemo/.waygraph-auto/e5111463.log +0 -0
  291. package/examples/saucedemo/.waygraph-auto/e5fc1d7c.log +5 -0
  292. package/examples/saucedemo/.waygraph-auto/e6fd2202.log +0 -0
  293. package/examples/saucedemo/.waygraph-auto/edaa806d.log +0 -0
  294. package/examples/saucedemo/.waygraph-auto/edaf33de.log +0 -0
  295. package/examples/saucedemo/.waygraph-auto/edd40cbb.log +20 -0
  296. package/examples/saucedemo/.waygraph-auto/eddfbffc.log +6 -0
  297. package/examples/saucedemo/.waygraph-auto/ee9fa1ad.log +5 -0
  298. package/examples/saucedemo/.waygraph-auto/ef319474.log +22 -0
  299. package/examples/saucedemo/.waygraph-auto/f28eee8d.log +0 -0
  300. package/examples/saucedemo/.waygraph-auto/f33bde90.log +0 -0
  301. package/examples/saucedemo/.waygraph-auto/f6ba7cb4.log +6 -0
  302. package/examples/saucedemo/.waygraph-auto/f7ac4d62.log +20 -0
  303. package/examples/saucedemo/.waygraph-auto/f929bb79.log +0 -0
  304. package/examples/saucedemo/.waygraph-auto/f92d4c6c.log +22 -0
  305. package/examples/saucedemo/.waygraph-auto/f92faf40.log +5 -0
  306. package/examples/saucedemo/.waygraph-auto/fa784369.log +21 -0
  307. package/examples/saucedemo/.waygraph-auto/fb55f723.log +20 -0
  308. package/examples/saucedemo/.waygraph-auto/fba3b738.log +0 -0
  309. package/examples/saucedemo/.waygraph-auto/fdf66b74.log +0 -0
  310. package/examples/saucedemo/.waygraph-auto/ffdf2854.log +6 -0
  311. package/examples/saucedemo/README.md +13 -2
  312. package/examples/saucedemo/package.json +4 -0
  313. package/examples/saucedemo/src/flows/api-demo.flow.ts +37 -0
  314. package/examples/saucedemo/src/flows/checkout.flow.ts +34 -11
  315. package/package.json +5 -3
  316. package/templates/scaffold/src/flows/shop.flow.ts +42 -27
  317. package/dist/auto-explore-run.d.ts +0 -37
  318. package/dist/auto-explore-run.js +0 -670
  319. package/dist/auto-explore.d.ts +0 -57
  320. package/dist/auto-explore.js +0 -376
  321. package/dist/auto-session-ipc.d.ts +0 -150
  322. package/dist/auto-session-ipc.js +0 -497
  323. package/dist/block-inject.d.ts +0 -15
  324. package/dist/block-inject.js +0 -91
  325. package/dist/browser.d.ts +0 -15
  326. package/dist/browser.js +0 -29
  327. package/dist/coverage-gap.d.ts +0 -11
  328. package/dist/coverage-gap.js +0 -119
  329. package/dist/engine.d.ts +0 -12
  330. package/dist/engine.js +0 -13
  331. package/dist/graph.d.ts +0 -92
  332. package/dist/graph.js +0 -467
  333. package/dist/highlight-shorthand.d.ts +0 -24
  334. package/dist/highlight-shorthand.js +0 -30
  335. package/dist/map-check.d.ts +0 -18
  336. package/dist/map-check.js +0 -140
  337. package/dist/overlay-beacon.d.ts +0 -44
  338. package/dist/overlay-beacon.js +0 -85
  339. package/dist/pilot.d.ts +0 -54
  340. package/dist/pilot.js +0 -80
  341. package/dist/practices-check.d.ts +0 -14
  342. package/dist/practices-check.js +0 -195
  343. package/dist/traverse-coverage.d.ts +0 -59
  344. package/dist/traverse-coverage.js +0 -127
  345. package/dist/traverse-lease.d.ts +0 -18
  346. package/dist/traverse-lease.js +0 -62
  347. package/dist/traverse-run.d.ts +0 -47
  348. package/dist/traverse-run.js +0 -439
  349. package/dist/ui/compose.d.ts +0 -4
  350. package/dist/ui/compose.js +0 -7
  351. /package/dist/{verbose-log.d.ts → auto-session/verbose-log.d.ts} +0 -0
  352. /package/dist/{verbose-log.js → auto-session/verbose-log.js} +0 -0
  353. /package/dist/{agent-dive.d.ts → commands/agent-dive-scaffold.d.ts} +0 -0
  354. /package/dist/{engine/core.d.ts → core/block.d.ts} +0 -0
  355. /package/dist/{engine → core}/blocks/nav.d.ts +0 -0
  356. /package/dist/{engine → core}/blocks/page.d.ts +0 -0
  357. /package/dist/{engine → core}/branch-regression.d.ts +0 -0
  358. /package/dist/{engine → core}/compose.d.ts +0 -0
  359. /package/dist/{engine → core}/config.d.ts +0 -0
  360. /package/dist/{engine → core}/config.js +0 -0
  361. /package/dist/{engine → core}/flow.d.ts +0 -0
  362. /package/dist/{engine → core}/locate.d.ts +0 -0
  363. /package/dist/{engine → core}/locate.js +0 -0
  364. /package/dist/{engine → core}/run-graph.d.ts +0 -0
@@ -0,0 +1,126 @@
1
+ // Real page network traffic -> the same network-tab overlay defineApiBlock's own calls use (see
2
+ // inpage/network.js's own header). Playwright's page.on('request'/'requestfinished') events cover
3
+ // every real request the PAGE makes (XHR/fetch/navigation) - not page.request.get()-style calls,
4
+ // which go through a separate APIRequestContext entirely and never touch the browser at all (that
5
+ // side is covered by defineApiBlock's own explicit call, in src/core/blocks/api.ts).
6
+ import { addNetworkEntry, clearNetworkLog } from "./inpage/network.js";
7
+
8
+ // Fetch/XHR/navigation only - a real page can fire dozens of image/font/stylesheet requests per
9
+ // second, which would flood a panel meant to answer "what API calls did this page just made".
10
+ const RELEVANT_TYPES = new Set(["xhr", "fetch", "document"]);
11
+ // Response bodies this size or smaller, and only if they look text-ish, get captured for the
12
+ // detail view - a multi-MB image/video response has no business being buffered into page memory
13
+ // just because a demo happened to be running.
14
+ const MAX_BODY_BYTES = 200_000;
15
+ // Matches the in-page addNetworkEntry's own cap (network.js) - the Node-side history this backs
16
+ // stays in sync with what the panel can actually show.
17
+ const MAX_HISTORY = 30;
18
+
19
+ /**
20
+ * Records one entry AND paints it live - the single place that touches page.__wgNetworkHistory,
21
+ * so every caller (this file's own listeners, defineApiBlock) stays in sync automatically. History
22
+ * lives on the Playwright `Page` object (Node side), which survives navigation - the panel DOM
23
+ * (page side, inside the shadow root) does not, and gets wiped on every real navigation. Without
24
+ * this, the "network tab" reset to empty on every step that navigated - not what a persistent
25
+ * Network tab is supposed to do.
26
+ */
27
+ export function recordNetworkEntry(page, entry) {
28
+ page.__wgNetworkHistory = page.__wgNetworkHistory || [];
29
+ page.__wgNetworkHistory.push(entry);
30
+ while (page.__wgNetworkHistory.length > MAX_HISTORY) page.__wgNetworkHistory.shift();
31
+ return page.evaluate(addNetworkEntry, entry).catch(() => {});
32
+ }
33
+
34
+ /**
35
+ * Replays whatever history survived the last navigation back into a freshly (re)installed panel -
36
+ * call this after ensureShadowRoot, every step, same as the rest of the overlay's own per-step
37
+ * resync (banner/todos/device), and BEFORE that step's own network activity can add anything new
38
+ * (installOverlay runs at the very start of a step, so this is always true in practice - no
39
+ * interleaving race between "replay old" and "record new" to reason about). A no-op when there's
40
+ * no history yet, or the panel already shows exactly as many entries as history has (nothing was
41
+ * wiped this step). Otherwise clears and rebuilds from scratch, in order - simpler and more
42
+ * obviously correct than trying to diff/append just the "missing" ones.
43
+ */
44
+ export async function restoreNetworkHistory(page) {
45
+ const history = page.__wgNetworkHistory;
46
+ if (!history || history.length === 0) return;
47
+ // page.__wgNetworkNeedsRestore is set by installNetworkCapture's own framenavigated listener -
48
+ // skip the page.evaluate() round-trip entirely (an extra one on EVERY step otherwise, since this
49
+ // runs from installOverlay every step) unless a real navigation actually happened since the last
50
+ // successful restore. A real, caught perf regression: this used to always evaluate() a shown-count
51
+ // check first, which measurably slowed down every step of every test that had ever captured any
52
+ // traffic at all, not just ones that navigate.
53
+ if (!page.__wgNetworkNeedsRestore) return;
54
+ page.__wgNetworkNeedsRestore = false;
55
+ await page.evaluate(clearNetworkLog).catch(() => {});
56
+ for (const entry of history) {
57
+ await page.evaluate(addNetworkEntry, entry).catch(() => {});
58
+ }
59
+ }
60
+
61
+ export function installNetworkCapture(page) {
62
+ if (page.__wgNetworkCaptureInstalled) return;
63
+ page.__wgNetworkCaptureInstalled = true;
64
+
65
+ // Marks history as needing a replay - see restoreNetworkHistory's own comment. Main frame only;
66
+ // an iframe navigating doesn't wipe the top-level shadow root the panel lives in.
67
+ page.on("framenavigated", (frame) => {
68
+ if (frame === page.mainFrame()) page.__wgNetworkNeedsRestore = true;
69
+ });
70
+
71
+ const startedAt = new Map();
72
+
73
+ page.on("request", (request) => {
74
+ startedAt.set(request, Date.now());
75
+ });
76
+
77
+ page.on("requestfinished", async (request) => {
78
+ try {
79
+ if (!RELEVANT_TYPES.has(request.resourceType())) return;
80
+ const response = await request.response();
81
+ if (!response) return;
82
+ const start = startedAt.get(request);
83
+ startedAt.delete(request);
84
+ let resBody;
85
+ try {
86
+ const contentType = (await response.headerValue("content-type")) || "";
87
+ if (/json|text|xml|html|javascript/.test(contentType)) {
88
+ const buf = await response.body();
89
+ if (buf.length <= MAX_BODY_BYTES) resBody = buf.toString("utf8");
90
+ }
91
+ } catch {
92
+ /* body already consumed / redirected away / not available - best-effort only */
93
+ }
94
+ const [reqHeaders, resHeaders] = await Promise.all([
95
+ request.allHeaders().catch(() => undefined),
96
+ response.allHeaders().catch(() => undefined),
97
+ ]);
98
+ await recordNetworkEntry(page, {
99
+ method: request.method(),
100
+ url: request.url(),
101
+ status: response.status(),
102
+ ok: response.ok(),
103
+ ms: start !== undefined ? Date.now() - start : undefined,
104
+ reqHeaders,
105
+ resHeaders,
106
+ reqBody: request.postData() || undefined,
107
+ resBody,
108
+ });
109
+ } catch {
110
+ /* a capture failure must never break the actual run it's observing */
111
+ }
112
+ });
113
+
114
+ page.on("requestfailed", (request) => {
115
+ startedAt.delete(request);
116
+ if (!RELEVANT_TYPES.has(request.resourceType())) return;
117
+ recordNetworkEntry(page, {
118
+ method: request.method(),
119
+ url: request.url(),
120
+ status: 0,
121
+ ok: false,
122
+ reqBody: request.postData() || undefined,
123
+ resBody: request.failure() ? request.failure().errorText : undefined,
124
+ });
125
+ });
126
+ }
@@ -80,7 +80,7 @@ export const RUNNER_EXTRA_CSS =
80
80
  // Todo checklist(s) float outside #wg-panel so --mini / Hide never hide them.
81
81
  // Multiple docks (one per todoId) are supported - stacked on the same side.
82
82
  // Click a dock to slide left <-> right (WAYGRAPH_TODO_POS / --todo-left|right).
83
- ".wg-todo-dock,#wg-todo-dock{position:fixed;z-index:2147483646;top:72px;left:14px;" +
83
+ ".wg-todo-dock,#wg-todo-dock{position:fixed;z-index:2147483646;top:104px;left:14px;" +
84
84
  "width:min(280px,42vw);max-height:calc(100vh - 100px);overflow:auto;box-sizing:border-box;" +
85
85
  "padding:10px 12px;background:" + SURFACE + ";color:#fff;border-radius:12px;" +
86
86
  "border:1px solid rgba(124,58,237,.45);box-shadow:0 8px 24px rgba(0,0,0,.35);" +
@@ -102,18 +102,74 @@ export const RUNNER_EXTRA_CSS =
102
102
  ".wg-todo-dock .wg-todo-dock-title{font:700 11px/1.2 system-ui,sans-serif;color:#c9a6ff;" +
103
103
  "letter-spacing:.04em;text-transform:uppercase;margin:0 0 8px;}" +
104
104
  ".wg-todo-dock .wg-todos-list,#wg-todo-dock #wg-todos,.wg-todo-dock #wg-todos{list-style:none;margin:0;padding:0;background:transparent;border:none;}" +
105
- // Always-on zoom HUD - bottom-right (top-left is crowded: todos + banners).
105
+ // Always-on zoom HUD - bottom-right (top-left is crowded: todos + banners). Violet, matching the
106
+ // rest of the overlay's design tokens - this used to be a lone amber/yellow badge, the one
107
+ // surface that never got pulled into the shared palette when everything else did.
106
108
  "#wg-zoom-badge{position:fixed;z-index:2147483646;bottom:14px;right:14px;" +
107
109
  "display:flex;align-items:center;gap:7px;padding:6px 11px 6px 8px;" +
108
110
  "border-radius:999px;background:" + SURFACE + ";color:#f0e8ff;" +
109
- "border:1px solid rgba(250,204,21,.6);box-shadow:0 6px 18px rgba(0,0,0,.4);" +
111
+ "border:1px solid rgba(124,58,237,.55);box-shadow:0 6px 18px rgba(0,0,0,.4);" +
110
112
  "font:700 12px/1.2 system-ui,sans-serif;pointer-events:none;" +
111
113
  "opacity:1;transform:translateY(0);}" +
112
114
  "#wg-zoom-badge .wg-zoom-ico{width:18px;height:18px;display:flex;align-items:center;justify-content:center;" +
113
- "border-radius:6px;background:rgba(250,204,21,.22);}" +
115
+ "border-radius:6px;background:rgba(124,58,237,.28);}" +
114
116
  "#wg-zoom-badge .wg-zoom-ico svg{width:14px;height:14px;display:block;}" +
115
- "#wg-zoom-badge .wg-zoom-val{color:#fde68a;font-variant-numeric:tabular-nums;font-weight:800;min-width:3.2em;}" +
116
- "#wg-zoom-badge[data-zoomed=\"1\"]{border-color:#fbbf24;}" +
117
+ "#wg-zoom-badge .wg-zoom-val{color:#c9a6ff;font-variant-numeric:tabular-nums;font-weight:800;min-width:3.2em;}" +
118
+ "#wg-zoom-badge[data-zoomed=\"1\"]{border-color:#7C3AED;}" +
119
+ // Network-tab overlay (real page traffic via network-capture.js + defineApiBlock's own
120
+ // page.request calls) - bottom-left, the one corner free of the zoom HUD (bottom-right) and the
121
+ // typing chip (bottom-center). Persistent (does not auto-fade) once any entry exists - this is a
122
+ // real Postman/DevTools-style inspector meant to be reviewed, not a flash-and-gone toast.
123
+ "#wg-network-log{position:fixed;z-index:2147483646;bottom:14px;left:14px;min-width:260px;" +
124
+ "max-width:min(92vw,420px);max-height:min(60vh,420px);display:flex;flex-direction:column;" +
125
+ "border-radius:10px;background:" + SURFACE + ";color:#f0e8ff;border:1px solid rgba(124,58,237,.45);" +
126
+ "box-shadow:0 8px 22px rgba(0,0,0,.4);font:12px/1.4 ui-monospace,\"SF Mono\",Consolas,monospace;" +
127
+ "opacity:0;transform:translateY(8px);transition:opacity .25s ease,transform .25s ease;overflow:hidden;}" +
128
+ "#wg-network-log.wg-in{opacity:1;transform:translateY(0);}" +
129
+ "#wg-network-log.wg-net-collapsed .wg-net-list{display:none;}" +
130
+ "#wg-network-log .wg-net-header{display:flex;align-items:center;gap:6px;padding:8px 10px;" +
131
+ "border-bottom:1px solid rgba(124,58,237,.25);cursor:default;flex:0 0 auto;}" +
132
+ "#wg-network-log .wg-net-title{font:700 10px/1.2 system-ui,sans-serif;color:#c9a6ff;" +
133
+ "letter-spacing:.06em;text-transform:uppercase;flex:1 1 auto;}" +
134
+ "#wg-network-log .wg-net-count{font:700 10px/1.2 system-ui,sans-serif;color:#9CA3AF;" +
135
+ "background:rgba(124,58,237,.22);border-radius:999px;padding:1px 7px;}" +
136
+ "#wg-network-log .wg-net-collapse{flex:0 0 auto;width:18px;height:18px;border-radius:5px;border:none;" +
137
+ "background:rgba(124,58,237,.28);color:#e8dcff;font:700 13px/1 system-ui,sans-serif;cursor:pointer;" +
138
+ "pointer-events:auto;}" +
139
+ "#wg-network-log .wg-net-collapse:hover{background:rgba(124,58,237,.42);}" +
140
+ "#wg-network-log .wg-net-list{list-style:none;margin:0;padding:6px 8px;display:flex;" +
141
+ "flex-direction:column;gap:2px;overflow-y:auto;pointer-events:auto;}" +
142
+ "#wg-network-log .wg-net-row{display:flex;align-items:baseline;gap:7px;opacity:0;padding:3px 4px;" +
143
+ "border-radius:5px;cursor:pointer;transform:translateX(-4px);transition:opacity .2s ease,transform .2s ease;}" +
144
+ "#wg-network-log .wg-net-row:hover,#wg-network-log .wg-net-row.wg-net-open{background:rgba(124,58,237,.18);}" +
145
+ "#wg-network-log .wg-net-row.wg-in{opacity:1;transform:translateX(0);}" +
146
+ "#wg-network-log .wg-net-method{flex:0 0 auto;font-weight:800;font-size:10px;min-width:38px;}" +
147
+ "#wg-network-log .wg-net-method-get{color:#3B82F6;}" +
148
+ "#wg-network-log .wg-net-method-post{color:#22C55E;}" +
149
+ "#wg-network-log .wg-net-method-put{color:#F97316;}" +
150
+ "#wg-network-log .wg-net-method-delete{color:#EF4444;}" +
151
+ "#wg-network-log .wg-net-method-other{color:#9CA3AF;}" +
152
+ "#wg-network-log .wg-net-path{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;" +
153
+ "white-space:nowrap;color:#e0e0f0;}" +
154
+ "#wg-network-log .wg-net-status{flex:0 0 auto;font-weight:700;color:#22C55E;}" +
155
+ "#wg-network-log .wg-net-row[data-ok=\"0\"] .wg-net-status{color:#EF4444;}" +
156
+ "#wg-network-log .wg-net-ms{flex:0 0 auto;color:#9CA3AF;font-size:10px;}" +
157
+ "#wg-network-log .wg-net-detail{list-style:none;background:rgba(0,0,0,.28);border-radius:6px;" +
158
+ "padding:8px;margin:2px 0 6px;}" +
159
+ "#wg-network-log .wg-net-detail-section{margin-bottom:8px;}" +
160
+ "#wg-network-log .wg-net-detail-section:last-child{margin-bottom:0;}" +
161
+ "#wg-network-log .wg-net-detail-section h4{margin:0 0 4px;font:700 9px/1.2 system-ui,sans-serif;" +
162
+ "color:#9CA3AF;letter-spacing:.06em;text-transform:uppercase;}" +
163
+ "#wg-network-log .wg-net-headers{width:100%;border-collapse:collapse;font-size:11px;}" +
164
+ "#wg-network-log .wg-net-headers td{padding:1px 6px 1px 0;vertical-align:top;word-break:break-all;}" +
165
+ "#wg-network-log .wg-net-headers td:first-child{color:#c9a6ff;white-space:nowrap;}" +
166
+ "#wg-network-log .wg-net-body{margin:0;font-size:11px;white-space:pre-wrap;word-break:break-all;" +
167
+ "max-height:160px;overflow-y:auto;color:#e0e0f0;}" +
168
+ "#wg-network-log .wg-net-curl{color:#7dd3fc;}" +
169
+ "#wg-network-log .wg-net-empty{font-size:11px;color:#6b7280;font-style:italic;}" +
170
+ "#wg-network-log .wg-net-copy{margin-top:5px;padding:3px 9px;border-radius:5px;border:1px solid rgba(124,58,237,.5);" +
171
+ "background:rgba(124,58,237,.22);color:#e8dcff;font:700 10px system-ui,sans-serif;cursor:pointer;}" +
172
+ "#wg-network-log .wg-net-copy:hover{background:rgba(124,58,237,.38);}" +
117
173
  // Typing chip (method fills: username / password / etc.)
118
174
  "#wg-typing-badge{position:fixed;z-index:2147483646;bottom:88px;left:50%;transform:translateX(-50%);" +
119
175
  "display:flex;align-items:center;gap:8px;padding:8px 14px;" +
@@ -254,7 +310,15 @@ export const RUNNER_EXTRA_CSS =
254
310
  // Hide / Show chrome: collapsed = compact "N / M · block" pill + Next (manual).
255
311
  "#wg-panel .wg-chrome{display:flex;align-items:center;justify-content:space-between;gap:8px;margin:0 0 8px;}" +
256
312
  "#wg-panel .wg-chrome-title{font:700 11px/1.2 system-ui,sans-serif;color:#c9a6ff;" +
257
- "letter-spacing:.04em;text-transform:uppercase;flex:1;min-width:0;}" +
313
+ "letter-spacing:.04em;text-transform:uppercase;flex:1;min-width:0;display:flex;align-items:center;gap:4px;}" +
314
+ // Animated fast-forward indicator on the collapsed bottom-center pill - a blitzed/FF step has
315
+ // no ring, no narration theater, nothing else visible marking it as different, so it read as
316
+ // just another normal step with no explanation for why it snapped past instantly.
317
+ "#wg-panel .wg-ff-icon{display:inline-flex;align-items:center;flex-shrink:0;width:13px;height:13px;}" +
318
+ "#wg-panel .wg-ff-icon svg{width:100%;height:100%;display:block;}" +
319
+ "#wg-panel .wg-ff-icon .wg-ff-chev{animation:wg-ff-pulse 900ms ease-in-out infinite;}" +
320
+ "#wg-panel .wg-ff-icon .wg-ff-chev:nth-child(2){animation-delay:150ms;}" +
321
+ "@keyframes wg-ff-pulse{0%,100%{opacity:.3;transform:translateX(-1.5px);}50%{opacity:1;transform:translateX(1.5px);}}" +
258
322
  "#wg-panel .wg-chrome-actions{display:flex;align-items:center;gap:6px;flex-shrink:0;}" +
259
323
  "#wg-panel button.wg-hide-btn,#wg-panel button.wg-mini-next{margin:0;padding:4px 10px;font:600 11px system-ui,sans-serif;" +
260
324
  "background:#3a2a60;color:#e8dcff;border:1px solid #5b3aa8;border-radius:6px;cursor:pointer;}" +
@@ -6,16 +6,46 @@ import { resolveTodoDockUi } from "../highlights.js";
6
6
  import { installCore } from "./inpage/core.js";
7
7
  import { installSwipeZoom } from "./inpage/swipe-zoom.js";
8
8
  import { installBanner } from "./inpage/banner.js";
9
+ import { showCaption, hideCaption } from "./inpage/caption.js";
9
10
  import { installStamp } from "./inpage/stamp.js";
10
11
  import { installPanelChrome } from "./inpage/panel-chrome.js";
11
12
  import { installTodos } from "./inpage/todos.js";
12
13
  import { installDevice } from "./inpage/device.js";
13
14
  import { applyVideoDeviceStage } from "./device-stage.js";
15
+ import { installNetworkCapture, restoreNetworkHistory } from "./network-capture.js";
16
+ import { setNetworkTabVisible } from "./inpage/network.js";
14
17
 
15
- /** `ui` = authored banner UX from the stub phase: { pos, collision, hidden } (all optional). */
16
- export async function installOverlay(page, title, ui) {
18
+ /**
19
+ * `ui` = authored banner UX from the stub phase: { pos, collision, hidden } (all optional).
20
+ * `caption` = bottom subtitle-bar text (ctx.caption()/ctx.hideCaption()) - `undefined` leaves it
21
+ * alone (unset this step), `""` hides it, any other string shows/updates it.
22
+ * `networkTabVisible` = network-tab panel shown/hidden (ctx.showNetworkTab()/hideNetworkTab()) -
23
+ * `undefined` leaves it alone (default state is hidden, set the very first time restoreNetworkHistory
24
+ * builds a panel); capture itself is unconditional and unaffected by this either way.
25
+ */
26
+ export async function installOverlay(page, title, ui, caption, networkTabVisible) {
17
27
  // ring/cursor/banner/dock come from the ONE shared bundle every surface installs (ui/css/*.css).
18
28
  await ensureShadowRoot(page);
29
+ // Idempotent (guarded on page.__wgNetworkCaptureInstalled) - safe to call every step even though
30
+ // installOverlay itself runs every step; the page.on() listeners this installs are attached to
31
+ // the Page object, not any one document, so they already survive navigations on their own.
32
+ installNetworkCapture(page);
33
+ // Visibility is Node-side state too (page.__wgNetworkTabVisible), same reason history is: a
34
+ // navigation wipes window.__wgNetworkTabVisible along with the rest of the page-side JS state,
35
+ // so "shown" would silently revert to the hidden default on the very next navigated step without
36
+ // this. Default false (hidden) - matches addNetworkEntry's own default-hidden behavior.
37
+ if (networkTabVisible !== undefined) page.__wgNetworkTabVisible = !!networkTabVisible;
38
+ await page.evaluate((v) => { window.__wgNetworkTabVisible = v; }, !!page.__wgNetworkTabVisible).catch(() => {});
39
+ // Real bug this fixes: a navigation wipes the shadow root (and with it, the network panel's DOM
40
+ // and in-page entry list) - without replaying page.__wgNetworkHistory (Node-side, survives
41
+ // navigation) back in every step, the "network tab" silently reset to empty on any step that
42
+ // navigated, instead of staying persistent like a real Network tab.
43
+ await restoreNetworkHistory(page);
44
+ // Explicit toggle too, not just the flag write above - covers the case where the panel already
45
+ // existed (no restore ran this step) and this step's `networkTabVisible` differs from before.
46
+ if (networkTabVisible !== undefined) {
47
+ await page.evaluate(setNetworkTabVisible, networkTabVisible).catch(() => {});
48
+ }
19
49
  // Runner-only chrome (step panel, zoom/typing/device chips) - separate key, no collision.
20
50
  await page.evaluate(([css, key]) => __wgCss(css, key), [RUNNER_EXTRA_CSS, "wg-runner-css"]).catch(() => {});
21
51
  await page.addStyleTag({ content: HOST_CSS }).catch(() => {});
@@ -36,6 +66,13 @@ export async function installOverlay(page, title, ui) {
36
66
  await page.evaluate(installPanelChrome, args).catch(() => {});
37
67
  await page.evaluate(installTodos, args).catch(() => {});
38
68
  await page.evaluate(installDevice, args).catch(() => {});
69
+ if (caption !== undefined) {
70
+ if (caption === "") {
71
+ await page.evaluate(hideCaption).catch(() => {});
72
+ } else {
73
+ await page.evaluate(showCaption, caption).catch(() => {});
74
+ }
75
+ }
39
76
  // Navigations wipe #wg-device-shell - rebuild when video stage + device are live.
40
77
  // If we already shuttered to desktop-flat, re-apply FLAT (never re-add bezel).
41
78
  if (
@@ -97,6 +97,11 @@ export function createOverlayStage(page, { todoDockRef, deviceRef }) {
97
97
  deviceRef.current = state.lastDevice;
98
98
  if (appliedDevice.sync !== "keep" || (reapplyDeviceOnKeep && state.lastDevice)) {
99
99
  await applyDeviceToPage(page, state.lastDevice, appliedDevice.sync);
100
+ // A deliberate settle beat: applyDeviceToPage's own viewport lerp is fully awaited above, but
101
+ // a ring/camera-zoom transition kicked off immediately after (the very next thing this step
102
+ // does) reads as happening AT THE SAME TIME as the device change on video, with no visual
103
+ // breathing room between them - two transitions with no gap look like one confused one.
104
+ await new Promise((r) => setTimeout(r, 220));
100
105
  }
101
106
  return { appliedTodo, appliedDevice };
102
107
  };
@@ -207,15 +207,25 @@ export async function cycleHighlightRings(page, highlights, gatesFast, opts) {
207
207
  try {
208
208
  await ensureSelectorInView(page, h.selector);
209
209
  await applyHighlightZoom(page, h.selector, h.zoom, h.zoomOut);
210
- // Prefer live in-page rect (honors device-shell scale) over Playwright box.
211
- const box = await page
212
- .evaluate((sel) => {
213
- const el = document.querySelector(sel);
214
- if (!el) return null;
215
- const r = el.getBoundingClientRect();
216
- return { x: r.x, y: r.y, width: r.width, height: r.height };
217
- }, h.selector)
218
- .catch(() => null);
210
+ // Prefer live in-page rect (honors device-shell scale) over Playwright's own boundingBox() -
211
+ // but resolve the element through Playwright's OWN locator (full selector engine: >>
212
+ // piercing, :has-text(), :visible, ...), not a raw DOM querySelector, which only understands
213
+ // real CSS and silently fails to match any Playwright-specific selector syntax.
214
+ // count() gate: a real, caught regression - Locator.evaluate() has no timeout option and
215
+ // auto-waits (Playwright's default ~30s) for a match to appear, unlike the instant
216
+ // document.querySelector it replaced. count() alone never waits, so this stays an immediate
217
+ // "does it exist right now" check - ensureSelectorInView above already gave the page a real
218
+ // moment to settle.
219
+ const hLoc = page.locator(h.selector).first();
220
+ const box =
221
+ (await hLoc.count().catch(() => 0)) > 0
222
+ ? await hLoc
223
+ .evaluate((el) => {
224
+ const r = el.getBoundingClientRect();
225
+ return { x: r.x, y: r.y, width: r.width, height: r.height };
226
+ })
227
+ .catch(() => null)
228
+ : null;
219
229
  if (box && box.width > 0 && box.height > 0) {
220
230
  await showRing(page, box, h.label, h.tone || "planned", {
221
231
  size: h.size,
@@ -318,44 +328,52 @@ export async function cycleHighlightRings(page, highlights, gatesFast, opts) {
318
328
  }
319
329
  if (list.length > 0) {
320
330
  const last = list[list.length - 1];
331
+ // Resolved through Playwright's own locator (>> piercing / :has-text() / :visible support),
332
+ // not handed to the page as a string for a raw DOM querySelector to fail silently on - see
333
+ // showRing's own comment (same fix, same reason) and __wgFollowRing's in core.js.
334
+ const handle = last.selector
335
+ ? await page.locator(last.selector).first().elementHandle({ timeout: 100 }).catch(() => null)
336
+ : null;
321
337
  await page
322
- .evaluate((h) => {
323
- if (!window.__wgFollowRing && !window.__wgPositionRing) return;
324
- if (window.__wgFollowRing) {
325
- window.__wgFollowRing(
326
- h.selector,
327
- h.label,
328
- h.tone || "planned",
329
- { size: h.size || "md", weight: h.weight || "normal" },
330
- !!h.focus,
331
- );
332
- return;
333
- }
334
- const reposition = () => {
335
- const el = document.querySelector(h.selector);
338
+ .evaluate(
339
+ ({ h, el }) => {
340
+ if (el && window.__wgFollowRing) {
341
+ window.__wgFollowRing(
342
+ el,
343
+ h.label,
344
+ h.tone || "planned",
345
+ { size: h.size || "md", weight: h.weight || "normal" },
346
+ !!h.focus,
347
+ );
348
+ return;
349
+ }
350
+ if (!window.__wgPositionRing) return;
336
351
  if (!el) {
337
352
  if (window.__wgHideRing) window.__wgHideRing();
338
353
  return;
339
354
  }
340
- const box = el.getBoundingClientRect();
341
- window.__wgPositionRing(box, h.label, h.tone || "planned", {
342
- size: h.size || "md",
343
- weight: h.weight || "normal",
344
- });
345
- if (h.focus && window.__wgApplyFocus) {
346
- window.__wgApplyFocus({
347
- x: box.x,
348
- y: box.y,
349
- width: box.width,
350
- height: box.height,
355
+ const reposition = () => {
356
+ const box = el.getBoundingClientRect();
357
+ window.__wgPositionRing(box, h.label, h.tone || "planned", {
358
+ size: h.size || "md",
359
+ weight: h.weight || "normal",
351
360
  });
352
- }
353
- };
354
- reposition();
355
- window.__wgRingTrack = reposition;
356
- window.addEventListener("resize", reposition);
357
- window.addEventListener("scroll", reposition, true);
358
- }, last)
361
+ if (h.focus && window.__wgApplyFocus) {
362
+ window.__wgApplyFocus({
363
+ x: box.x,
364
+ y: box.y,
365
+ width: box.width,
366
+ height: box.height,
367
+ });
368
+ }
369
+ };
370
+ reposition();
371
+ window.__wgRingTrack = reposition;
372
+ window.addEventListener("resize", reposition);
373
+ window.addEventListener("scroll", reposition, true);
374
+ },
375
+ { h: last, el: handle },
376
+ )
359
377
  .catch(() => {});
360
378
  } else {
361
379
  await hideRing(page);
@@ -417,11 +435,17 @@ export async function showRing(page, box, label, tone, style) {
417
435
  const weight = normalizeHighlightWeight(style && style.weight);
418
436
  const selector = style && style.selector ? String(style.selector) : "";
419
437
  const focus = !!(style && style.focus);
438
+ // Resolve through Playwright's own locator (full selector engine), not a selector string handed
439
+ // to the page for a raw DOM lookup - >> piercing / :has-text() / :visible are Playwright-only
440
+ // syntax, invisible to document.querySelector. The resolved element handle is passed straight
441
+ // into evaluate (Playwright unwraps it to the real DOM node inside the page), so __wgFollowRing's
442
+ // per-frame RAF loop tracks that exact element directly - no repeated selector re-resolution.
443
+ const handle = selector ? await page.locator(selector).first().elementHandle({ timeout: 100 }).catch(() => null) : null;
420
444
  await page
421
445
  .evaluate(
422
- ({ box, label, tone, size, weight, selector, focus }) => {
423
- if (selector && window.__wgFollowRing) {
424
- window.__wgFollowRing(selector, label, tone || "planned", { size, weight }, focus);
446
+ ({ box, label, tone, size, weight, el, focus }) => {
447
+ if (el && window.__wgFollowRing) {
448
+ window.__wgFollowRing(el, label, tone || "planned", { size, weight }, focus);
425
449
  return;
426
450
  }
427
451
  if (window.__wgStopRingFollow) window.__wgStopRingFollow();
@@ -431,7 +455,7 @@ export async function showRing(page, box, label, tone, style) {
431
455
  if (focus && box && window.__wgApplyFocus) window.__wgApplyFocus(box);
432
456
  else if (!focus && window.__wgClearFocus) window.__wgClearFocus();
433
457
  },
434
- { box, label, tone: tone || "planned", size, weight, selector, focus },
458
+ { box, label, tone: tone || "planned", size, weight, el: handle, focus },
435
459
  )
436
460
  .catch(() => {});
437
461
  }
@@ -43,14 +43,20 @@ export async function presentSlides(page, slides, _gate, opts) {
43
43
  try {
44
44
  await ensureSelectorInView(page, s.selector);
45
45
  await applyHighlightZoom(page, s.selector, s.zoom, s.zoomOut);
46
- const box = await page
47
- .evaluate((sel) => {
48
- const el = document.querySelector(sel);
49
- if (!el) return null;
50
- const r = el.getBoundingClientRect();
51
- return { x: r.x, y: r.y, width: r.width, height: r.height };
52
- }, s.selector)
53
- .catch(() => null);
46
+ // Playwright's own locator (>> piercing / :has-text() / :visible support), not a raw
47
+ // querySelector string - see rings.js's showRing for the same fix, same reason. count()
48
+ // gate: Locator.evaluate() has no timeout option and auto-waits ~30s for a match to
49
+ // appear - count() never waits, keeping this an immediate "does it exist now" check.
50
+ const sLoc = page.locator(s.selector).first();
51
+ const box =
52
+ (await sLoc.count().catch(() => 0)) > 0
53
+ ? await sLoc
54
+ .evaluate((el) => {
55
+ const r = el.getBoundingClientRect();
56
+ return { x: r.x, y: r.y, width: r.width, height: r.height };
57
+ })
58
+ .catch(() => null)
59
+ : null;
54
60
  if (box && box.width > 0 && box.height > 0) {
55
61
  await showRing(page, box, caption, slideTone, {
56
62
  ...slideStyle,
@@ -342,6 +342,10 @@ export async function runStepMode(engine, start, end, context, page, mem, resolv
342
342
  justEnteredEpisode,
343
343
  title: overlayTitle,
344
344
  bannerUi: stage.state.lastBannerUi,
345
+ caption: stubBeforePhase.caption,
346
+ networkTabVisible: stubBeforePhase.networkTabVisible,
347
+ fastForward: !!r.block.fastForward,
348
+ isApi: r.block.__waygraphKind === "api",
345
349
  todoPos: overlayTodoPos,
346
350
  episodeNumber: r.episodeNumber,
347
351
  episodeTitle: r.episodeTitle,
@@ -544,6 +548,8 @@ export async function runStepMode(engine, start, end, context, page, mem, resolv
544
548
  let highlights;
545
549
  let stubAfterTodos = [];
546
550
  let afterOverlayTitle = overlayTitle;
551
+ let afterCaption; // undefined = leave whatever's currently shown alone (see installOverlay's own comment)
552
+ let afterNetworkTabVisible; // undefined = leave the network tab's current shown/hidden state alone
547
553
  let afterTodoPos = overlayTodoPos;
548
554
  let appliedAfter = { dock: stage.state.lastTodoDock, sync: "keep" };
549
555
  let appliedDeviceAfter = { device: stage.state.lastDevice, sync: "keep" };
@@ -573,6 +579,8 @@ export async function runStepMode(engine, start, end, context, page, mem, resolv
573
579
  if (afterPhase.title && String(afterPhase.title).trim()) {
574
580
  afterOverlayTitle = String(afterPhase.title).trim();
575
581
  }
582
+ if (afterPhase.caption !== undefined) afterCaption = afterPhase.caption;
583
+ if (afterPhase.networkTabVisible !== undefined) afterNetworkTabVisible = afterPhase.networkTabVisible;
576
584
  if (afterPhase.todoPos) afterTodoPos = afterPhase.todoPos;
577
585
  if (stage.state.lastTodoDock && stage.state.lastTodoDock.pos) afterTodoPos = stage.state.lastTodoDock.pos;
578
586
  highlights = afterPhase.highlights.map((h) => {
@@ -615,6 +623,10 @@ export async function runStepMode(engine, start, end, context, page, mem, resolv
615
623
  allEpisodes,
616
624
  title: afterOverlayTitle,
617
625
  bannerUi: stage.state.lastBannerUi,
626
+ caption: afterCaption,
627
+ networkTabVisible: afterNetworkTabVisible,
628
+ fastForward: !!r.block.fastForward,
629
+ isApi: r.block.__waygraphKind === "api",
618
630
  todoPos: afterTodoPos,
619
631
  episodeNumber: r.episodeNumber,
620
632
  episodeTitle: r.episodeTitle,
@@ -6,7 +6,7 @@ import { applyHighlightStyleDefaults, formatHighlightCaption, hasAuthoredStubOnE
6
6
  import { cycleHighlightRings } from "./rings.js";
7
7
 
8
8
  export async function renderBeforeStep(page, info) {
9
- await installOverlay(page, info.title, info.bannerUi);
9
+ await installOverlay(page, info.title, info.bannerUi, info.caption, info.networkTabVisible);
10
10
  // A ring left highlighting the PREVIOUS step's element (and its live
11
11
  // resize/scroll tracker) shouldn't linger once a new step's own panel is
12
12
  // up - only relevant when a Block's act() doesn't navigate away, since a
@@ -135,6 +135,8 @@ export async function renderBeforeStep(page, info) {
135
135
  window.__wgWirePanelChrome(panel, "wg-panel-hidden", "waygraph demo", {
136
136
  stepLabel: info.stepLabel || "",
137
137
  forceCollapsed: info.forceCollapsed === true ? true : undefined,
138
+ fastForward: !!info.fastForward,
139
+ isApi: !!info.isApi,
138
140
  });
139
141
  }
140
142
  if (window.__wgSyncTodos) {
@@ -375,7 +377,7 @@ export async function presentFailPanel(page, opts) {
375
377
 
376
378
 
377
379
  export async function renderAfterStep(page, info) {
378
- await installOverlay(page, info.title, info.bannerUi);
380
+ await installOverlay(page, info.title, info.bannerUi, info.caption, info.networkTabVisible);
379
381
  // Clear any tracker from a previous highlight before cycling through this
380
382
  // step's own.
381
383
  await page
@@ -506,6 +508,8 @@ export async function renderAfterStep(page, info) {
506
508
  window.__wgWirePanelChrome(panel, "wg-panel-hidden", "waygraph demo", {
507
509
  stepLabel: info.stepLabel || "",
508
510
  forceCollapsed: info.forceCollapsed === true ? true : undefined,
511
+ fastForward: !!info.fastForward,
512
+ isApi: !!info.isApi,
509
513
  });
510
514
  }
511
515
  if (window.__wgSyncTodos) {
@@ -574,7 +578,7 @@ export async function renderAfterStep(page, info) {
574
578
  * regardless - main()'s own try/finally - but not before this is visible).
575
579
  */
576
580
  async function renderStepError(page, info) {
577
- await installOverlay(page, info.title, info.bannerUi);
581
+ await installOverlay(page, info.title, info.bannerUi, info.caption, info.networkTabVisible);
578
582
  const errorPayload = { ...info, stepLabel: miniStepLabel(info) };
579
583
  await page
580
584
  .evaluate((info) => {
@@ -640,6 +644,8 @@ async function renderStepError(page, info) {
640
644
  window.__wgWirePanelChrome(panel, "wg-panel-hidden", "waygraph demo", {
641
645
  stepLabel: info.stepLabel || "",
642
646
  forceCollapsed: info.forceCollapsed === true ? true : undefined,
647
+ fastForward: !!info.fastForward,
648
+ isApi: !!info.isApi,
643
649
  });
644
650
  }
645
651
  if (window.__wgStampModal) {
@@ -110,15 +110,22 @@ export async function restoreTheaterAfterNavigation(page, todoDockRef, deviceRef
110
110
  const stubs = (stubBeforeRef && stubBeforeRef.current) || [];
111
111
  for (const h of stubs) {
112
112
  if (!h || !h.selector) continue;
113
- const box = await page
114
- .evaluate((sel) => {
115
- const el = document.querySelector(sel);
116
- if (!el) return null;
117
- const r = el.getBoundingClientRect();
118
- if (r.width < 2 || r.height < 2) return null;
119
- return { x: r.x, y: r.y, width: r.width, height: r.height };
120
- }, h.selector)
121
- .catch(() => null);
113
+ // Playwright's own locator (>> piercing / :has-text() / :visible support), not a raw
114
+ // querySelector string - see rings.js's showRing for the same fix, same reason. count() gate:
115
+ // Locator.evaluate() has no timeout option and auto-waits ~30s for a match to appear - count()
116
+ // never waits, keeping this an immediate "does it still exist" check (this selector routinely
117
+ // won't, after a route change - that's the whole point of the loop).
118
+ const hLoc = page.locator(h.selector).first();
119
+ const box =
120
+ (await hLoc.count().catch(() => 0)) > 0
121
+ ? await hLoc
122
+ .evaluate((el) => {
123
+ const r = el.getBoundingClientRect();
124
+ if (r.width < 2 || r.height < 2) return null;
125
+ return { x: r.x, y: r.y, width: r.width, height: r.height };
126
+ })
127
+ .catch(() => null)
128
+ : null;
122
129
  if (box) {
123
130
  await showRing(page, box, formatHighlightCaption(h), h.tone || "planned", {
124
131
  size: h.size,
@@ -1,8 +1,9 @@
1
1
  import type { Page, BrowserContext } from "@playwright/test";
2
- import { Engine } from "../engine.js";
2
+ import { Engine } from "../core.js";
3
3
  import { MemPage } from "../mem-page.js";
4
4
  import { type BlockEntry } from "./auto-explore.js";
5
5
  import type { Checkpoint } from "../types.js";
6
+ import { resolveBaseUrl } from "../config.js";
6
7
  export interface AutoExploreOptions {
7
8
  /** Terminal menu (browser still runs for act()). Default false = headful picker panel. */
8
9
  cli?: boolean;
@@ -12,7 +13,9 @@ export interface AutoExploreOptions {
12
13
  /** Phase C: glob / regex / bare `--blocks` file select for discovery. */
13
14
  blocksSelect?: import("../blocks-select.js").BlocksSelect;
14
15
  }
15
- export declare function resolveBaseUrl(projectDir: string): string | undefined;
16
+ /** See `../config.js`'s own `resolveBaseUrl` - re-exported so existing importers of this module
17
+ * don't need to change their import path. */
18
+ export { resolveBaseUrl };
16
19
  export declare function detectHere(page: Page, navBlocks: BlockEntry[]): Promise<string | null>;
17
20
  export declare function ensureLivePage(context: BrowserContext, page: Page, startUrl: string | undefined): Promise<Page>;
18
21
  /**