waygraph 0.13.6 → 0.14.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 (297) hide show
  1. package/README.md +820 -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 +417 -51
  15. package/dist/engine.d.ts +40 -1
  16. package/dist/engine.js +82 -0
  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/pilot-overlay.d.ts +88 -0
  24. package/dist/pilot-overlay.js +363 -0
  25. package/dist/pilot.d.ts +49 -0
  26. package/dist/pilot.js +53 -0
  27. package/dist/trait.d.ts +22 -0
  28. package/dist/trait.js +60 -3
  29. package/examples/routed-demo/package.json +26 -0
  30. package/examples/routed-demo/playwright.config.ts +20 -0
  31. package/examples/routed-demo/scripts/fixture-server.mjs +37 -0
  32. package/examples/routed-demo/scripts/with-fixture.mjs +70 -0
  33. package/examples/routed-demo/src/flows/routed-demo.flow.ts +12 -0
  34. package/examples/routed-demo/src/pages/dashboard.html +10 -0
  35. package/examples/routed-demo/src/pages/docs.html +8 -0
  36. package/examples/routed-demo/src/routes/(base_app)/dashboard/dashboard.sel.ts +10 -0
  37. package/examples/routed-demo/src/routes/(base_app)/dashboard/methods/click-widget.block.ts +23 -0
  38. package/examples/routed-demo/src/routes/(base_app)/dashboard/nav.block.ts +18 -0
  39. package/examples/routed-demo/src/routes/(base_app)/dashboard/page.block.ts +22 -0
  40. package/examples/routed-demo/src/routes/(external)/docs/docs.sel.ts +7 -0
  41. package/examples/routed-demo/src/routes/(external)/docs/nav.block.ts +21 -0
  42. package/examples/routed-demo/src/routes/(external)/docs/page.block.ts +15 -0
  43. package/examples/routed-demo/src/states/routed-demo.states.ts +10 -0
  44. package/examples/routed-demo/tests/routed-demo.spec.ts +75 -0
  45. package/examples/routed-demo/tsconfig.json +18 -0
  46. package/examples/routed-demo-consumer/package.json +18 -0
  47. package/examples/saucedemo/.waygraph-auto/010dd92b.log +0 -0
  48. package/examples/saucedemo/.waygraph-auto/011ad671.log +0 -0
  49. package/examples/saucedemo/.waygraph-auto/01b45645.log +0 -0
  50. package/examples/saucedemo/.waygraph-auto/03764153.log +0 -0
  51. package/examples/saucedemo/.waygraph-auto/0593587e.log +0 -0
  52. package/examples/saucedemo/.waygraph-auto/06d12823.log +0 -0
  53. package/examples/saucedemo/.waygraph-auto/0b1f5b26.json +8 -0
  54. package/examples/saucedemo/.waygraph-auto/0c00f25f.log +0 -0
  55. package/examples/saucedemo/.waygraph-auto/0e480591.log +0 -0
  56. package/examples/saucedemo/.waygraph-auto/110958b8.log +0 -0
  57. package/examples/saucedemo/.waygraph-auto/138107c1.log +0 -0
  58. package/examples/saucedemo/.waygraph-auto/159d541b.log +0 -0
  59. package/examples/saucedemo/.waygraph-auto/16aa2c01.log +0 -0
  60. package/examples/saucedemo/.waygraph-auto/16c35dd5.log +0 -0
  61. package/examples/saucedemo/.waygraph-auto/1706547d.log +0 -0
  62. package/examples/saucedemo/.waygraph-auto/17537e42.log +0 -0
  63. package/examples/saucedemo/.waygraph-auto/17ede493.log +0 -0
  64. package/examples/saucedemo/.waygraph-auto/1fe2414f.log +0 -0
  65. package/examples/saucedemo/.waygraph-auto/1fe2e3b8.log +0 -0
  66. package/examples/saucedemo/.waygraph-auto/25f68ada.log +0 -0
  67. package/examples/saucedemo/.waygraph-auto/26ca9cd8.log +0 -0
  68. package/examples/saucedemo/.waygraph-auto/2bb6c4e8.log +0 -0
  69. package/examples/saucedemo/.waygraph-auto/2d425004.log +0 -0
  70. package/examples/saucedemo/.waygraph-auto/2f5b3ea6.log +0 -0
  71. package/examples/saucedemo/.waygraph-auto/31bb303d.log +0 -0
  72. package/examples/saucedemo/.waygraph-auto/31f2042f.log +0 -0
  73. package/examples/saucedemo/.waygraph-auto/36551ec1.log +0 -0
  74. package/examples/saucedemo/.waygraph-auto/36a1c274.log +0 -0
  75. package/examples/saucedemo/.waygraph-auto/381aa338.log +0 -0
  76. package/examples/saucedemo/.waygraph-auto/3882bce1.log +0 -0
  77. package/examples/saucedemo/.waygraph-auto/38acd1dc.log +0 -0
  78. package/examples/saucedemo/.waygraph-auto/3b8b77b9.log +0 -0
  79. package/examples/saucedemo/.waygraph-auto/4028d2a2.log +0 -0
  80. package/examples/saucedemo/.waygraph-auto/4168b208.log +0 -0
  81. package/examples/saucedemo/.waygraph-auto/43ab66ce.log +0 -0
  82. package/examples/saucedemo/.waygraph-auto/43f66838.log +0 -0
  83. package/examples/saucedemo/.waygraph-auto/442171d4.log +0 -0
  84. package/examples/saucedemo/.waygraph-auto/453b1ce1.log +0 -0
  85. package/examples/saucedemo/.waygraph-auto/457322bd.log +0 -0
  86. package/examples/saucedemo/.waygraph-auto/46197027.log +0 -0
  87. package/examples/saucedemo/.waygraph-auto/46889468.log +0 -0
  88. package/examples/saucedemo/.waygraph-auto/4890da1c.log +0 -0
  89. package/examples/saucedemo/.waygraph-auto/4893a63b.log +0 -0
  90. package/examples/saucedemo/.waygraph-auto/4af71440.log +0 -0
  91. package/examples/saucedemo/.waygraph-auto/4f7496d1.log +0 -0
  92. package/examples/saucedemo/.waygraph-auto/50e8baaa.log +0 -0
  93. package/examples/saucedemo/.waygraph-auto/52b3a455.log +0 -0
  94. package/examples/saucedemo/.waygraph-auto/532dd9b8.log +0 -0
  95. package/examples/saucedemo/.waygraph-auto/5391ce40.log +0 -0
  96. package/examples/saucedemo/.waygraph-auto/57dbddb3.log +0 -0
  97. package/examples/saucedemo/.waygraph-auto/5897f501.log +0 -0
  98. package/examples/saucedemo/.waygraph-auto/59c0b57d.log +0 -0
  99. package/examples/saucedemo/.waygraph-auto/5b511794.log +0 -0
  100. package/examples/saucedemo/.waygraph-auto/5c47910f.log +0 -0
  101. package/examples/saucedemo/.waygraph-auto/5eda8273.log +0 -0
  102. package/examples/saucedemo/.waygraph-auto/621518ad.log +0 -0
  103. package/examples/saucedemo/.waygraph-auto/632b7118.log +0 -0
  104. package/examples/saucedemo/.waygraph-auto/64314c2b.log +0 -0
  105. package/examples/saucedemo/.waygraph-auto/66516213.log +0 -0
  106. package/examples/saucedemo/.waygraph-auto/66c17079.log +0 -0
  107. package/examples/saucedemo/.waygraph-auto/69bf0b80.log +0 -0
  108. package/examples/saucedemo/.waygraph-auto/69c2347a.log +0 -0
  109. package/examples/saucedemo/.waygraph-auto/6d22bdb0.log +0 -0
  110. package/examples/saucedemo/.waygraph-auto/7103bebb.log +0 -0
  111. package/examples/saucedemo/.waygraph-auto/740c9faa.log +0 -0
  112. package/examples/saucedemo/.waygraph-auto/74872fc5.log +0 -0
  113. package/examples/saucedemo/.waygraph-auto/75846ca9.log +0 -0
  114. package/examples/saucedemo/.waygraph-auto/7626c85b.log +0 -0
  115. package/examples/saucedemo/.waygraph-auto/76308eec.log +0 -0
  116. package/examples/saucedemo/.waygraph-auto/76c1650e.log +0 -0
  117. package/examples/saucedemo/.waygraph-auto/7861f38f.log +0 -0
  118. package/examples/saucedemo/.waygraph-auto/7af224ed.log +0 -0
  119. package/examples/saucedemo/.waygraph-auto/7c3be585.log +0 -0
  120. package/examples/saucedemo/.waygraph-auto/7ed55a2c.log +0 -0
  121. package/examples/saucedemo/.waygraph-auto/80086ba2.log +0 -0
  122. package/examples/saucedemo/.waygraph-auto/80206369.log +0 -0
  123. package/examples/saucedemo/.waygraph-auto/847f1092.log +0 -0
  124. package/examples/saucedemo/.waygraph-auto/8581abfa.log +0 -0
  125. package/examples/saucedemo/.waygraph-auto/87b7e0fd.log +0 -0
  126. package/examples/saucedemo/.waygraph-auto/87c79256.log +0 -0
  127. package/examples/saucedemo/.waygraph-auto/88af2495.log +0 -0
  128. package/examples/saucedemo/.waygraph-auto/8c04a403.log +0 -0
  129. package/examples/saucedemo/.waygraph-auto/8c9ab09e.log +0 -0
  130. package/examples/saucedemo/.waygraph-auto/8cc5db51.log +0 -0
  131. package/examples/saucedemo/.waygraph-auto/8ea3a69c.log +0 -0
  132. package/examples/saucedemo/.waygraph-auto/9150f913.log +0 -0
  133. package/examples/saucedemo/.waygraph-auto/929a4313.log +0 -0
  134. package/examples/saucedemo/.waygraph-auto/95a599e4.log +0 -0
  135. package/examples/saucedemo/.waygraph-auto/96c45350.log +0 -0
  136. package/examples/saucedemo/.waygraph-auto/986030e6.log +0 -0
  137. package/examples/saucedemo/.waygraph-auto/99787abb.log +0 -0
  138. package/examples/saucedemo/.waygraph-auto/99ddb62c.log +0 -0
  139. package/examples/saucedemo/.waygraph-auto/a63a2d20.log +0 -0
  140. package/examples/saucedemo/.waygraph-auto/a78befb7.log +0 -0
  141. package/examples/saucedemo/.waygraph-auto/a84d9b79.log +0 -0
  142. package/examples/saucedemo/.waygraph-auto/a9270890.log +0 -0
  143. package/examples/saucedemo/.waygraph-auto/aa440153.log +0 -0
  144. package/examples/saucedemo/.waygraph-auto/ab7561e0.log +0 -0
  145. package/examples/saucedemo/.waygraph-auto/ac19ae60.log +0 -0
  146. package/examples/saucedemo/.waygraph-auto/ae21ad8e.log +0 -0
  147. package/examples/saucedemo/.waygraph-auto/af09042f.log +0 -0
  148. package/examples/saucedemo/.waygraph-auto/b1684126.log +0 -0
  149. package/examples/saucedemo/.waygraph-auto/b21e9d12.log +0 -0
  150. package/examples/saucedemo/.waygraph-auto/b5a838be.log +0 -0
  151. package/examples/saucedemo/.waygraph-auto/b603549d.log +0 -0
  152. package/examples/saucedemo/.waygraph-auto/b83e6259.log +0 -0
  153. package/examples/saucedemo/.waygraph-auto/b9cb2796.log +0 -0
  154. package/examples/saucedemo/.waygraph-auto/bb0a0018.log +0 -0
  155. package/examples/saucedemo/.waygraph-auto/bc0bdd0e.log +0 -0
  156. package/examples/saucedemo/.waygraph-auto/bc7d4a83.log +0 -0
  157. package/examples/saucedemo/.waygraph-auto/bd8e082a.log +0 -0
  158. package/examples/saucedemo/.waygraph-auto/bea0c93e.log +0 -0
  159. package/examples/saucedemo/.waygraph-auto/bf35201a.log +0 -0
  160. package/examples/saucedemo/.waygraph-auto/bffa3a7a.log +0 -0
  161. package/examples/saucedemo/.waygraph-auto/c4afb8bc.log +0 -0
  162. package/examples/saucedemo/.waygraph-auto/c916a654.log +0 -0
  163. package/examples/saucedemo/.waygraph-auto/c9b8d69e.log +0 -0
  164. package/examples/saucedemo/.waygraph-auto/d02e5e7e.log +0 -0
  165. package/examples/saucedemo/.waygraph-auto/d09aff71.log +0 -0
  166. package/examples/saucedemo/.waygraph-auto/d0e41396.log +0 -0
  167. package/examples/saucedemo/.waygraph-auto/d1370d76.log +0 -0
  168. package/examples/saucedemo/.waygraph-auto/d3714ae4.log +0 -0
  169. package/examples/saucedemo/.waygraph-auto/da0685dc.log +0 -0
  170. package/examples/saucedemo/.waygraph-auto/da894ad8.log +0 -0
  171. package/examples/saucedemo/.waygraph-auto/daa2f922.log +0 -0
  172. package/examples/saucedemo/.waygraph-auto/daefb614.log +0 -0
  173. package/examples/saucedemo/.waygraph-auto/db97e833.log +0 -0
  174. package/examples/saucedemo/.waygraph-auto/e101d19a.log +0 -0
  175. package/examples/saucedemo/.waygraph-auto/e207c989.log +0 -0
  176. package/examples/saucedemo/.waygraph-auto/e633e545.log +0 -0
  177. package/examples/saucedemo/.waygraph-auto/e69aec68.log +0 -0
  178. package/examples/saucedemo/.waygraph-auto/e70e2d06.log +0 -0
  179. package/examples/saucedemo/.waygraph-auto/ebad3410.log +0 -0
  180. package/examples/saucedemo/.waygraph-auto/ecbb0966.log +0 -0
  181. package/examples/saucedemo/.waygraph-auto/ecdee753.log +0 -0
  182. package/examples/saucedemo/.waygraph-auto/ed888783.log +0 -0
  183. package/examples/saucedemo/.waygraph-auto/ed931dac.log +0 -0
  184. package/examples/saucedemo/.waygraph-auto/ef655a3f.log +0 -0
  185. package/examples/saucedemo/.waygraph-auto/f3c29b21.log +0 -0
  186. package/examples/saucedemo/.waygraph-auto/f53f7cfc.log +0 -0
  187. package/examples/saucedemo/.waygraph-auto/f5ad5830.log +0 -0
  188. package/examples/saucedemo/.waygraph-auto/faed36dd.log +0 -0
  189. package/examples/saucedemo/docs/CONVENTION.md +25 -5
  190. package/examples/saucedemo/docs/HELPERS.md +15 -4
  191. package/examples/saucedemo/scripts/capture-wrong-login.mjs +8 -2
  192. package/examples/saucedemo/scripts/prove-wrong-login-runtime.mjs +8 -2
  193. package/examples/saucedemo/src/blocks/SITE-MAP.md +14 -3
  194. package/examples/saucedemo/src/blocks/saucedemo-web/NAV.md +15 -1
  195. package/examples/saucedemo/src/blocks/saucedemo-web/cart/NAV.md +1 -0
  196. package/examples/saucedemo/src/blocks/saucedemo-web/cart/cart.sel.ts +9 -0
  197. package/examples/saucedemo/src/blocks/saucedemo-web/cart/nav-cart.block.ts +3 -2
  198. package/examples/saucedemo/src/blocks/saucedemo-web/cart/nav-checkout-info.block.ts +2 -1
  199. package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/NAV.md +6 -1
  200. package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/methods/checkout-info.sel.ts +11 -0
  201. package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/methods/fill-first-name.method.block.ts +22 -0
  202. package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/methods/fill-last-name.method.block.ts +21 -0
  203. package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/methods/fill-postal-code.method.block.ts +21 -0
  204. package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/methods/submit-checkout-info.method.block.ts +6 -7
  205. package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-two/NAV.md +2 -0
  206. package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-two/methods/checkout-overview.sel.ts +9 -0
  207. package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-two/methods/finish-order.method.block.ts +7 -6
  208. package/examples/saucedemo/src/blocks/saucedemo-web/ff-owner-auth.block.ts +7 -2
  209. package/examples/saucedemo/src/blocks/saucedemo-web/inventory-item/NAV.md +1 -0
  210. package/examples/saucedemo/src/blocks/saucedemo-web/inventory-item/item-detail.sel.ts +9 -0
  211. package/examples/saucedemo/src/blocks/saucedemo-web/inventory-item/nav-back-to-inventory.block.ts +2 -1
  212. package/examples/saucedemo/src/blocks/saucedemo-web/inventory-item/nav-back-to-products.block.ts +2 -1
  213. package/examples/saucedemo/src/blocks/saucedemo-web/inventory-item/nav-continue-shopping.block.ts +2 -1
  214. package/examples/saucedemo/src/blocks/saucedemo-web/methods/fill-password.method.block.ts +51 -0
  215. package/examples/saucedemo/src/blocks/saucedemo-web/methods/fill-username.method.block.ts +69 -0
  216. package/examples/saucedemo/src/blocks/saucedemo-web/methods/login.sel.ts +13 -0
  217. package/examples/saucedemo/src/blocks/saucedemo-web/methods/submit-login-for-flow.ts +4 -4
  218. package/examples/saucedemo/src/blocks/saucedemo-web/methods/submit-login.method.block.ts +13 -51
  219. package/examples/saucedemo/src/blocks/saucedemo-web/methods/submit-logout.method.block.ts +4 -3
  220. package/examples/saucedemo/src/blocks/saucedemo-web/nav-login.block.ts +14 -6
  221. package/examples/saucedemo/src/flows/checkout-then-browse-again.flow.ts +15 -0
  222. package/examples/saucedemo/src/flows/checkout.flow.ts +20 -2
  223. package/examples/saucedemo/src/flows/device-showcase.flow.ts +4 -0
  224. package/examples/saucedemo/src/flows/login.flow.ts +3 -1
  225. package/examples/saucedemo/src/flows/shop.flow.ts +6 -0
  226. package/examples/saucedemo/src/flows/smoke.flow.ts +13 -7
  227. package/examples/saucedemo/src/flows/stub-on-error.flow.ts +4 -2
  228. package/examples/saucedemo/src/flows/viewer-blocked.flow.ts +6 -2
  229. package/examples/saucedemo/tests/flow-block-verify.spec.ts +3 -3
  230. package/examples/saucedemo/tests/submit-login-branch.spec.ts +5 -3
  231. package/package.json +2 -1
  232. package/templates/agents/waygraph-author.agent.md +43 -5
  233. package/templates/agents/waygraph-planner.agent.md +33 -2
  234. package/templates/quickstart/src/blocks/saucedemo-web/NAV.md +15 -1
  235. package/templates/quickstart/src/blocks/saucedemo-web/cart/NAV.md +1 -0
  236. package/templates/quickstart/src/blocks/saucedemo-web/cart/cart.sel.ts +9 -0
  237. package/templates/quickstart/src/blocks/saucedemo-web/cart/nav-cart.block.ts +19 -15
  238. package/templates/quickstart/src/blocks/saucedemo-web/cart/nav-checkout-info.block.ts +2 -1
  239. package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/NAV.md +6 -1
  240. package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/methods/checkout-info.sel.ts +11 -0
  241. package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/methods/fill-first-name.method.block.ts +22 -0
  242. package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/methods/fill-last-name.method.block.ts +21 -0
  243. package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/methods/fill-postal-code.method.block.ts +21 -0
  244. package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/methods/submit-checkout-info.method.block.ts +6 -7
  245. package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-two/NAV.md +2 -0
  246. package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-two/methods/checkout-overview.sel.ts +9 -0
  247. package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-two/methods/finish-order.method.block.ts +7 -6
  248. package/templates/quickstart/src/blocks/saucedemo-web/ff-owner-auth.block.ts +7 -2
  249. package/templates/quickstart/src/blocks/saucedemo-web/inventory/methods/add-to-cart.effect.block.ts +24 -16
  250. package/templates/quickstart/src/blocks/saucedemo-web/inventory/nav-item-detail.block.ts +3 -3
  251. package/templates/quickstart/src/blocks/saucedemo-web/inventory-item/NAV.md +1 -0
  252. package/templates/quickstart/src/blocks/saucedemo-web/inventory-item/item-detail.sel.ts +9 -0
  253. package/templates/quickstart/src/blocks/saucedemo-web/inventory-item/nav-back-to-inventory.block.ts +2 -1
  254. package/templates/quickstart/src/blocks/saucedemo-web/inventory-item/nav-back-to-products.block.ts +2 -1
  255. package/templates/quickstart/src/blocks/saucedemo-web/inventory-item/nav-continue-shopping.block.ts +2 -1
  256. package/templates/quickstart/src/blocks/saucedemo-web/methods/fill-password.method.block.ts +51 -0
  257. package/templates/quickstart/src/blocks/saucedemo-web/methods/fill-username.method.block.ts +69 -0
  258. package/templates/quickstart/src/blocks/saucedemo-web/methods/login.sel.ts +13 -0
  259. package/templates/quickstart/src/blocks/saucedemo-web/methods/submit-login-for-flow.ts +4 -4
  260. package/templates/quickstart/src/blocks/saucedemo-web/methods/submit-login.method.block.ts +35 -63
  261. package/templates/quickstart/src/blocks/saucedemo-web/methods/submit-logout.method.block.ts +4 -3
  262. package/templates/quickstart/src/blocks/saucedemo-web/nav-login.block.ts +14 -6
  263. package/templates/quickstart/src/flows/checkout-then-browse-again.flow.ts +15 -0
  264. package/templates/quickstart/src/flows/checkout.flow.ts +29 -2
  265. package/templates/quickstart/src/flows/device-showcase.flow.ts +4 -0
  266. package/templates/quickstart/src/flows/login.flow.ts +3 -1
  267. package/templates/quickstart/src/flows/shop.flow.ts +6 -0
  268. package/templates/quickstart/src/flows/smoke.flow.ts +13 -7
  269. package/templates/quickstart/src/flows/viewer-blocked.flow.ts +6 -2
  270. package/templates/quickstart/tests/chain-flow.spec.ts +8 -1
  271. package/templates/scaffold/STRUCTURE.md +23 -3
  272. package/templates/scaffold/src/blocks/demo-external/mailpit/mailpit-inbox.page.block.ts +30 -0
  273. package/templates/scaffold/src/blocks/demo-external/mailpit/mailpit-sel.ts +5 -0
  274. package/templates/scaffold/src/blocks/demo-external/mailpit/methods/assert-email-content.method.block.ts +48 -0
  275. package/templates/scaffold/src/blocks/demo-external/mailpit/methods/assert-email-received.method.block.ts +49 -0
  276. package/templates/scaffold/src/blocks/demo-external/mailpit/methods/extract-email-link.method.block.ts +41 -0
  277. package/templates/scaffold/src/blocks/demo-external/mailpit/methods/open-message.method.block.ts +39 -0
  278. package/templates/scaffold/src/blocks/demo-external/mailpit/nav-mailpit-inbox.block.ts +20 -0
  279. package/templates/scaffold/src/blocks/demo-web/demo-sel.ts +1 -0
  280. package/templates/scaffold/src/blocks/demo-web/docs.html +8 -0
  281. package/templates/scaffold/src/blocks/demo-web/home.html +4 -0
  282. package/templates/scaffold/src/blocks/demo-web/methods/assert-hello.method.block.ts +34 -38
  283. package/templates/scaffold/src/blocks/demo-web/methods/assert-item-added.method.block.ts +38 -0
  284. package/templates/scaffold/src/blocks/demo-web/nav-verification-link.block.ts +34 -0
  285. package/templates/scaffold/src/flows/mail-verify.flow.ts +85 -0
  286. package/templates/scaffold/src/flows/routes-demo.flow.ts +14 -0
  287. package/templates/scaffold/src/flows/shop.flow.ts +19 -2
  288. package/templates/scaffold/src/routes/(external)/docs/docs.sel.ts +7 -0
  289. package/templates/scaffold/src/routes/(external)/docs/nav.block.ts +21 -0
  290. package/templates/scaffold/src/routes/(external)/docs/page.block.ts +15 -0
  291. package/templates/scaffold/src/states/demo.mem-keys.ts +25 -1
  292. package/templates/scaffold/src/states/demo.states.ts +13 -0
  293. package/templates/scaffold/test-results/.last-run.json +4 -0
  294. package/templates/scaffold/tests/mail-verify.spec.ts +191 -0
  295. package/templates/skills/waygraph-blind-pilot.skill.md +61 -0
  296. package/templates/skills/waygraph-pilot.skill.md +108 -0
  297. package/templates/quickstart/README-saucedemo-commands.md +0 -72
