waygraph 0.13.7 → 0.15.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 (358) hide show
  1. package/README.md +970 -232
  2. package/assets/stubs/stub.mp4 +0 -0
  3. package/assets/stubs/stub.pdf +32 -0
  4. package/assets/stubs/stub.png +0 -0
  5. package/dist/agent-dive.d.ts +9 -0
  6. package/dist/agent-dive.js +32 -0
  7. package/dist/auto-explore-run.d.ts +20 -2
  8. package/dist/auto-explore-run.js +9 -8
  9. package/dist/auto-explore.js +22 -2
  10. package/dist/auto-session-ipc.d.ts +123 -0
  11. package/dist/auto-session-ipc.js +381 -0
  12. package/dist/auto-session.d.ts +342 -0
  13. package/dist/auto-session.js +760 -0
  14. package/dist/cli.js +450 -51
  15. package/dist/engine.d.ts +201 -1
  16. package/dist/engine.js +312 -2
  17. package/dist/graph.d.ts +18 -0
  18. package/dist/graph.js +65 -2
  19. package/dist/highlights.d.ts +20 -1
  20. package/dist/highlights.js +60 -0
  21. package/dist/index.d.ts +8 -4
  22. package/dist/index.js +5 -3
  23. package/dist/map-check.d.ts +18 -0
  24. package/dist/map-check.js +140 -0
  25. package/dist/pilot-overlay.d.ts +88 -0
  26. package/dist/pilot-overlay.js +363 -0
  27. package/dist/pilot.d.ts +49 -0
  28. package/dist/pilot.js +53 -0
  29. package/dist/trait.d.ts +22 -0
  30. package/dist/trait.js +60 -3
  31. package/dist/types.d.ts +21 -1
  32. package/dist/types.js +17 -1
  33. package/examples/routed-demo/.waygraph-auto/4d4902b7.log +0 -0
  34. package/examples/routed-demo/.waygraph-auto/51ef462e.log +0 -0
  35. package/examples/routed-demo/.waygraph-auto/71527ad9.log +0 -0
  36. package/examples/routed-demo/.waygraph-auto/ca16778e.log +0 -0
  37. package/examples/routed-demo/package.json +26 -0
  38. package/examples/routed-demo/playwright.config.ts +20 -0
  39. package/examples/routed-demo/scripts/fixture-server.mjs +37 -0
  40. package/examples/routed-demo/scripts/with-fixture.mjs +70 -0
  41. package/examples/routed-demo/src/flows/routed-demo-map.flow.ts +39 -0
  42. package/examples/routed-demo/src/flows/routed-demo.flow.ts +12 -0
  43. package/examples/routed-demo/src/map/(app_base)/dashboard/_methods/click-widget.block.ts +23 -0
  44. package/examples/routed-demo/src/map/(app_base)/dashboard/_nav.block.ts +18 -0
  45. package/examples/routed-demo/src/map/(app_base)/dashboard/_page.block.ts +22 -0
  46. package/examples/routed-demo/src/map/(app_base)/dashboard/_sel.ts +10 -0
  47. package/examples/routed-demo/src/map/(external)/docs/_nav.block.ts +21 -0
  48. package/examples/routed-demo/src/map/(external)/docs/_page.block.ts +15 -0
  49. package/examples/routed-demo/src/map/(external)/docs/_sel.ts +7 -0
  50. package/examples/routed-demo/src/pages/dashboard.html +10 -0
  51. package/examples/routed-demo/src/pages/docs.html +8 -0
  52. package/examples/routed-demo/src/states/routed-demo.states.ts +10 -0
  53. package/examples/routed-demo/test-results/.last-run.json +4 -0
  54. package/examples/routed-demo/tests/routed-demo-map.spec.ts +17 -0
  55. package/examples/routed-demo/tests/routed-demo.spec.ts +75 -0
  56. package/examples/routed-demo/tsconfig.json +18 -0
  57. package/examples/routed-demo-consumer/package.json +18 -0
  58. package/examples/saucedemo/.waygraph-auto/00d5336e.log +0 -0
  59. package/examples/saucedemo/.waygraph-auto/010dd92b.log +0 -0
  60. package/examples/saucedemo/.waygraph-auto/011ad671.log +0 -0
  61. package/examples/saucedemo/.waygraph-auto/01b45645.log +0 -0
  62. package/examples/saucedemo/.waygraph-auto/03764153.log +0 -0
  63. package/examples/saucedemo/.waygraph-auto/0593587e.log +0 -0
  64. package/examples/saucedemo/.waygraph-auto/06d12823.log +0 -0
  65. package/examples/saucedemo/.waygraph-auto/083cc5b9.log +0 -0
  66. package/examples/saucedemo/.waygraph-auto/0b1f5b26.json +8 -0
  67. package/examples/saucedemo/.waygraph-auto/0c00f25f.log +0 -0
  68. package/examples/saucedemo/.waygraph-auto/0e480591.log +0 -0
  69. package/examples/saucedemo/.waygraph-auto/104751ef.log +0 -0
  70. package/examples/saucedemo/.waygraph-auto/110958b8.log +0 -0
  71. package/examples/saucedemo/.waygraph-auto/138107c1.log +0 -0
  72. package/examples/saucedemo/.waygraph-auto/159d541b.log +0 -0
  73. package/examples/saucedemo/.waygraph-auto/16aa2c01.log +0 -0
  74. package/examples/saucedemo/.waygraph-auto/16c35dd5.log +0 -0
  75. package/examples/saucedemo/.waygraph-auto/1706547d.log +0 -0
  76. package/examples/saucedemo/.waygraph-auto/17537e42.log +0 -0
  77. package/examples/saucedemo/.waygraph-auto/175655f7.log +0 -0
  78. package/examples/saucedemo/.waygraph-auto/17ede493.log +0 -0
  79. package/examples/saucedemo/.waygraph-auto/1fe2414f.log +0 -0
  80. package/examples/saucedemo/.waygraph-auto/1fe2e3b8.log +0 -0
  81. package/examples/saucedemo/.waygraph-auto/2219f00b.log +0 -0
  82. package/examples/saucedemo/.waygraph-auto/23e62571.log +0 -0
  83. package/examples/saucedemo/.waygraph-auto/25f68ada.log +0 -0
  84. package/examples/saucedemo/.waygraph-auto/26ca9cd8.log +0 -0
  85. package/examples/saucedemo/.waygraph-auto/2bb6c4e8.log +0 -0
  86. package/examples/saucedemo/.waygraph-auto/2d425004.log +0 -0
  87. package/examples/saucedemo/.waygraph-auto/2f5b3ea6.log +0 -0
  88. package/examples/saucedemo/.waygraph-auto/31bb303d.log +0 -0
  89. package/examples/saucedemo/.waygraph-auto/31f2042f.log +0 -0
  90. package/examples/saucedemo/.waygraph-auto/36551ec1.log +0 -0
  91. package/examples/saucedemo/.waygraph-auto/36a1c274.log +0 -0
  92. package/examples/saucedemo/.waygraph-auto/381aa338.log +0 -0
  93. package/examples/saucedemo/.waygraph-auto/3882bce1.log +0 -0
  94. package/examples/saucedemo/.waygraph-auto/38acd1dc.log +0 -0
  95. package/examples/saucedemo/.waygraph-auto/3b8b77b9.log +0 -0
  96. package/examples/saucedemo/.waygraph-auto/4028d2a2.log +0 -0
  97. package/examples/saucedemo/.waygraph-auto/4168b208.log +0 -0
  98. package/examples/saucedemo/.waygraph-auto/42cc9113.log +0 -0
  99. package/examples/saucedemo/.waygraph-auto/439d30aa.log +0 -0
  100. package/examples/saucedemo/.waygraph-auto/43ab66ce.log +0 -0
  101. package/examples/saucedemo/.waygraph-auto/43f66838.log +0 -0
  102. package/examples/saucedemo/.waygraph-auto/442171d4.log +0 -0
  103. package/examples/saucedemo/.waygraph-auto/453b1ce1.log +0 -0
  104. package/examples/saucedemo/.waygraph-auto/457322bd.log +0 -0
  105. package/examples/saucedemo/.waygraph-auto/46197027.log +0 -0
  106. package/examples/saucedemo/.waygraph-auto/46889468.log +0 -0
  107. package/examples/saucedemo/.waygraph-auto/4890da1c.log +0 -0
  108. package/examples/saucedemo/.waygraph-auto/4893a63b.log +0 -0
  109. package/examples/saucedemo/.waygraph-auto/4a85f496.log +0 -0
  110. package/examples/saucedemo/.waygraph-auto/4af71440.log +0 -0
  111. package/examples/saucedemo/.waygraph-auto/4f7496d1.log +0 -0
  112. package/examples/saucedemo/.waygraph-auto/50e8baaa.log +0 -0
  113. package/examples/saucedemo/.waygraph-auto/52b3a455.log +0 -0
  114. package/examples/saucedemo/.waygraph-auto/532dd9b8.log +0 -0
  115. package/examples/saucedemo/.waygraph-auto/5391ce40.log +0 -0
  116. package/examples/saucedemo/.waygraph-auto/57dbddb3.log +0 -0
  117. package/examples/saucedemo/.waygraph-auto/5897f501.log +0 -0
  118. package/examples/saucedemo/.waygraph-auto/59c0b57d.log +0 -0
  119. package/examples/saucedemo/.waygraph-auto/5b511794.log +0 -0
  120. package/examples/saucedemo/.waygraph-auto/5c0eef7f.log +0 -0
  121. package/examples/saucedemo/.waygraph-auto/5c47910f.log +0 -0
  122. package/examples/saucedemo/.waygraph-auto/5d60da77.log +0 -0
  123. package/examples/saucedemo/.waygraph-auto/5eda8273.log +0 -0
  124. package/examples/saucedemo/.waygraph-auto/5fc3a33b.log +0 -0
  125. package/examples/saucedemo/.waygraph-auto/61b6546d.log +0 -0
  126. package/examples/saucedemo/.waygraph-auto/621518ad.log +0 -0
  127. package/examples/saucedemo/.waygraph-auto/632b7118.log +0 -0
  128. package/examples/saucedemo/.waygraph-auto/64314c2b.log +0 -0
  129. package/examples/saucedemo/.waygraph-auto/650ed066.log +0 -0
  130. package/examples/saucedemo/.waygraph-auto/66516213.log +0 -0
  131. package/examples/saucedemo/.waygraph-auto/66c17079.log +0 -0
  132. package/examples/saucedemo/.waygraph-auto/69bf0b80.log +0 -0
  133. package/examples/saucedemo/.waygraph-auto/69c2347a.log +0 -0
  134. package/examples/saucedemo/.waygraph-auto/6d22bdb0.log +0 -0
  135. package/examples/saucedemo/.waygraph-auto/6d9aaad3.log +0 -0
  136. package/examples/saucedemo/.waygraph-auto/7103bebb.log +0 -0
  137. package/examples/saucedemo/.waygraph-auto/740c9faa.log +0 -0
  138. package/examples/saucedemo/.waygraph-auto/74872fc5.log +0 -0
  139. package/examples/saucedemo/.waygraph-auto/75846ca9.log +0 -0
  140. package/examples/saucedemo/.waygraph-auto/7626c85b.log +0 -0
  141. package/examples/saucedemo/.waygraph-auto/76308eec.log +0 -0
  142. package/examples/saucedemo/.waygraph-auto/76c1650e.log +0 -0
  143. package/examples/saucedemo/.waygraph-auto/7861f38f.log +0 -0
  144. package/examples/saucedemo/.waygraph-auto/78b21219.log +0 -0
  145. package/examples/saucedemo/.waygraph-auto/7af224ed.log +0 -0
  146. package/examples/saucedemo/.waygraph-auto/7c3be585.log +0 -0
  147. package/examples/saucedemo/.waygraph-auto/7ed55a2c.log +0 -0
  148. package/examples/saucedemo/.waygraph-auto/80086ba2.log +0 -0
  149. package/examples/saucedemo/.waygraph-auto/80206369.log +0 -0
  150. package/examples/saucedemo/.waygraph-auto/847f1092.log +0 -0
  151. package/examples/saucedemo/.waygraph-auto/84d6d293.log +0 -0
  152. package/examples/saucedemo/.waygraph-auto/8581abfa.log +0 -0
  153. package/examples/saucedemo/.waygraph-auto/87b7e0fd.log +0 -0
  154. package/examples/saucedemo/.waygraph-auto/87c79256.log +0 -0
  155. package/examples/saucedemo/.waygraph-auto/88af2495.log +0 -0
  156. package/examples/saucedemo/.waygraph-auto/8a3eb088.log +0 -0
  157. package/examples/saucedemo/.waygraph-auto/8c04a403.log +0 -0
  158. package/examples/saucedemo/.waygraph-auto/8c9ab09e.log +0 -0
  159. package/examples/saucedemo/.waygraph-auto/8cc5db51.log +0 -0
  160. package/examples/saucedemo/.waygraph-auto/8ea3a69c.log +0 -0
  161. package/examples/saucedemo/.waygraph-auto/9150f913.log +0 -0
  162. package/examples/saucedemo/.waygraph-auto/929a4313.log +0 -0
  163. package/examples/saucedemo/.waygraph-auto/95a599e4.log +0 -0
  164. package/examples/saucedemo/.waygraph-auto/96c45350.log +0 -0
  165. package/examples/saucedemo/.waygraph-auto/986030e6.log +0 -0
  166. package/examples/saucedemo/.waygraph-auto/99787abb.log +0 -0
  167. package/examples/saucedemo/.waygraph-auto/99ddb62c.log +0 -0
  168. package/examples/saucedemo/.waygraph-auto/a2dd30dd.log +0 -0
  169. package/examples/saucedemo/.waygraph-auto/a63a2d20.log +0 -0
  170. package/examples/saucedemo/.waygraph-auto/a78befb7.log +0 -0
  171. package/examples/saucedemo/.waygraph-auto/a84d9b79.log +0 -0
  172. package/examples/saucedemo/.waygraph-auto/a87bb3ee.log +0 -0
  173. package/examples/saucedemo/.waygraph-auto/a9270890.log +0 -0
  174. package/examples/saucedemo/.waygraph-auto/aa440153.log +0 -0
  175. package/examples/saucedemo/.waygraph-auto/ab7561e0.log +0 -0
  176. package/examples/saucedemo/.waygraph-auto/ac19ae60.log +0 -0
  177. package/examples/saucedemo/.waygraph-auto/ae21ad8e.log +0 -0
  178. package/examples/saucedemo/.waygraph-auto/af09042f.log +0 -0
  179. package/examples/saucedemo/.waygraph-auto/b1684126.log +0 -0
  180. package/examples/saucedemo/.waygraph-auto/b21e9d12.log +0 -0
  181. package/examples/saucedemo/.waygraph-auto/b5a838be.log +0 -0
  182. package/examples/saucedemo/.waygraph-auto/b603549d.log +0 -0
  183. package/examples/saucedemo/.waygraph-auto/b81e074f.log +0 -0
  184. package/examples/saucedemo/.waygraph-auto/b83e6259.log +0 -0
  185. package/examples/saucedemo/.waygraph-auto/b9cb2796.log +0 -0
  186. package/examples/saucedemo/.waygraph-auto/ba58abb7.log +0 -0
  187. package/examples/saucedemo/.waygraph-auto/bb0a0018.log +0 -0
  188. package/examples/saucedemo/.waygraph-auto/bb9fd384.log +0 -0
  189. package/examples/saucedemo/.waygraph-auto/bc0bdd0e.log +0 -0
  190. package/examples/saucedemo/.waygraph-auto/bc7d4a83.log +0 -0
  191. package/examples/saucedemo/.waygraph-auto/bd8e082a.log +0 -0
  192. package/examples/saucedemo/.waygraph-auto/bea0c93e.log +0 -0
  193. package/examples/saucedemo/.waygraph-auto/bf35201a.log +0 -0
  194. package/examples/saucedemo/.waygraph-auto/bffa3a7a.log +0 -0
  195. package/examples/saucedemo/.waygraph-auto/c02ea583.log +0 -0
  196. package/examples/saucedemo/.waygraph-auto/c2caf0a8.log +0 -0
  197. package/examples/saucedemo/.waygraph-auto/c3bdc714.log +0 -0
  198. package/examples/saucedemo/.waygraph-auto/c4afb8bc.log +0 -0
  199. package/examples/saucedemo/.waygraph-auto/c916a654.log +0 -0
  200. package/examples/saucedemo/.waygraph-auto/c9b8d69e.log +0 -0
  201. package/examples/saucedemo/.waygraph-auto/cd68bbc4.log +0 -0
  202. package/examples/saucedemo/.waygraph-auto/cdc6db50.log +0 -0
  203. package/examples/saucedemo/.waygraph-auto/d01906a7.log +0 -0
  204. package/examples/saucedemo/.waygraph-auto/d02e5e7e.log +0 -0
  205. package/examples/saucedemo/.waygraph-auto/d09aff71.log +0 -0
  206. package/examples/saucedemo/.waygraph-auto/d0e41396.log +0 -0
  207. package/examples/saucedemo/.waygraph-auto/d1370d76.log +0 -0
  208. package/examples/saucedemo/.waygraph-auto/d3714ae4.log +0 -0
  209. package/examples/saucedemo/.waygraph-auto/d9e5f8a4.log +0 -0
  210. package/examples/saucedemo/.waygraph-auto/da0685dc.log +0 -0
  211. package/examples/saucedemo/.waygraph-auto/da894ad8.log +0 -0
  212. package/examples/saucedemo/.waygraph-auto/daa2f922.log +0 -0
  213. package/examples/saucedemo/.waygraph-auto/daefb614.log +0 -0
  214. package/examples/saucedemo/.waygraph-auto/db97e833.log +0 -0
  215. package/examples/saucedemo/.waygraph-auto/dec3076e.log +0 -0
  216. package/examples/saucedemo/.waygraph-auto/e101d19a.log +0 -0
  217. package/examples/saucedemo/.waygraph-auto/e1973991.log +0 -0
  218. package/examples/saucedemo/.waygraph-auto/e207c989.log +0 -0
  219. package/examples/saucedemo/.waygraph-auto/e633e545.log +0 -0
  220. package/examples/saucedemo/.waygraph-auto/e69aec68.log +0 -0
  221. package/examples/saucedemo/.waygraph-auto/e70e2d06.log +0 -0
  222. package/examples/saucedemo/.waygraph-auto/e8306a4b.log +0 -0
  223. package/examples/saucedemo/.waygraph-auto/ebad3410.log +0 -0
  224. package/examples/saucedemo/.waygraph-auto/ec88b3ef.log +0 -0
  225. package/examples/saucedemo/.waygraph-auto/ecbb0966.log +0 -0
  226. package/examples/saucedemo/.waygraph-auto/ecdee753.log +0 -0
  227. package/examples/saucedemo/.waygraph-auto/ed888783.log +0 -0
  228. package/examples/saucedemo/.waygraph-auto/ed931dac.log +0 -0
  229. package/examples/saucedemo/.waygraph-auto/ef655a3f.log +0 -0
  230. package/examples/saucedemo/.waygraph-auto/f34c9a26.log +0 -0
  231. package/examples/saucedemo/.waygraph-auto/f3c29b21.log +0 -0
  232. package/examples/saucedemo/.waygraph-auto/f53f7cfc.log +0 -0
  233. package/examples/saucedemo/.waygraph-auto/f5525d53.log +0 -0
  234. package/examples/saucedemo/.waygraph-auto/f5ad5830.log +0 -0
  235. package/examples/saucedemo/.waygraph-auto/f90035b3.log +0 -0
  236. package/examples/saucedemo/.waygraph-auto/fa687bc2.log +0 -0
  237. package/examples/saucedemo/.waygraph-auto/faed36dd.log +0 -0
  238. package/examples/saucedemo/.waygraph-auto/fb66fba0.log +0 -0
  239. package/examples/saucedemo/.waygraph-auto/fc48fd76.log +0 -0
  240. package/examples/saucedemo/docs/CONVENTION.md +25 -5
  241. package/examples/saucedemo/docs/HELPERS.md +15 -4
  242. package/examples/saucedemo/scripts/capture-wrong-login.mjs +8 -2
  243. package/examples/saucedemo/scripts/prove-wrong-login-runtime.mjs +8 -2
  244. package/examples/saucedemo/src/blocks/SITE-MAP.md +14 -3
  245. package/examples/saucedemo/src/blocks/saucedemo-web/NAV.md +15 -1
  246. package/examples/saucedemo/src/blocks/saucedemo-web/cart/NAV.md +1 -0
  247. package/examples/saucedemo/src/blocks/saucedemo-web/cart/cart.sel.ts +9 -0
  248. package/examples/saucedemo/src/blocks/saucedemo-web/cart/nav-cart.block.ts +3 -2
  249. package/examples/saucedemo/src/blocks/saucedemo-web/cart/nav-checkout-info.block.ts +2 -1
  250. package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/NAV.md +6 -1
  251. package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/methods/checkout-info.sel.ts +11 -0
  252. package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/methods/fill-first-name.method.block.ts +22 -0
  253. package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/methods/fill-last-name.method.block.ts +21 -0
  254. package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/methods/fill-postal-code.method.block.ts +21 -0
  255. package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/methods/submit-checkout-info.method.block.ts +6 -7
  256. package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-two/NAV.md +2 -0
  257. package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-two/methods/checkout-overview.sel.ts +9 -0
  258. package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-two/methods/finish-order.method.block.ts +7 -6
  259. package/examples/saucedemo/src/blocks/saucedemo-web/ff-owner-auth.block.ts +7 -2
  260. package/examples/saucedemo/src/blocks/saucedemo-web/inventory-item/NAV.md +1 -0
  261. package/examples/saucedemo/src/blocks/saucedemo-web/inventory-item/item-detail.sel.ts +9 -0
  262. package/examples/saucedemo/src/blocks/saucedemo-web/inventory-item/nav-back-to-inventory.block.ts +2 -1
  263. package/examples/saucedemo/src/blocks/saucedemo-web/inventory-item/nav-back-to-products.block.ts +2 -1
  264. package/examples/saucedemo/src/blocks/saucedemo-web/inventory-item/nav-continue-shopping.block.ts +2 -1
  265. package/examples/saucedemo/src/blocks/saucedemo-web/methods/fill-password.method.block.ts +51 -0
  266. package/examples/saucedemo/src/blocks/saucedemo-web/methods/fill-username.method.block.ts +69 -0
  267. package/examples/saucedemo/src/blocks/saucedemo-web/methods/login.sel.ts +13 -0
  268. package/examples/saucedemo/src/blocks/saucedemo-web/methods/submit-login-for-flow.ts +4 -4
  269. package/examples/saucedemo/src/blocks/saucedemo-web/methods/submit-login.method.block.ts +13 -51
  270. package/examples/saucedemo/src/blocks/saucedemo-web/methods/submit-logout.method.block.ts +4 -3
  271. package/examples/saucedemo/src/blocks/saucedemo-web/nav-login.block.ts +14 -6
  272. package/examples/saucedemo/src/flows/checkout-then-browse-again.flow.ts +15 -0
  273. package/examples/saucedemo/src/flows/checkout.flow.ts +20 -2
  274. package/examples/saucedemo/src/flows/device-showcase.flow.ts +4 -0
  275. package/examples/saucedemo/src/flows/login.flow.ts +3 -1
  276. package/examples/saucedemo/src/flows/shop.flow.ts +6 -0
  277. package/examples/saucedemo/src/flows/smoke.flow.ts +13 -7
  278. package/examples/saucedemo/src/flows/stub-on-error.flow.ts +4 -2
  279. package/examples/saucedemo/src/flows/viewer-blocked.flow.ts +6 -2
  280. package/examples/saucedemo/tests/flow-block-verify.spec.ts +3 -3
  281. package/examples/saucedemo/tests/submit-login-branch.spec.ts +5 -3
  282. package/package.json +2 -1
  283. package/templates/agents/waygraph-author.agent.md +43 -5
  284. package/templates/agents/waygraph-planner.agent.md +33 -2
  285. package/templates/quickstart/src/blocks/saucedemo-web/NAV.md +15 -1
  286. package/templates/quickstart/src/blocks/saucedemo-web/cart/NAV.md +1 -0
  287. package/templates/quickstart/src/blocks/saucedemo-web/cart/cart.sel.ts +9 -0
  288. package/templates/quickstart/src/blocks/saucedemo-web/cart/nav-cart.block.ts +19 -15
  289. package/templates/quickstart/src/blocks/saucedemo-web/cart/nav-checkout-info.block.ts +2 -1
  290. package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/NAV.md +6 -1
  291. package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/methods/checkout-info.sel.ts +11 -0
  292. package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/methods/fill-first-name.method.block.ts +22 -0
  293. package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/methods/fill-last-name.method.block.ts +21 -0
  294. package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/methods/fill-postal-code.method.block.ts +21 -0
  295. package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/methods/submit-checkout-info.method.block.ts +6 -7
  296. package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-two/NAV.md +2 -0
  297. package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-two/methods/checkout-overview.sel.ts +9 -0
  298. package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-two/methods/finish-order.method.block.ts +7 -6
  299. package/templates/quickstart/src/blocks/saucedemo-web/ff-owner-auth.block.ts +7 -2
  300. package/templates/quickstart/src/blocks/saucedemo-web/inventory/methods/add-to-cart.effect.block.ts +24 -16
  301. package/templates/quickstart/src/blocks/saucedemo-web/inventory/nav-item-detail.block.ts +3 -3
  302. package/templates/quickstart/src/blocks/saucedemo-web/inventory-item/NAV.md +1 -0
  303. package/templates/quickstart/src/blocks/saucedemo-web/inventory-item/item-detail.sel.ts +9 -0
  304. package/templates/quickstart/src/blocks/saucedemo-web/inventory-item/nav-back-to-inventory.block.ts +2 -1
  305. package/templates/quickstart/src/blocks/saucedemo-web/inventory-item/nav-back-to-products.block.ts +2 -1
  306. package/templates/quickstart/src/blocks/saucedemo-web/inventory-item/nav-continue-shopping.block.ts +2 -1
  307. package/templates/quickstart/src/blocks/saucedemo-web/methods/fill-password.method.block.ts +51 -0
  308. package/templates/quickstart/src/blocks/saucedemo-web/methods/fill-username.method.block.ts +69 -0
  309. package/templates/quickstart/src/blocks/saucedemo-web/methods/login.sel.ts +13 -0
  310. package/templates/quickstart/src/blocks/saucedemo-web/methods/submit-login-for-flow.ts +4 -4
  311. package/templates/quickstart/src/blocks/saucedemo-web/methods/submit-login.method.block.ts +35 -63
  312. package/templates/quickstart/src/blocks/saucedemo-web/methods/submit-logout.method.block.ts +4 -3
  313. package/templates/quickstart/src/blocks/saucedemo-web/nav-login.block.ts +14 -6
  314. package/templates/quickstart/src/flows/checkout-then-browse-again.flow.ts +15 -0
  315. package/templates/quickstart/src/flows/checkout.flow.ts +29 -2
  316. package/templates/quickstart/src/flows/device-showcase.flow.ts +4 -0
  317. package/templates/quickstart/src/flows/login.flow.ts +3 -1
  318. package/templates/quickstart/src/flows/shop.flow.ts +6 -0
  319. package/templates/quickstart/src/flows/smoke.flow.ts +13 -7
  320. package/templates/quickstart/src/flows/viewer-blocked.flow.ts +6 -2
  321. package/templates/quickstart/tests/chain-flow.spec.ts +8 -1
  322. package/templates/scaffold/STRUCTURE.md +23 -3
  323. package/templates/scaffold/scripts/fixture-server.mjs +11 -2
  324. package/templates/scaffold/src/flows/example.flow.ts +8 -6
  325. package/templates/scaffold/src/flows/mail-verify.flow.ts +85 -0
  326. package/templates/scaffold/src/flows/shop.flow.ts +23 -6
  327. package/templates/scaffold/src/map/(app_base)/docs/_nav.block.ts +20 -0
  328. package/templates/scaffold/src/map/(app_base)/docs/_page.block.ts +15 -0
  329. package/templates/scaffold/src/map/(app_base)/docs/_sel.ts +7 -0
  330. package/templates/scaffold/src/map/(app_base)/docs/docs.html +8 -0
  331. package/templates/scaffold/src/{blocks/demo-web/methods → map/(app_base)/home/_methods}/add-item.effect.block.ts +3 -3
  332. package/templates/scaffold/src/map/(app_base)/home/_methods/assert-hello.method.block.ts +46 -0
  333. package/templates/scaffold/src/map/(app_base)/home/_methods/assert-item-added.method.block.ts +38 -0
  334. package/templates/scaffold/src/{blocks/demo-web/methods → map/(app_base)/home/_methods}/clear-cart.method.block.ts +9 -3
  335. package/templates/scaffold/src/{blocks/demo-web/methods → map/(app_base)/home/_methods}/remove-item.effect.block.ts +3 -3
  336. package/templates/scaffold/src/{blocks/demo-web/nav-home.block.ts → map/(app_base)/home/_nav.block.ts} +2 -2
  337. package/templates/scaffold/src/{blocks/demo-web/home.page.block.ts → map/(app_base)/home/_page.block.ts} +7 -7
  338. package/templates/scaffold/src/{blocks/demo-web/demo-sel.ts → map/(app_base)/home/_sel.ts} +1 -0
  339. package/templates/scaffold/src/{blocks/demo-web → map/(app_base)/home}/home.html +4 -0
  340. package/templates/scaffold/src/map/(app_base)/home/nav-verification-link.block.ts +34 -0
  341. package/templates/scaffold/src/map/(external)/mailpit/_methods/assert-email-content.method.block.ts +48 -0
  342. package/templates/scaffold/src/map/(external)/mailpit/_methods/assert-email-received.method.block.ts +49 -0
  343. package/templates/scaffold/src/map/(external)/mailpit/_methods/extract-email-link.method.block.ts +41 -0
  344. package/templates/scaffold/src/map/(external)/mailpit/_methods/open-message.method.block.ts +39 -0
  345. package/templates/scaffold/src/map/(external)/mailpit/_nav.block.ts +20 -0
  346. package/templates/scaffold/src/map/(external)/mailpit/_page.block.ts +30 -0
  347. package/templates/scaffold/src/map/(external)/mailpit/_sel.ts +5 -0
  348. package/templates/scaffold/src/states/demo.mem-keys.ts +25 -1
  349. package/templates/scaffold/src/states/demo.states.ts +11 -0
  350. package/templates/scaffold/test-results/.last-run.json +4 -0
  351. package/templates/scaffold/tests/example.spec.ts +2 -2
  352. package/templates/scaffold/tests/mail-verify.spec.ts +191 -0
  353. package/templates/skills/waygraph-blind-pilot.skill.md +61 -0
  354. package/templates/skills/waygraph-pilot.skill.md +108 -0
  355. package/templates/quickstart/README-saucedemo-commands.md +0 -72
  356. package/templates/scaffold/src/blocks/SITE-MAP.md +0 -12
  357. package/templates/scaffold/src/blocks/demo-web/NAV.md +0 -29
  358. package/templates/scaffold/src/blocks/demo-web/methods/assert-hello.method.block.ts +0 -50
@@ -0,0 +1,30 @@
1
+ import { definePageBlock, Trait } from "waygraph";
2
+ import type { MailpitInbox } from "../../../states/demo.states.js";
3
+ import { AssertEmailReceivedBlock } from "./_methods/assert-email-received.method.block.js";
4
+ import { OpenMessageBlock } from "./_methods/open-message.method.block.js";
5
+ import { AssertEmailContentBlock } from "./_methods/assert-email-content.method.block.js";
6
+ import { ExtractEmailLinkBlock } from "./_methods/extract-email-link.method.block.js";
7
+
8
+ /**
9
+ * Kind: Page
10
+ * Helper: definePageBlock
11
+ * Route: (external)/mailpit/ (= http://127.0.0.1:8025/ by default)
12
+ *
13
+ * Hub for the Mailpit dev-inbox screen. Arrival-only (no url/click) -
14
+ * nav-mailpit-inbox owns the goto. Methods: confirm the email arrived, open
15
+ * it, confirm its content, then read its link - all mem-driven (recipient,
16
+ * link pattern, expected content), so this one page's methods serve any
17
+ * number of different email scenarios, not just one.
18
+ */
19
+ export const MailpitInboxPageBlock = definePageBlock<MailpitInbox>({
20
+ name: "page-mailpit-inbox",
21
+ description: "Mailpit dev inbox hub - confirm arrival/content, open the expected message, read its link.",
22
+ checkpoint: "MailpitInbox",
23
+ verify: [Trait.url({ pathname: "/" })],
24
+ methods: {
25
+ assertEmailReceived: () => AssertEmailReceivedBlock,
26
+ openMessage: () => OpenMessageBlock,
27
+ assertEmailContent: () => AssertEmailContentBlock,
28
+ extractEmailLink: () => ExtractEmailLinkBlock,
29
+ },
30
+ });
@@ -0,0 +1,5 @@
1
+ /** Selectors confirmed against a real running `axllent/mailpit` container's web UI. */
2
+ export const MailpitSel = {
3
+ messageRow: "a.message",
4
+ previewIframe: "#preview-html",
5
+ } as const;
@@ -1,7 +1,31 @@
1
- import { keyGroup } from "waygraph";
1
+ import { key, keyGroup } from "waygraph";
2
2
 