package/dist/cli.js CHANGED
@@ -19,6 +19,8 @@ import { fileURLToPath } from "node:url";
19
19
  import { spawn } from "node:child_process";
20
20
  import { discoverGraph, toMermaid, findOrphanBlocks, findBlockPath } from "./graph.js";
21
21
  import { runAutoExplore } from "./auto-explore-run.js";
22
+ import { pilotStart } from "./pilot.js";
23
+ import { spawnDetachedSession, requestSession, runAttachLoop, runAutoServeCommand, } from "./auto-session-ipc.js";
22
24
  import { runAgentDive } from "./agent-dive.js";
23
25
  import { runTraverse } from "./traverse-run.js";
24
26
  import { parseMinEdgeCoverage } from "./traverse-coverage.js";
@@ -232,6 +234,7 @@ import {
232
234
  completeSequentialTodoDock,
233
235
  applyDevicePhase,
234
236
  resolveDeviceState,
237
+ WAYGRAPH_RING_CSS,
235
238
  } from "waygraph";
236
239
 
237
240
  function walkDir(dir, pattern) {
@@ -416,45 +419,10 @@ function seedMemForFlow(mem, flowBlocks, json, label) {
416
419
  // Purely CLI-level orchestration - no engine changes, no change to the
417
420
  // non-STEP path above.
418
421
  const RING_CSS =
419
- "#wg-ring{position:fixed;z-index:2147483646;pointer-events:none;opacity:0;" +
420
- "border:2.5px solid #7C3AED;border-radius:10px;" +
421
- // Opacity fade only - NEVER transition border-color/box-shadow. Tone swaps
422
- // (auto gray -> planned purple -> warning yellow) must snap instantly;
423
- // color transitions read as a muddy gray/purple/yellow morph on ring 2+.
424
- "box-shadow:0 0 0 4px rgba(124,58,237,.16);transition:opacity .3s ease;}" +
425
- // Planned (stubs / fixtures / YAP / instruction.highlights) = purple.
426
- // Automation (verify fallback, unmatched fill/click) = gray - operators
427
- // can ignore engine checks and watch purple + semantic tones.
428
- "#wg-ring[data-tone=planned]{border-color:#7C3AED;box-shadow:0 0 0 4px rgba(124,58,237,.16);}" +
429
- "#wg-ring[data-tone=auto]{border-color:#9CA3AF;box-shadow:0 0 0 4px rgba(156,163,175,.28);}" +
430
- "#wg-ring[data-tone=info]{border-color:#3B82F6;box-shadow:0 0 0 4px rgba(59,130,246,.22);}" +
431
- "#wg-ring[data-tone=warning]{border-color:#EAB308;box-shadow:0 0 0 4px rgba(234,179,8,.22);}" +
432
- "#wg-ring[data-tone=danger]{border-color:#EF4444;box-shadow:0 0 0 4px rgba(239,68,68,.22);}" +
433
- "#wg-ring[data-tone=success]{border-color:#22C55E;box-shadow:0 0 0 4px rgba(34,197,94,.22);}" +
434
- // A real element, not a ::after pseudo-element - a pseudo-element's
435
- // position is CSS-relative to the ring's own box (left:0 always meant
436
- // "the ring's own left edge"), so it had no way to be clamped back onto
437
- // screen when that box sat near a viewport edge - the label's text just
438
- // ran off, invisibly, with no overflow guard at all. A real sibling can
439
- // be measured (its actual rendered width) and repositioned in JS -
440
- // pushed back onto screen, same width, never shrunk. See
441
- // window.__wgPositionRing in installOverlay.
442
- "#wg-ring-label{position:fixed;z-index:2147483646;pointer-events:none;opacity:0;" +
443
- "max-width:min(360px,70vw);white-space:normal;padding:6px 10px;border-radius:7px;background:#7C3AED;color:#fff;" +
444
- "font:600 12px/1.35 system-ui,sans-serif;transition:opacity .3s ease;}" +
445
- "#wg-ring-label[data-tone=planned]{background:#7C3AED;color:#fff;}" +
446
- "#wg-ring-label[data-tone=auto]{background:#6B7280;color:#fff;}" +
447
- "#wg-ring-label[data-tone=info]{background:#2563EB;color:#fff;}" +
448
- "#wg-ring-label[data-tone=warning]{background:#EAB308;color:#1c1917;}" +
449
- "#wg-ring-label[data-tone=danger]{background:#DC2626;color:#fff;}" +
450
- "#wg-ring-label[data-tone=success]{background:#16A34A;color:#fff;}" +
451
- // size: ring pad + label font; weight: label boldness
452
- "#wg-ring[data-size=sm]{border-width:1.5px;border-radius:8px;}" +
453
- "#wg-ring[data-size=lg]{border-width:4px;border-radius:12px;}" +
454
- "#wg-ring-label[data-size=sm]{font-size:10px;line-height:1.25;padding:4px 7px;border-radius:5px;}" +
455
- "#wg-ring-label[data-size=lg]{font-size:16px;line-height:1.35;padding:8px 14px;border-radius:9px;max-width:min(480px,85vw);}" +
456
- "#wg-ring-label[data-weight=bold]{font-weight:800;}" +
457
- "#wg-ring-label[data-weight=normal]{font-weight:600;}" +
422
+ // Shared with pilot-overlay.ts's showPilotVision - same ring/label CSS,
423
+ // one source of truth (highlights.ts), so a Blind Pilot vision ring and a
424
+ // demo stepper ring never visually drift apart.
425
+ WAYGRAPH_RING_CSS +
458
426
  // Mouse cursor icon that travels to a target before it's acted on, plus a
459
427
  // quick expanding ripple at the moment of a click - same idea as
460
428
  // help-center-clip-engine's #clip-cursor/#clip-ring (video-pipeline). The
@@ -6343,7 +6311,7 @@ async function validateFlows(projectDir) {
6343
6311
  // instant a regular Block's act() calls a navigation method; this command
6344
6312
  // sweeps a whole project in one shot for contexts with no editor watching
6345
6313
  // (CI, an autonomous agent writing Block files without a language server).
6346
- // See openspec/changes/nav-block-and-check/ for the full rationale.
6314
+ // See openspec/specs/nav-block-and-check/spec.md for the full rationale.
6347
6315
  // ---------------------------------------------------------------------------
6348
6316
  function discoverBlocks(projectDir) {
6349
6317
  return walkDir(projectDir, /\.block\.ts$/);
@@ -6362,6 +6330,19 @@ function isNavBlockMarked(val) {
6362
6330
  return val.__waygraphKind === "nav";
6363
6331
  }
6364
6332
  const NAV_METHOD_CALLS = ["page.goto(", "page.reload(", "page.goBack(", "page.goForward("];
6333
+ /**
6334
+ * Matches a selector-taking Trait factory call whose first argument is a
6335
+ * literal string/template, not an identifier or property access - the exact
6336
+ * shape found repeatedly in hand-written assertion Blocks
6337
+ * (`Trait.visible("#some-id")` instead of `Trait.visible(SomeSel.thing)`).
6338
+ * `Trait.url(...)` is deliberately excluded - it takes a URLPatternInit, never
6339
+ * a DOM selector. Same file-scoped-regex bluntness the nav-escape sweep above
6340
+ * already accepts (see openspec/specs/nav-block-and-check/spec.md) - a known
6341
+ * blind spot on string concatenation/template-built selectors, not solved
6342
+ * here for the same "recipe before promotion" reason that check accepts its
6343
+ * own shared-helper blind spot.
6344
+ */
6345
+ const INLINE_SELECTOR_CALL = /\b(?:Trait\.visible|Trait\.text|textEquals|visible)\(\s*["'`]/;
6365
6346
  /**
6366
6347
  * Walks every `*.block.ts` file under `projectDir`, imports each to find its
6367
6348
  * exported Blocks, and for any Block NOT built via `defineNavBlock`, scans
@@ -6457,7 +6438,8 @@ function initCommand(projectName) {
6457
6438
  }
6458
6439
  async function checkCommand(projectDir) {
6459
6440
  const files = discoverBlocks(projectDir);
6460
- const warnings = [];
6441
+ const navWarnings = [];
6442
+ const selWarnings = [];
6461
6443
  for (const file of files) {
6462
6444
  let mod;
6463
6445
  try {
@@ -6470,15 +6452,21 @@ async function checkCommand(projectDir) {
6470
6452
  for (const [exportName, exported] of Object.entries(mod)) {
6471
6453
  if (!isBlockLike(exported))
6472
6454
  continue;
6473
- if (isNavBlockMarked(exported))
6474
- continue;
6475
6455
  src ??= readFileSync(file, "utf-8");
6476
- if (NAV_METHOD_CALLS.some((needle) => src.includes(needle))) {
6477
- warnings.push({ file, blockName: exported.name, exportName });
6456
+ // Nav-escape: NavBlocks are exempt (their generated act() is the one
6457
+ // legitimate goto/click call site).
6458
+ if (!isNavBlockMarked(exported) &&
6459
+ NAV_METHOD_CALLS.some((needle) => src.includes(needle))) {
6460
+ navWarnings.push({ file, blockName: exported.name, exportName });
6461
+ }
6462
+ // Inline selector: applies to every Block kind, including NavBlocks -
6463
+ // a Nav's own `verify` array is just as likely to inline a selector.
6464
+ if (INLINE_SELECTOR_CALL.test(src)) {
6465
+ selWarnings.push({ file, blockName: exported.name, exportName });
6478
6466
  }
6479
6467
  }
6480
6468
  }
6481
- return warnings;
6469
+ return { navWarnings, selWarnings };
6482
6470
  }
6483
6471
  function takeFlagValue(argv, i, a, flag) {
6484
6472
  if (a.startsWith(flag + "=")) {
@@ -6560,6 +6548,9 @@ function parseRunFlags(argv) {
6560
6548
  else if (a === "--cli") {
6561
6549
  out.cli = true;
6562
6550
  }
6551
+ else if (a === "--detach") {
6552
+ out.detach = true;
6553
+ }
6563
6554
  else if (a === "--headed") {
6564
6555
  out.headed = true;
6565
6556
  }
@@ -6881,9 +6872,81 @@ function usage() {
6881
6872
  Primary (less is more):
6882
6873
  waygraph auto [project|.flow.ts] Interactive explore (picker)
6883
6874
  --cli Terminal menu instead of browser panel
6875
+ --cli --detach Run the --cli session as a background socket
6876
+ server; prints {sessionId, socketPath} and exits
6884
6877
  --blocks <From> <To> Graph path-find From->To, then run
6885
6878
  --data '{...}' Mem seed (same as demo/run)
6886
6879
  (pass a .flow.ts to run that flow - same as run)
6880
+ --cli --detach --non-headless Detached session with a real visible browser
6881
+ (same --non-headless flag run/demo already use)
6882
+ waygraph auto send <sessionId> "<pick>" Send one pick to a --detach session, print
6883
+ the resulting state as JSON (no TTY needed)
6884
+ --timeout <ms> Override the 15s default wait for this one call -
6885
+ a single Block can legitimately run a slow real
6886
+ interaction (e.g. a multi-step mouse drag)
6887
+ waygraph auto status <sessionId> Read a --detach session's state (no side effects)
6888
+ waygraph auto attach <sessionId> Reopen an interactive terminal against a
6889
+ running --detach session
6890
+ waygraph auto dom <sessionId> Read the live page's structure (no side effects)
6891
+ --mode aria|full Default aria (Playwright ariaSnapshotJSON, AI mode);
6892
+ full = bounded raw DOM walk (tag/attrs/text/children)
6893
+ --selector <sel> Scope either mode to one element's subtree
6894
+ --depth N Limit snapshot depth (aria: native; full: caller cap)
6895
+ waygraph auto trace <sessionId> Read the session's Checkpoint/Block-level history
6896
+ (no side effects; not raw click/fill recording)
6897
+ waygraph auto console <sessionId> Read the real browser console/pageerror messages and
6898
+ failed (4xx/5xx) network responses seen so far - for
6899
+ diagnosing a silent failure (e.g. a form submit that
6900
+ does nothing observable in the DOM) that inspectDom
6901
+ alone can't explain, since it only reads what actually
6902
+ rendered, not what the page/network actually said
6903
+ waygraph auto storage <sessionId> Read localStorage/sessionStorage plus registered
6904
+ service workers (scope/active URL/state) - client-
6905
+ side state (push-subscription/auth tokens etc.) that
6906
+ never appears in the rendered DOM inspectDom reads
6907
+ waygraph auto click <sessionId> <sel> Click a real element - works even with zero Blocks
6908
+ (Blind Pilot: act before any Block covers this)
6909
+ waygraph auto type <sessionId> <sel> <text> Fill a real input the same way
6910
+ waygraph auto goto <sessionId> <url> Navigate the real live page
6911
+ waygraph auto press <sessionId> <sel> <key>
6912
+ Presses a real key (Playwright name, e.g. Enter,
6913
+ Escape, Tab) on a real focused element - many real
6914
+ inline-edit inputs (no visible Save button until you
6915
+ type) commit on Enter, not blur/click-elsewhere
6916
+ waygraph auto upload <sessionId> <sel> <image|pdf|video|path>
6917
+ Fill a real <input type="file"> - a built-in stub
6918
+ (small, real, valid: assets/stubs/stub.png|pdf|mp4)
6919
+ or a caller-supplied file path
6920
+ (click/type/goto/upload each re-detect the session's Checkpoint afterward,
6921
+ same detection send/status already use)
6922
+ waygraph auto reload <sessionId> Re-discover the project's Block library/graph
6923
+ from disk without restarting the session - picks
6924
+ up a Block written to disk mid-session
6925
+ waygraph auto reach <sessionId> <Checkpoint> Path-find from here to Checkpoint and run
6926
+ the whole route in one call - not one auto send
6927
+ per step. Same findBlockPath BFS auto --blocks
6928
+ <From> <To> already uses, against this session's
6929
+ own live graph/position. Fails loud (not a guess)
6930
+ if a step has several live options on the page
6931
+ (an instanceOptions Block) - use send for that step
6932
+ waygraph auto resync <sessionId> Force here to be re-detected from the real live
6933
+ page right now, discarding whatever was cached -
6934
+ fixes a session's tracked position going stale
6935
+ after anything OUTSIDE this session changed the
6936
+ page (e.g. a human clicking around in a visible
6937
+ --non-headless session someone is co-driving);
6938
+ send/reach never do this on their own, since they
6939
+ only re-detect when the position is already unknown
6940
+ waygraph pilot start Bootstrap for an agent: starts a --detach session
6941
+ (same as auto --cli --detach) AND reads back the
6942
+ whole project's Block graph (same as waygraph
6943
+ graph) in one call - {sessionId, socketPath,
6944
+ headless, graph, snapshot}. Drive it afterward with
6945
+ auto send/status/dom/trace <sessionId> - pilot start
6946
+ does not resolve, narrate, or act on anything itself;
6947
+ planning a multi-step request is the agent's job.
6948
+ --non-headless Real visible browser (same flag as auto/demo/run)
6949
+ --base-url / --data Same as auto/demo/run
6887
6950
  waygraph demo [--blocks <flow|file|spec>] Watch with step overlay (QA path)
6888
6951
  --data '{...}' Mem seed JSON (or inline flow({...}))
6889
6952
  --auto-next Auto-advance steps (alias: --autoplay)
@@ -7311,6 +7374,233 @@ Agents shipped: waygraph-planner, waygraph-author, waygraph-healer.
7311
7374
  }
7312
7375
  case "graph":
7313
7376
  case "auto": {
7377
+ // auto send|status|attach <sessionId> - session control against a
7378
+ // --detach'd background session. Intercepted before the normal
7379
+ // project-directory resolution below, same pattern `try demo|auto|
7380
+ // auto:cli` already uses for a sub-verb positional.
7381
+ if (command === "auto" &&
7382
+ (args[1] === "send" ||
7383
+ args[1] === "status" ||
7384
+ args[1] === "attach" ||
7385
+ args[1] === "dom" ||
7386
+ args[1] === "trace" ||
7387
+ args[1] === "console" ||
7388
+ args[1] === "storage" ||
7389
+ args[1] === "upload" ||
7390
+ args[1] === "click" ||
7391
+ args[1] === "type" ||
7392
+ args[1] === "press" ||
7393
+ args[1] === "goto" ||
7394
+ args[1] === "reload" ||
7395
+ args[1] === "reach" ||
7396
+ args[1] === "resync")) {
7397
+ const sub = args[1];
7398
+ const sessionId = args[2];
7399
+ if (!sessionId) {
7400
+ console.error(`waygraph auto ${sub}: missing <sessionId>`);
7401
+ process.exit(1);
7402
+ }
7403
+ const proj = resolve(process.cwd());
7404
+ if (sub === "attach") {
7405
+ await runAttachLoop(proj, sessionId);
7406
+ break;
7407
+ }
7408
+ if (sub === "send") {
7409
+ const pick = args[3];
7410
+ if (pick === undefined) {
7411
+ console.error('waygraph auto send: usage: waygraph auto send <sessionId> "<pick>" [--timeout <ms>]');
7412
+ process.exit(1);
7413
+ }
7414
+ // Real, direct need found live: a single Block can legitimately
7415
+ // run a genuinely slow real interaction (e.g. a multi-step mouse
7416
+ // drag) that exceeds the 15s default - same reasoning `auto
7417
+ // reach` already gets a 90s default for (multiple Blocks in one
7418
+ // call). Unlike reach, send has no way to know ahead of time
7419
+ // whether the ONE Block it's running is fast or slow, so this is
7420
+ // opt-in via a flag rather than a raised default.
7421
+ let timeoutMs;
7422
+ for (let i = 4; i < args.length; i++) {
7423
+ if (args[i] === "--timeout") {
7424
+ const raw = args[++i];
7425
+ const n = Number(raw);
7426
+ if (!Number.isFinite(n) || n <= 0) {
7427
+ console.error(`waygraph auto send: --timeout must be a positive number of ms, got "${raw}"`);
7428
+ process.exit(1);
7429
+ }
7430
+ timeoutMs = n;
7431
+ }
7432
+ }
7433
+ const res = await requestSession(proj, sessionId, { op: "send", pick }, timeoutMs);
7434
+ console.log(JSON.stringify(res));
7435
+ if (!res.ok)
7436
+ process.exitCode = 1;
7437
+ break;
7438
+ }
7439
+ if (sub === "dom") {
7440
+ const domArgs = args.slice(3);
7441
+ let mode;
7442
+ let selector;
7443
+ let depth;
7444
+ for (let i = 0; i < domArgs.length; i++) {
7445
+ const a = domArgs[i];
7446
+ if (a === "--mode" || a.startsWith("--mode=")) {
7447
+ const v = a.startsWith("--mode=") ? a.slice("--mode=".length) : domArgs[++i];
7448
+ if (v !== "aria" && v !== "full") {
7449
+ console.error(`waygraph auto dom: --mode must be "aria" or "full", got "${v}"`);
7450
+ process.exit(1);
7451
+ }
7452
+ mode = v;
7453
+ }
7454
+ else if (a === "--selector" || a.startsWith("--selector=")) {
7455
+ selector = a.startsWith("--selector=") ? a.slice("--selector=".length) : domArgs[++i];
7456
+ }
7457
+ else if (a === "--depth" || a.startsWith("--depth=")) {
7458
+ const raw = a.startsWith("--depth=") ? a.slice("--depth=".length) : domArgs[++i];
7459
+ const n = Number(raw);
7460
+ if (!Number.isInteger(n) || n < 1) {
7461
+ console.error(`waygraph auto dom: --depth must be a positive integer, got "${raw}"`);
7462
+ process.exit(1);
7463
+ }
7464
+ depth = n;
7465
+ }
7466
+ else {
7467
+ console.error(`waygraph auto dom: unrecognized argument "${a}"`);
7468
+ process.exit(1);
7469
+ }
7470
+ }
7471
+ const res = await requestSession(proj, sessionId, {
7472
+ op: "dom",
7473
+ ...(mode ? { mode } : {}),
7474
+ ...(selector ? { selector } : {}),
7475
+ ...(depth !== undefined ? { depth } : {}),
7476
+ });
7477
+ console.log(JSON.stringify(res));
7478
+ if (!res.ok)
7479
+ process.exitCode = 1;
7480
+ break;
7481
+ }
7482
+ if (sub === "trace") {
7483
+ const res = await requestSession(proj, sessionId, { op: "trace" });
7484
+ console.log(JSON.stringify(res));
7485
+ if (!res.ok)
7486
+ process.exitCode = 1;
7487
+ break;
7488
+ }
7489
+ if (sub === "console") {
7490
+ const res = await requestSession(proj, sessionId, { op: "console" });
7491
+ console.log(JSON.stringify(res));
7492
+ if (!res.ok)
7493
+ process.exitCode = 1;
7494
+ break;
7495
+ }
7496
+ if (sub === "storage") {
7497
+ const res = await requestSession(proj, sessionId, { op: "storage" });
7498
+ console.log(JSON.stringify(res));
7499
+ if (!res.ok)
7500
+ process.exitCode = 1;
7501
+ break;
7502
+ }
7503
+ if (sub === "click") {
7504
+ const selector = args[3];
7505
+ if (selector === undefined) {
7506
+ console.error('waygraph auto click: usage: waygraph auto click <sessionId> "<selector>"');
7507
+ process.exit(1);
7508
+ }
7509
+ const res = await requestSession(proj, sessionId, { op: "click", selector });
7510
+ console.log(JSON.stringify(res));
7511
+ if (!res.ok)
7512
+ process.exitCode = 1;
7513
+ break;
7514
+ }
7515
+ if (sub === "type") {
7516
+ const selector = args[3];
7517
+ const text = args[4];
7518
+ if (selector === undefined || text === undefined) {
7519
+ console.error('waygraph auto type: usage: waygraph auto type <sessionId> "<selector>" "<text>"');
7520
+ process.exit(1);
7521
+ }
7522
+ const res = await requestSession(proj, sessionId, { op: "type", selector, text });
7523
+ console.log(JSON.stringify(res));
7524
+ if (!res.ok)
7525
+ process.exitCode = 1;
7526
+ break;
7527
+ }
7528
+ if (sub === "press") {
7529
+ const selector = args[3];
7530
+ const key = args[4];
7531
+ if (selector === undefined || key === undefined) {
7532
+ console.error('waygraph auto press: usage: waygraph auto press <sessionId> "<selector>" <key>');
7533
+ process.exit(1);
7534
+ }
7535
+ const res = await requestSession(proj, sessionId, { op: "press", selector, key });
7536
+ console.log(JSON.stringify(res));
7537
+ if (!res.ok)
7538
+ process.exitCode = 1;
7539
+ break;
7540
+ }
7541
+ if (sub === "goto") {
7542
+ const url = args[3];
7543
+ if (url === undefined) {
7544
+ console.error("waygraph auto goto: usage: waygraph auto goto <sessionId> <url>");
7545
+ process.exit(1);
7546
+ }
7547
+ const res = await requestSession(proj, sessionId, { op: "goto", url });
7548
+ console.log(JSON.stringify(res));
7549
+ if (!res.ok)
7550
+ process.exitCode = 1;
7551
+ break;
7552
+ }
7553
+ if (sub === "upload") {
7554
+ const selector = args[3];
7555
+ const kindOrPath = args[4];
7556
+ if (selector === undefined || kindOrPath === undefined) {
7557
+ console.error('waygraph auto upload: usage: waygraph auto upload <sessionId> "<selector>" <image|pdf|video|path-to-file>');
7558
+ process.exit(1);
7559
+ }
7560
+ const stub = kindOrPath === "image" || kindOrPath === "pdf" || kindOrPath === "video"
7561
+ ? { selector, stub: kindOrPath }
7562
+ : { selector, stub: { filePath: resolve(process.cwd(), kindOrPath) } };
7563
+ const res = await requestSession(proj, sessionId, { op: "upload", ...stub });
7564
+ console.log(JSON.stringify(res));
7565
+ if (!res.ok)
7566
+ process.exitCode = 1;
7567
+ break;
7568
+ }
7569
+ if (sub === "reload") {
7570
+ const res = await requestSession(proj, sessionId, { op: "reload" });
7571
+ console.log(JSON.stringify(res));
7572
+ if (!res.ok)
7573
+ process.exitCode = 1;
7574
+ break;
7575
+ }
7576
+ if (sub === "reach") {
7577
+ const checkpoint = args[3];
7578
+ if (checkpoint === undefined) {
7579
+ console.error("waygraph auto reach: usage: waygraph auto reach <sessionId> <Checkpoint>");
7580
+ process.exit(1);
7581
+ }
7582
+ // Longer than every other op's default (15s): a real multi-step
7583
+ // route runs several real Blocks in sequence server-side before
7584
+ // responding - a legitimately slow single request, not a hang.
7585
+ const res = await requestSession(proj, sessionId, { op: "reach", checkpoint }, 90_000);
7586
+ console.log(JSON.stringify(res));
7587
+ if (!res.ok)
7588
+ process.exitCode = 1;
7589
+ break;
7590
+ }
7591
+ if (sub === "resync") {
7592
+ const res = await requestSession(proj, sessionId, { op: "resync" });
7593
+ console.log(JSON.stringify(res));
7594
+ if (!res.ok)
7595
+ process.exitCode = 1;
7596
+ break;
7597
+ }
7598
+ const res = await requestSession(proj, sessionId, { op: "status" });
7599
+ console.log(JSON.stringify(res));
7600
+ if (!res.ok)
7601
+ process.exitCode = 1;
7602
+ break;
7603
+ }
7314
7604
  const flags = parseRunFlags(args.slice(1));
7315
7605
  applyRunFlags(flags);
7316
7606
  const mermaid = flags.mermaid === true;
@@ -7345,6 +7635,29 @@ Agents shipped: waygraph-planner, waygraph-author, waygraph-healer.
7345
7635
  " or path-find: waygraph auto --blocks LoginPage OrderComplete");
7346
7636
  process.exit(1);
7347
7637
  }
7638
+ // auto --cli --detach: start the explore session as a background socket
7639
+ // server instead of blocking in the interactive loop. Session control
7640
+ // only applies to --cli (spec: "Headful mode is unaffected").
7641
+ if (command === "auto" && flags.detach) {
7642
+ if (!cliPicker) {
7643
+ console.error("waygraph auto --detach requires --cli (headful has no session control)");
7644
+ process.exit(1);
7645
+ }
7646
+ const baseURL = flags.baseUrl ?? process.env.WAYGRAPH_BASE_URL ?? resolveBaseUrl(proj);
7647
+ try {
7648
+ const meta = await spawnDetachedSession({
7649
+ projectDir: proj,
7650
+ ...(baseURL ? { baseURL } : {}),
7651
+ ...(flags.nonHeadless ? { headless: false } : {}),
7652
+ });
7653
+ console.log(JSON.stringify({ sessionId: meta.sessionId, socketPath: meta.socketPath, headless: meta.headless }));
7654
+ }
7655
+ catch (err) {
7656
+ console.error(`waygraph auto --detach: ${err instanceof Error ? err.message : String(err)}`);
7657
+ process.exit(1);
7658
+ }
7659
+ break;
7660
+ }
7348
7661
  // auto --blocks From To (graph path-find + run)
7349
7662
  // auto --blocks '/regex/' or '**/*.block.ts' (Phase C file select → explore)
7350
7663
  if (command === "auto" && (flags.blocksFromTo || flags.blocks)) {
@@ -7389,6 +7702,49 @@ Agents shipped: waygraph-planner, waygraph-author, waygraph-healer.
7389
7702
  await runAutoExplore(proj, baseURL ? { cli: cliPicker, baseURL } : { cli: cliPicker });
7390
7703
  break;
7391
7704
  }
7705
+ case "pilot": {
7706
+ if (args[1] !== "start") {
7707
+ console.error('waygraph pilot: usage: waygraph pilot start [--non-headless] [--base-url <url>] [--data <json>]');
7708
+ process.exit(1);
7709
+ }
7710
+ const flags = parseRunFlags(args.slice(2));
7711
+ applyRunFlags(flags);
7712
+ const proj = resolve(process.cwd());
7713
+ const baseURL = flags.baseUrl ?? process.env.WAYGRAPH_BASE_URL ?? resolveBaseUrl(proj);
7714
+ try {
7715
+ const result = await pilotStart({
7716
+ projectDir: proj,
7717
+ ...(baseURL ? { baseURL } : {}),
7718
+ ...(flags.nonHeadless ? { headless: false } : {}),
7719
+ });
7720
+ console.log(JSON.stringify(result));
7721
+ }
7722
+ catch (err) {
7723
+ console.error(`waygraph pilot start: ${err instanceof Error ? err.message : String(err)}`);
7724
+ process.exit(1);
7725
+ }
7726
+ break;
7727
+ }
7728
+ // Hidden: the detached server's own entry point, spawned by
7729
+ // `spawnDetachedSession` (auto --cli --detach). Not documented in
7730
+ // usage() - not meant to be invoked directly by a person.
7731
+ case "__auto-serve": {
7732
+ const proj = resolve(args[1] ?? process.cwd());
7733
+ const flags = parseRunFlags(args.slice(2));
7734
+ const sessionIdIdx = args.indexOf("--session-id");
7735
+ const sessionId = sessionIdIdx >= 0 ? args[sessionIdIdx + 1] : undefined;
7736
+ if (!sessionId) {
7737
+ console.error("waygraph __auto-serve: missing --session-id");
7738
+ process.exit(1);
7739
+ }
7740
+ const baseURL = flags.baseUrl ?? process.env.WAYGRAPH_BASE_URL ?? resolveBaseUrl(proj);
7741
+ await runAutoServeCommand({
7742
+ projectDir: proj,
7743
+ ...(baseURL ? { baseURL } : {}),
7744
+ ...(flags.nonHeadless ? { headless: false } : {}),
7745
+ }, sessionId);
7746
+ break;
7747
+ }
7392
7748
  case "try": {
7393
7749
  const flags = parseRunFlags(args.slice(1));
7394
7750
  applyRunFlags(flags);
@@ -7418,20 +7774,30 @@ Agents shipped: waygraph-planner, waygraph-author, waygraph-healer.
7418
7774
  }
7419
7775
  case "check": {
7420
7776
  const proj = resolve(args[1] ?? process.cwd());
7421
- const warnings = await checkCommand(proj);
7422
- if (warnings.length === 0) {
7777
+ const { navWarnings, selWarnings } = await checkCommand(proj);
7778
+ if (navWarnings.length === 0) {
7423
7779
  console.log(`waygraph check: no navigation found outside NavBlocks under ${proj}`);
7424
7780
  }
7425
7781
  else {
7426
- for (const w of warnings) {
7782
+ for (const w of navWarnings) {
7427
7783
  const rel = relative(proj, w.file);
7428
7784
  console.warn(`waygraph check: ${rel} (${w.blockName}) calls page.goto/reload/goBack/goForward outside a NavBlock - consider defineNavBlock instead`);
7429
7785
  }
7430
- console.log(`waygraph check: ${warnings.length} nav warning${warnings.length === 1 ? "" : "s"}`);
7786
+ console.log(`waygraph check: ${navWarnings.length} nav warning${navWarnings.length === 1 ? "" : "s"}`);
7787
+ }
7788
+ if (selWarnings.length === 0) {
7789
+ console.log(`waygraph check: no inline selectors found in verify arrays under ${proj}`);
7790
+ }
7791
+ else {
7792
+ for (const w of selWarnings) {
7793
+ const rel = relative(proj, w.file);
7794
+ console.warn(`waygraph check: ${rel} (${w.blockName}) has an inline selector literal in verify - move it into a *Sel object`);
7795
+ }
7796
+ console.log(`waygraph check: ${selWarnings.length} inline-selector warning${selWarnings.length === 1 ? "" : "s"}`);
7431
7797
  }
7432
7798
  const orphans = await findOrphanBlocks(proj);
7433
7799
  printOrphanReport(proj, orphans);
7434
- // Nav warnings only - never fail exit code. Orphans are reported for
7800
+ // Warnings only - never fail exit code. Orphans are reported for
7435
7801
  // human/agent cleanup; chain auto refuses while any remain.
7436
7802
  break;
7437
7803
  }
package/dist/engine.d.ts CHANGED
@@ -637,7 +637,7 @@ export declare function defineBlock<In extends Checkpoint<string>, Out extends C
637
637
  * (same shape `DefinedBlock`/`ComposedBlock` already use), so it drops into
638
638
  * `defineFlow([...])`, `connect()`, `composeBlock()` exactly like any other
639
639
  * Block - no special-casing needed anywhere that only expects a `Block`.
640
- * See `openspec/changes/nav-block-and-check/` for why this exists.
640
+ * See `openspec/specs/nav-block-and-check/spec.md` for why this exists.
641
641
  */
642
642
  export type NavBlock<Out extends Checkpoint<string>> = DefinedBlock<Checkpoint<string>, Out>;
643
643
  /**
@@ -742,6 +742,45 @@ export type ActionBlock<In extends Checkpoint<string>, Out extends Checkpoint<st
742
742
  export declare function defineMethodBlock<In extends Checkpoint<string>, Out extends Checkpoint<string>>(base: Parameters<typeof defineBlock<In, Out>>[0]): MethodBlock<In, Out>;
743
743
  /** @deprecated Prefer {@link defineMethodBlock} - identical helper (0.7 name). */
744
744
  export declare const defineActionBlock: typeof defineMethodBlock;
745
+ export interface AssertBlockOptions<Out extends Checkpoint<string> = Checkpoint<string>> {
746
+ name: string;
747
+ description?: string;
748
+ /** Self-loop target - the Checkpoint this assertion runs on and returns to. */
749
+ checkpoint: Out["__state"];
750
+ /**
751
+ * Shorthand for the wait-then-assert shape found repeatedly in hand-written
752
+ * assertion Blocks: waits for a heading with this accessible name before
753
+ * `verify` runs. Omit for a pure "assert whatever is already on the page"
754
+ * check with no wait. Not a general `act()` override - a Block that needs
755
+ * more than this stays a plain `defineMethodBlock`.
756
+ */
757
+ waitForHeading?: string;
758
+ verify: Trait[] | ((out: Out) => Trait[]);
759
+ /** Mem keys this assertion's `verify` reads (e.g. a mem-aware Trait) - checked by preflight before the flow runs. */
760
+ requires?: readonly MemKey<any>[];
761
+ stubBefore?: import("./highlights.js").HighlightStubPhaseOrFn<Out>;
762
+ stubAfter?: import("./highlights.js").HighlightStubPhaseOrFn<Out>;
763
+ stubOnError?: import("./highlights.js").HighlightStubPhaseOrFn<Out>;
764
+ /** Multi-step yap slides (demo only) - same field `Instruction.slides` exposes elsewhere. */
765
+ slides?: import("./highlights.js").WaygraphSlidesOrFn<Out>;
766
+ }
767
+ /**
768
+ * Sugar for a self-loop-only "pure assertion" Block: no hand-written
769
+ * `act`/`resolve`, just a name, a `checkpoint` tag, and a `verify` array.
770
+ * `resolve` is generated from the one `checkpoint` field given, closing the
771
+ * copy/rename footgun where a hand-restated checkpoint string can silently
772
+ * drift wrong across a copy/pasted file. Mirrors `definePageBlock`'s own
773
+ * construction pattern (flat options in, `defineBlock` built internally).
774
+ * See openspec/changes/waygraph-agent-skill-hardening/spec.md.
775
+ * @example
776
+ * defineAssertBlock({
777
+ * name: "assert-raw-materials-table",
778
+ * checkpoint: "RawMaterials",
779
+ * waitForHeading: "Raw Materials & Lead Times",
780
+ * verify: [Trait.visible(RawMaterialsSel.reorderBadge)],
781
+ * });
782
+ */
783
+ export declare function defineAssertBlock<Out extends Checkpoint<string> = Checkpoint<string>>(options: AssertBlockOptions<Out>): MethodBlock<Out, Out>;
745
784
  /** One Block (or lazy factory) registered on a {@link PageBlock}. */
746
785
  export type PageMethodEntry = DefinedBlock<any, any> | (() => DefinedBlock<any, any>);
747
786
  export type PageBlockOptions<Out extends Checkpoint<string>> = {