3
3
  /**
4
4
  * Which catalog row `add-item` / `remove-item` act on.
5
5
  * `waygraph auto` fills this via Effect `instanceOptions` (one menu row per live button).
6
6
  */
7
7
  export const SelectedItem = keyGroup<{ id: string; name: string }>("demo.selectedItem");
8
+
9
+ /** The link read out of the opened message - set by extract-email-link. */
10
+ export const EmailLink = keyGroup<{ url: string }>("demo.emailLink");
11
+
12
+ /**
13
+ * The recipient open-message looks for in the inbox. Mailpit lists newest
14
+ * first, but `.first()` alone picks the wrong row once more than one
15
+ * recipient's mail is sitting in the same inbox - match by mem, not position.
16
+ */
17
+ export const ExpectedRecipient = keyGroup<{ email: string }>("demo.expectedRecipient");
18
+
19
+ /**
20
+ * Substring the link's `href` must contain - lets the same extract-email-link
21
+ * Block serve any number of different email templates/scenarios in one
22
+ * project without a new Block per scenario. Only the mem values change per
23
+ * run, not the Blocks.
24
+ */
25
+ export const ExpectedLinkPattern = key<string>("demo.expectedLinkPattern");
26
+
27
+ /**
28
+ * The substring the open message's body must contain - same reuse reasoning
29
+ * as ExpectedLinkPattern: one Block, many scenarios, driven by mem.
30
+ */
31
+ export const ExpectedEmailContent = key<string>("demo.expectedEmailContent");
@@ -4,3 +4,14 @@ export type Home = Checkpoint<"Home">;
4
4
  export type HomeVerified = Checkpoint<"HomeVerified">;
5
5
  export type ItemInCart = Checkpoint<"ItemInCart">;
6
6
  export type CartEmpty = Checkpoint<"CartEmpty">;
7
+
8
+ // --- Mailpit (external tool surface, src/map/(external)/mailpit/) ---
9
+
10
+ /** Mailpit inbox UI reached; message list visible. */
11
+ export type MailpitInbox = Checkpoint<"MailpitInbox">;
12
+
13
+ /** The message addressed to the expected recipient is open; preview iframe visible. */
14
+ export type MailpitMessageOpen = Checkpoint<"MailpitMessageOpen">;
15
+
16
+ /** Reached via src/map/(app_base)/docs/ - see openspec/changes/waygraph-map. */
17
+ export type Docs = Checkpoint<"Docs">;
@@ -0,0 +1,4 @@
1
+ {
2
+ "status": "failed",
3
+ "failedTests": []
4
+ }
@@ -4,9 +4,9 @@ import { exampleFlow } from "../src/flows/example.flow.js";
4
4
  import { shopFlow } from "../src/flows/shop.flow.js";
5
5
  import { SelectedItem } from "../src/states/demo.mem-keys.js";
6
6
 
7
- test("example flow reaches HomeVerified", async ({ context }) => {
7
+ test("example flow reaches Docs (home -> assert -> sibling docs/ page)", async ({ context }) => {
8
8
  const result = await exampleFlow.run(context, new MemPage());
9
- expect(result).toEqual(checkpoint("HomeVerified"));
9
+ expect(result).toEqual(checkpoint("Docs"));
10
10
  });
11
11
 
12
12
  test("shop flow adds then clears (Effect + Method)", async ({ context }) => {
@@ -0,0 +1,191 @@
1
+ import { test, expect } from "@playwright/test";
2
+ import { spawnSync } from "node:child_process";
3
+ import net from "node:net";
4
+ import { MemPage, checkpoint } from "waygraph";
5
+ import { mailVerifyFlow } from "../src/flows/mail-verify.flow.js";
6
+ import { ExpectedRecipient, ExpectedLinkPattern, ExpectedEmailContent } from "../src/states/demo.mem-keys.js";
7
+ import { HOME_URL } from "../src/map/(app_base)/home/_sel.js";
8
+
9
+ /**
10
+ * This scaffold has no real backend, so these tests play the role of "the
11
+ * app sent a verification email" themselves: spin up a real, throwaway
12
+ * Mailpit container, send a real SMTP message, then run mailVerifyFlow for
13
+ * real - a real cross-origin browser hop into Mailpit's own web UI and
14
+ * back, no mail-catcher REST API anywhere. Covers the happy path, both
15
+ * failure paths its QA-facing asserts exist for (no email arrived, wrong
16
+ * content), and - the actual point of making the mail-reading Blocks
17
+ * mem-driven - a second, entirely different email scenario running through
18
+ * the exact same four Blocks with zero new code.
19
+ */
20
+
21
+ function runMailpit(): { containerId: string; smtpPort: number; httpPort: number } {
22
+ const run = spawnSync("docker", ["run", "--rm", "-d", "-p", "0:1025", "-p", "0:8025", "axllent/mailpit"], {
23
+ encoding: "utf8",
24
+ });
25
+ if (run.status !== 0) throw new Error(`docker run axllent/mailpit failed: ${run.stderr || run.stdout}`);
26
+ const containerId = run.stdout.trim();
27
+ const portCheck = spawnSync("docker", ["port", containerId], { encoding: "utf8" });
28
+ const portFor = (containerPort: number) => {
29
+ const line = portCheck.stdout.split("\n").find((l) => l.startsWith(`${containerPort}/tcp`) && l.includes("0.0.0.0"));
30
+ const m = line?.match(/:(\d+)\s*$/);
31
+ if (!m) throw new Error(`could not determine host port for ${containerPort}`);
32
+ return Number(m[1]);
33
+ };
34
+ return { containerId, smtpPort: portFor(1025), httpPort: portFor(8025) };
35
+ }
36
+
37
+ function dockerAvailable(): boolean {
38
+ return spawnSync("docker", ["ps"], { encoding: "utf8" }).status === 0;
39
+ }
40
+
41
+ async function sendTestEmail(opts: { host: string; port: number; to: string; subject: string; html: string }): Promise<void> {
42
+ const body = [
43
+ "From: scaffold-app@example.com",
44
+ `To: ${opts.to}`,
45
+ `Subject: ${opts.subject}`,
46
+ "Content-Type: text/html; charset=utf-8",
47
+ "",
48
+ opts.html,
49
+ ".",
50
+ ].join("\r\n");
51
+
52
+ await new Promise<void>((resolve, reject) => {
53
+ const socket = net.createConnection({ host: opts.host, port: opts.port });
54
+ function cmd(line: string): Promise<string> {
55
+ return new Promise((res) => {
56
+ socket.once("data", (d) => res(d.toString()));
57
+ socket.write(line + "\r\n");
58
+ });
59
+ }
60
+ socket.once("error", reject);
61
+ socket.once("connect", () => {
62
+ (async () => {
63
+ await new Promise<void>((r) => socket.once("data", () => r()));
64
+ await cmd("HELO localhost");
65
+ await cmd("MAIL FROM:<scaffold-app@example.com>");
66
+ await cmd(`RCPT TO:<${opts.to}>`);
67
+ await cmd("DATA");
68
+ await cmd(body);
69
+ await cmd("QUIT");
70
+ socket.end();
71
+ resolve();
72
+ })().catch(reject);
73
+ });
74
+ });
75
+ }
76
+
77
+ async function withMailpit<T>(fn: (opts: { httpPort: number; smtpPort: number }) => Promise<T>): Promise<T> {
78
+ const { containerId, smtpPort, httpPort } = runMailpit();
79
+ const originalMailUrl = process.env.WAYGRAPH_MAIL_URL;
80
+ try {
81
+ process.env.WAYGRAPH_MAIL_URL = `http://127.0.0.1:${httpPort}`;
82
+ return await fn({ httpPort, smtpPort });
83
+ } finally {
84
+ if (originalMailUrl === undefined) delete process.env.WAYGRAPH_MAIL_URL;
85
+ else process.env.WAYGRAPH_MAIL_URL = originalMailUrl;
86
+ spawnSync("docker", ["stop", containerId]);
87
+ }
88
+ }
89
+
90
+ const VERIFICATION_CONTENT = "Please confirm your email address to finish setting up your account.";
91
+
92
+ test("mailVerifyFlow: confirms arrival, confirms content, reads the real link, navigates to it", async ({
93
+ context,
94
+ }) => {
95
+ test.skip(!dockerAvailable(), "Docker not reachable in this environment");
96
+ test.setTimeout(60_000);
97
+
98
+ await withMailpit(async ({ smtpPort }) => {
99
+ const recipient = "demo-user@example.com";
100
+ await sendTestEmail({
101
+ host: "127.0.0.1",
102
+ port: smtpPort,
103
+ to: recipient,
104
+ subject: "Please verify your account",
105
+ html: `<p>${VERIFICATION_CONTENT}</p><a href="${HOME_URL}?verified=1">Verify your account</a>`,
106
+ });
107
+
108
+ const mem = new MemPage();
109
+ mem.set(ExpectedRecipient({ email: recipient }));
110
+ mem.set(ExpectedLinkPattern, "verified=1");
111
+ mem.set(ExpectedEmailContent, VERIFICATION_CONTENT);
112
+ const result = await mailVerifyFlow.run(context, mem);
113
+ expect(result).toEqual(checkpoint("HomeVerified"));
114
+ });
115
+ });
116
+
117
+ test("the same four mail-reading Blocks handle a second, unrelated email scenario - zero new Blocks", async ({
118
+ context,
119
+ }) => {
120
+ test.skip(!dockerAvailable(), "Docker not reachable in this environment");
121
+ test.setTimeout(60_000);
122
+
123
+ await withMailpit(async ({ smtpPort }) => {
124
+ const recipient = "password-reset-user@example.com";
125
+ const resetContent = "We received a request to reset your password.";
126
+ await sendTestEmail({
127
+ host: "127.0.0.1",
128
+ port: smtpPort,
129
+ to: recipient,
130
+ subject: "Reset your password",
131
+ // A decoy link comes first - proves ExpectedLinkPattern actually
132
+ // discriminates between two links in the body, not just "the first one".
133
+ html: `<p>${resetContent}</p>
134
+ <a href="https://example.com/report-abuse?ref=xyz">Not you? Report this</a>
135
+ <a href="${HOME_URL}?verified=1">Reset your password</a>`,
136
+ });
137
+
138
+ const mem = new MemPage();
139
+ mem.set(ExpectedRecipient({ email: recipient }));
140
+ mem.set(ExpectedLinkPattern, "verified=1");
141
+ mem.set(ExpectedEmailContent, resetContent);
142
+ const result = await mailVerifyFlow.run(context, mem);
143
+ expect(result).toEqual(checkpoint("HomeVerified"));
144
+ });
145
+ });
146
+
147
+ test("assert-email-received fails loud, naming itself, when no email ever arrives", async ({ context }) => {
148
+ test.skip(!dockerAvailable(), "Docker not reachable in this environment");
149
+ test.setTimeout(30_000);
150
+
151
+ await withMailpit(async () => {
152
+ const mem = new MemPage();
153
+ mem.set(ExpectedRecipient({ email: "nobody-sent-this-one@example.com" }));
154
+ mem.set(ExpectedLinkPattern, "verified=1");
155
+ mem.set(ExpectedEmailContent, VERIFICATION_CONTENT);
156
+ // A defineFlow chain's verify-failure error names the whole path taken so
157
+ // far (each composed Block's own name accumulates through connect()),
158
+ // not just the leaf Block - real, useful QA context, not a bug - so this
159
+ // matches the accumulated name ending at assert-email-received, not an
160
+ // exact "failed after \"assert-email-received\"" alone.
161
+ await expect(mailVerifyFlow.run(context, mem)).rejects.toThrow(
162
+ /trait "email-received" failed after ".*assert-email-received"/,
163
+ );
164
+ });
165
+ });
166
+
167
+ test("assert-email-content fails loud, naming itself, when the email's copy doesn't match", async ({ context }) => {
168
+ test.skip(!dockerAvailable(), "Docker not reachable in this environment");
169
+ test.setTimeout(60_000);
170
+
171
+ await withMailpit(async ({ smtpPort }) => {
172
+ const recipient = "demo-user@example.com";
173
+ await sendTestEmail({
174
+ host: "127.0.0.1",
175
+ port: smtpPort,
176
+ to: recipient,
177
+ subject: "Please verify your account",
178
+ // A real link is present (so this isolates the content check, not the
179
+ // link-extraction step), but the surrounding copy is wrong.
180
+ html: `<p>Your package has shipped!</p><a href="${HOME_URL}?verified=1">Track it</a>`,
181
+ });
182
+
183
+ const mem = new MemPage();
184
+ mem.set(ExpectedRecipient({ email: recipient }));
185
+ mem.set(ExpectedLinkPattern, "verified=1");
186
+ mem.set(ExpectedEmailContent, VERIFICATION_CONTENT);
187
+ await expect(mailVerifyFlow.run(context, mem)).rejects.toThrow(
188
+ /trait "body-contains-expected-text" failed after ".*assert-email-content"/,
189
+ );
190
+ });
191
+ });
@@ -0,0 +1,61 @@
1
+ ---
2
+ name: waygraph-blind-pilot
3
+ description: Cold-start a waygraph project against a real site with zero existing Blocks - navigate with raw primitives, recognize real patterns, and author real Nav/Page/Method Blocks as you go. Use when the target app has no (or very little) waygraph coverage yet, not for driving an already-Block-covered app.
4
+ ---
5
+
6
+ Blind Pilot is the same session mechanism as `waygraph-pilot`, minus the requirement of any
7
+ pre-existing Blocks. `auto --cli --detach` tolerates a project with zero `.block.ts` files -
8
+ `auto click/type/goto/press/upload` act on the real page before any Block exists to cover it.
9
+ This package generates **no Block content for you** - you write real `.block.ts`/`*Sel`/
10
+ mem-key files by hand as you go. That's the whole point: turn one-off exploration into
11
+ permanent, reusable, typed coverage instead of leaving nothing behind.
12
+
13
+ ## The real loop
14
+
15
+ 1. `auto goto <sessionId> <url>` / `auto click` / `auto type` to explore the real page.
16
+ 2. `auto dom <sessionId> --mode full --selector <sel>` to read real structure before writing
17
+ a selector - never guess a selector, confirm it against the real DOM first. `--mode aria`
18
+ is faster for a first pass but can show stale/hidden responsive-duplicate content in some
19
+ real apps (confirmed live: a hidden `lg:hidden` panel's heading text showed up in an aria
20
+ snapshot even when scoped to `main`) - fall back to `--mode full` and check actual CSS
21
+ classes/structure if aria output looks inconsistent with what a screenshot shows.
22
+ 3. Once you recognize a real pattern (a login form, a list-item-with-action row, a modal),
23
+ write the real Blocks for it - `*Sel` object first (grounded in the DOM you just read),
24
+ then `Nav`/`Page`/`Method` Blocks, following `templates/scaffold`'s own folder convention
25
+ (`(group)/<page-slug>/page.block.ts` + `nav.block.ts` + `methods/*.block.ts` + one `*.sel.ts`)
26
+ so the result becomes part of the Waygraph Map, not a scattered one-off file.
27
+ 4. `auto reload <sessionId>` to pick up the newly-written Block(s) without restarting.
28
+ 5. Run the new Block for real via `auto send` - prove it works before moving to the next
29
+ pattern, exactly like any other real Block.
30
+ 6. Ask the user a clarifying question only when something genuinely can't be resolved from
31
+ the DOM alone (is this instance local or published? does a downstream integration exist?)
32
+ - don't ask about things `auto dom` can just answer.
33
+
34
+ ## Real gotchas specific to cold-start authoring
35
+
36
+ - **`discoverGraph`'s per-file import errors are mostly silent.** A malformed newly-written
37
+ Block file can simply vanish from the graph with no error printed anywhere obvious - if a
38
+ Block you just wrote doesn't show up after `auto reload`, check `waygraph graph`'s own
39
+ `skipped` list and the file's syntax directly, don't assume it just needs more time.
40
+ - **`defineAssertBlock` needs no `<In, Out>` generic to type-check** (`checkpoint: "X"` alone
41
+ is enough for TypeScript to infer it) - but older/naive static-graph discovery logic may
42
+ rely on parsing an explicit generic from source text. If a freshly-written
43
+ `defineAssertBlock` Block is missing from `waygraph graph`'s edges (silently, no error),
44
+ check whether this package's own `graph.ts` has the matching-marker fix for it, or add an
45
+ explicit generic type argument as a workaround.
46
+ - **A `<p>`/text-based selector often needs scoping**, not just a class name - a sibling
47
+ "chat list item" and "message preview" frequently share the exact same CSS classes in real
48
+ apps, distinguished only by DOM position (first vs second child of a specific wrapper).
49
+ Confirm via `auto dom --mode full` before assuming a class alone is unique enough.
50
+ - **Confirm a selector count, not just its first match**, when building anything the menu
51
+ will expand into multiple live rows (an `instanceOptions`-driven Block) - `auto dom`'s
52
+ default read can silently show only one match even when several exist; check the real
53
+ page count (e.g. via a scoped debug script) before assuming a plain `.first()` is safe
54
+ long-term. A `.first()`-shaped Block is a legitimate STARTING point for a page that only
55
+ ever has one real row to act on - promote it to a mem-driven `defineMemNavBlock` /
56
+ `defineEffectBlock` (see the `waygraph-pilot` skill and
57
+ `examples/saucedemo/.../nav-item-detail.block.ts` for the real pattern) once a second real
58
+ row genuinely exists to pick between, not before.
59
+ - **Prefer the real Pilot overlay over ad hoc status output** when driving a
60
+ `--non-headless` session someone might be watching - it auto-updates on every menu build,
61
+ point a human at the badge/panel instead of re-inventing status reporting.
@@ -0,0 +1,108 @@
1
+ ---
2
+ name: waygraph-pilot
3
+ description: Drive an existing waygraph Block graph as a real agent - use when a task needs to operate a web app that already has waygraph Blocks written for it (login, checkout, matching, chat, admin flows, etc.), not when writing new Blocks from scratch.
4
+ ---
5
+
6
+ Waygraph Pilot is not a planner you call and get an answer from - `pilot start` only
7
+ bootstraps a session and hands you the whole project's Block graph as context. **You** are
8
+ the reasoning agent. Every multi-step decision (which Block to run next, when a route needs
9
+ `reach` vs `send`, when to fall back to raw primitives) is yours to make, turn by turn, by
10
+ reading each `auto status`/`auto send` response.
11
+
12
+ ## Starting a session
13
+
14
+ ```
15
+ waygraph pilot start # bootstraps: {sessionId, socketPath, headless, graph, snapshot}
16
+ waygraph auto status <sessionId> # re-read the live menu, no side effects
17
+ waygraph auto send <sessionId> "<pick>" # run exactly one Block (by menu index or name)
18
+ waygraph auto reach <sessionId> <Checkpoint> # path-find + run a whole route in one call
19
+ ```
20
+
21
+ `graph` in `pilot start`'s response is the **whole project's** Block/Checkpoint graph, not
22
+ just what's reachable from here - use it to plan several steps ahead before you start
23
+ sending picks.
24
+
25
+ ## Rule 1: run real Blocks, not raw primitives
26
+
27
+ Default action is always `auto send`/`auto reach` (a real Block). `auto dom/click/type/
28
+ goto/press/upload` are for genuine gaps only - a page no Block covers yet. Before reaching
29
+ for a raw primitive, check `auto status`'s own menu: if a Block already does this, use it.
30
+ A raw click finishes the moment's task but leaves nothing typed, reusable, or re-runnable -
31
+ the entire reason this package exists. If a needed action truly has no Block, write one
32
+ properly (mirroring a sibling Block's shape) and `auto reload` it in rather than raw-clicking
33
+ past the gap.
34
+
35
+ The one legitimate exception: `auto dom` to resolve a real ambiguity the menu's own labels
36
+ can't (e.g. two products tied at the same displayed price) - and say so explicitly when you
37
+ do it.
38
+
39
+ ## Rule 2: `resync` fixes a stale position, but has its own real limit
40
+
41
+ `auto resync <sessionId>` forces `here` to be re-detected from the live page right now -
42
+ use it whenever something outside this session might have changed the page (a human
43
+ co-driving a visible `--non-headless` session is the real, common case). But `resync` can
44
+ only ever be as good as the project's own Block coverage: if two Checkpoints share a route
45
+ and nothing in their `verify` arrays tells them apart, `resync` will confidently report the
46
+ wrong one. This is a coverage gap in the project's Blocks, not a `resync` bug - if you hit
47
+ one, fix the ambiguity (add a second, concrete `Trait.visible` condition that's only true in
48
+ one of the two states - see `AppHomePageBlock`/`InPoolPageBlock` in a real veciro-waygraph
49
+ example of exactly this: the same `/app` route, split by presence of a "Join Pool" vs
50
+ "Leave pool" button).
51
+
52
+ ## Rule 3: mem is intent, Checkpoint is reality - never blur them
53
+
54
+ Checkpoint is *designed* to be DOM-derivable (that's what `resync` does) - when in doubt,
55
+ trust the DOM for "where am I." Mem is different: it holds the agent's own intent or
56
+ expectation (which row to act on next, what value a later assertion should find) - it must
57
+ never be inferred from the DOM, because doing so breaks assertion Blocks' entire ability to
58
+ catch a real app bug (mem states what's expected, DOM states what's real, `verify` compares
59
+ them - if mem always mirrored the DOM, a genuine bug would just silently agree with itself).
60
+ A Block with an `instanceOptions` re-asserts its own mem input fresh every time it's picked
61
+ from a live menu; a Block without one has no such protection - if something outside your
62
+ control (a human click) might have interfered, re-supply mem explicitly before the next
63
+ step rather than trusting stale state.
64
+
65
+ ## Rule 4: a transition Block needs its OWN `verify`
66
+
67
+ A real bug this exact lesson comes from: a login Block's `act()` (click submit) succeeded
68
+ instantly, but the real backend call failed a moment later (401, unverified email) - well
69
+ after `resolve()` had already optimistically claimed "AppHome." The destination
70
+ Checkpoint's own PageBlock `verify` never ran, because a Block's `verify` is its own, never
71
+ inherited from another Block that merely resolves to the same tag. Without an explicit
72
+ `verify: [Trait.visible(...)]` on the transition Block itself, a real failure silently
73
+ self-reports success instead of failing loud. Any Block whose `act()` can plausibly fail
74
+ server-side after a client-side click needs its own verify - don't assume the destination
75
+ Checkpoint's PageBlock covers it.
76
+
77
+ ## Rule 5: `defineAssertBlock` for "already there, assert a fact" checks
78
+
79
+ The majority shape of real QA/verification: you're already logged in, already at some
80
+ Checkpoint, and need to assert something is true. `defineAssertBlock({ name, checkpoint,
81
+ verify })` is sugar for exactly this - no hand-written act/resolve. For a check whose target
82
+ varies per run (assert a specific matched user's name is present, not a fixed string), hand-
83
+ write a `Trait` object directly instead of the `Trait.visible`/`text` factories - `Trait`'s
84
+ own shape is `{ name, check(page, mem) }`, so a plain object literal gets real mem access a
85
+ factory-built Trait can't. Gate it with `requires: [SomeKey]` so it's correctly hidden from
86
+ the live menu until that mem is actually populated, rather than appearing early and failing
87
+ confusingly.
88
+
89
+ ## Known real environment gotchas
90
+
91
+ - **`auto reload`** picks up an edited/new consumer Block file mid-session, no restart
92
+ needed. It does NOT help if the waygraph *package's own source* changed (a detached
93
+ session process never re-imports its own already-loaded dependencies) - that needs a
94
+ full session restart. It also doesn't help for a non-`.block.ts` file (a `.sel.ts`, a
95
+ shared selector/type file) that some *other* already-loaded Block file imported earlier
96
+ in the session's life - ESM caches that import too, and only the top-level `.block.ts`
97
+ file gets cache-busted on reload. When in doubt after editing a shared file, restart.
98
+ - **HeadlessUI-style popovers** (or similar open/close transitions) sometimes aren't
99
+ interactable the instant their trigger is clicked - a real, reproducible flake, not
100
+ paranoia. A short `page.waitForTimeout(300-400)` between opening a popover and acting
101
+ inside it is a real, load-bearing fix seen live more than once, not defensive padding.
102
+ - **Orphan Blocks** (not wired into any `.flow.ts`) are still fully visible and runnable in
103
+ the live Pilot menu - orphan status only blocks `auto --blocks <From> <To>` pathfinding,
104
+ never `auto`'s own interactive menu.
105
+ - A hard `page.goto()` straight to an SPA route can render a stale/incomplete view compared
106
+ to reaching the same page via a real in-app click-nav - if `auto dom` output looks wrong
107
+ right after a raw `goto`, try reaching the page through its real click-based NavBlock
108
+ instead before assuming the DOM read is broken.
@@ -1,72 +0,0 @@
1
- # Sauce Demo - convention showcase
2
-
3
- Full live consumer for [saucedemo.com](https://www.saucedemo.com). This tree is
4
- the **reference** for waygraph consumer conventions:
5
-
6
- - Route folders under `src/blocks/saucedemo-web/` = real Swag Labs URLs
7
- - **Nav** / **Effect** / **Action** file kinds (helpers are TypeScript salt;
8
- runtime is still `Block`)
9
- - `instanceOptions` menus for `waygraph auto` (Add/Remove + Open details)
10
- - Detailed Kind / Helper / Route comments on every Block file
11
- - Per-route `NAV.md` + root `src/blocks/SITE-MAP.md`
12
-
13
- **GitHub Pages walkthrough:**
14
- [docs/saucedemo](https://deviate-dv8.github.io/waygraph/saucedemo/)
15
- (`docs/saucedemo/` in this repo - README, SITE-MAP, kinds, layout, auto, comments).
16
-
17
- `waygraph try demo` copies the sibling template at `templates/quickstart`
18
- (same Blocks) into an OS temp dir.
19
-
20
- ## Setup
21
-
22
- From the waygraph package root (after `npm run build`):
23
-
24
- ```bash
25
- cd examples/saucedemo
26
- npm install
27
- npx playwright install chromium
28
- ```
29
-
30
- ## Commands
31
-
32
- | Want | Command |
33
- |------|---------|
34
- | Headless suite | `npm test` |
35
- | Interactive explore (headed panel) | `npm run auto` |
36
- | Interactive explore (terminal menu) | `npm run auto:cli` |
37
- | Shop demo stepper | `npm run demo:step` |
38
- | Shop demo autoplay | `npm run demo:autoplay` |
39
- | **Cart bulk** demo (named flow) | `npm run demo:bulk` |
40
- | Cart bulk stepper | `npm run demo:bulk:step` |
41
- | **Cart bulk** chain (Block names only) | `npm run chain:bulk` |
42
- | List flows | `npm run flows` |
43
-
44
- **Demo vs auto vs chain for cart bulk**
45
-
46
- | | CLI | Needs `.flow.ts`? |
47
- |--|-----|-------------------|
48
- | **`chain` (block names)** | `npm run chain:bulk` → `loginFlow({…}) then add-all-to-cart then remove-all-from-cart` | No — Block `.name` only |
49
- | **`demo` (named flow)** | `npm run demo:bulk` → `cartBulkFlow` | Yes — `cart-bulk.flow.ts` |
50
- | **`auto` (pick live)** | `npm run auto` / `auto:cli` | No — menu from graph |
51
-
52
- Same Blocks either way. `chain` is the ad-hoc path (handout-style `"A then B then C"`).
53
-
54
- ## Layout (short)
55
-
56
- ```text
57
- src/blocks/
58
- SITE-MAP.md
59
- saucedemo-web/ # URL /
60
- NAV.md
61
- nav-login.block.ts
62
- methods/ # submit-login, logout, …
63
- inventory/ # URL /inventory.html
64
- nav-item-detail.block.ts # MemNav
65
- methods/*.effect.block.ts # Add / Remove
66
- cart/ # URL /cart.html
67
- checkout-step-one/
68
- checkout-step-two/
69
- ```
70
-
71
- Docs: [Sauce Demo showcase](../../docs/saucedemo/) ·
72
- [Auto explore](../../docs/auto.html) · [Consumer layout](../../docs/consumer.html)
@@ -1,12 +0,0 @@
1
- # Site map (scaffold)
2
-
3
- Offline catalog uses one synthetic namespace (`demo-web/`) and a local
4
- `home.html` fixture so `npm test` / `waygraph auto` need no network.
5
-
6
- | Folder | URL | Notes |
7
- |--------|-----|-------|
8
- | `demo-web/` | `/` (synthetic) | Nav + Page hub + methods/effects |
9
- | `demo-web/methods/` | same URL | assert, add/remove Effects, clear |
10
-
11
- When you wire a real app, rename `demo-web/` to your FE origin namespace and
12
- add one folder per real `page.tsx` route. See **Consumer layout** docs.
@@ -1,29 +0,0 @@
1
- # demo-web / (synthetic home)
2
-
3
- **URL:** `http://127.0.0.1:4177/home.html` (offline catalog via `scripts/fixture-server.mjs` - replace with your real `/`)
4
-
5
- ## Nav-to
6
-
7
- | From | Block | How |
8
- |------|-------|-----|
9
- | start | `nav-home` | `defineNavBlock` `url` → home.html |
10
-
11
- ## Page hub
12
-
13
- | Block | Checkpoint | Methods |
14
- |-------|------------|---------|
15
- | `page-home` | `Home` | add-item, remove-item, clear-cart, assert-hello |
16
-
17
- ## Methods / Effects
18
-
19
- | Block | Kind | Auto |
20
- |-------|------|------|
21
- | `assert-hello` | Method | single row |
22
- | `add-item` | Effect | one row per live Add button (`instanceOptions`) |
23
- | `remove-item` | Effect | one row per live Remove button |
24
- | `clear-cart` | Method | single row |
25
-
26
- ## States / mem-keys
27
-
28
- - Checkpoints: `Home`, `HomeVerified`, `ItemInCart`, `CartEmpty`
29
- - Mem: `demo.selectedItem` (`SelectedItem`) - filled by auto or `--data`
@@ -1,50 +0,0 @@
1
- import { defineMethodBlock, checkpoint, Trait } from "waygraph";
2
- import { DemoSel } from "../demo-sel.js";
3
-
4
- /**
5
- * Kind: Method
6
- * Helper: defineMethodBlock
7
- * Route: demo-web/methods/
8
- *
9
- * Same-URL assert after nav - stubs + fixtures + YAP slide.
10
- */
11
- export const AssertHelloBlock = defineMethodBlock({
12
- name: "assert-hello",
13
- description: "Confirms the hello heading is still visible after arrival.",
14
- instruction: {
15
- async act(_page) {},
16
- async observe(page) {
17
- await page.locator(DemoSel.title).first().waitFor({ state: "visible", timeout: 5_000 });
18
- return "ok" as const;
19
- },
20
- resolve: () => checkpoint("HomeVerified"),
21
- verify: [Trait.text(DemoSel.title, "Hello Waygraph"), Trait.visible(DemoSel.sub)],
22
- stubBefore: {
23
- title: { selector: DemoSel.title, label: "Heading about to check" },
24
- },
25
- stubAfter: {
26
- title: {
27
- selector: DemoSel.title,
28
- label: "Hello confirmed",
29
- detail: "Offline scaffold proof point.",
30
- duration: true,
31
- },
32
- sub: { selector: DemoSel.sub, label: "Subcopy", duration: 1500 },
33
- },
34
- stubOnError: {
35
- title: {
36
- selector: DemoSel.title,
37
- label: "Heading at failure",
38
- tag: "FAIL",
39
- },
40
- },
41
- slides: [
42
- {
43
- caption: "Scaffold covers auto + narration",
44
- detail: "Page hub, Effect instanceOptions, stubs, fixtures, YAP.",
45
- tag: "YAP",
46
- duration: true,
47
- },
48
- ],
49
- },
50
- });