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.
- package/README.md +970 -232
- package/assets/stubs/stub.mp4 +0 -0
- package/assets/stubs/stub.pdf +32 -0
- package/assets/stubs/stub.png +0 -0
- package/dist/agent-dive.d.ts +9 -0
- package/dist/agent-dive.js +32 -0
- package/dist/auto-explore-run.d.ts +20 -2
- package/dist/auto-explore-run.js +9 -8
- package/dist/auto-explore.js +22 -2
- package/dist/auto-session-ipc.d.ts +123 -0
- package/dist/auto-session-ipc.js +381 -0
- package/dist/auto-session.d.ts +342 -0
- package/dist/auto-session.js +760 -0
- package/dist/cli.js +450 -51
- package/dist/engine.d.ts +201 -1
- package/dist/engine.js +312 -2
- package/dist/graph.d.ts +18 -0
- package/dist/graph.js +65 -2
- package/dist/highlights.d.ts +20 -1
- package/dist/highlights.js +60 -0
- package/dist/index.d.ts +8 -4
- package/dist/index.js +5 -3
- package/dist/map-check.d.ts +18 -0
- package/dist/map-check.js +140 -0
- package/dist/pilot-overlay.d.ts +88 -0
- package/dist/pilot-overlay.js +363 -0
- package/dist/pilot.d.ts +49 -0
- package/dist/pilot.js +53 -0
- package/dist/trait.d.ts +22 -0
- package/dist/trait.js +60 -3
- package/dist/types.d.ts +21 -1
- package/dist/types.js +17 -1
- package/examples/routed-demo/.waygraph-auto/4d4902b7.log +0 -0
- package/examples/routed-demo/.waygraph-auto/51ef462e.log +0 -0
- package/examples/routed-demo/.waygraph-auto/71527ad9.log +0 -0
- package/examples/routed-demo/.waygraph-auto/ca16778e.log +0 -0
- package/examples/routed-demo/package.json +26 -0
- package/examples/routed-demo/playwright.config.ts +20 -0
- package/examples/routed-demo/scripts/fixture-server.mjs +37 -0
- package/examples/routed-demo/scripts/with-fixture.mjs +70 -0
- package/examples/routed-demo/src/flows/routed-demo-map.flow.ts +39 -0
- package/examples/routed-demo/src/flows/routed-demo.flow.ts +12 -0
- package/examples/routed-demo/src/map/(app_base)/dashboard/_methods/click-widget.block.ts +23 -0
- package/examples/routed-demo/src/map/(app_base)/dashboard/_nav.block.ts +18 -0
- package/examples/routed-demo/src/map/(app_base)/dashboard/_page.block.ts +22 -0
- package/examples/routed-demo/src/map/(app_base)/dashboard/_sel.ts +10 -0
- package/examples/routed-demo/src/map/(external)/docs/_nav.block.ts +21 -0
- package/examples/routed-demo/src/map/(external)/docs/_page.block.ts +15 -0
- package/examples/routed-demo/src/map/(external)/docs/_sel.ts +7 -0
- package/examples/routed-demo/src/pages/dashboard.html +10 -0
- package/examples/routed-demo/src/pages/docs.html +8 -0
- package/examples/routed-demo/src/states/routed-demo.states.ts +10 -0
- package/examples/routed-demo/test-results/.last-run.json +4 -0
- package/examples/routed-demo/tests/routed-demo-map.spec.ts +17 -0
- package/examples/routed-demo/tests/routed-demo.spec.ts +75 -0
- package/examples/routed-demo/tsconfig.json +18 -0
- package/examples/routed-demo-consumer/package.json +18 -0
- package/examples/saucedemo/.waygraph-auto/00d5336e.log +0 -0
- package/examples/saucedemo/.waygraph-auto/010dd92b.log +0 -0
- package/examples/saucedemo/.waygraph-auto/011ad671.log +0 -0
- package/examples/saucedemo/.waygraph-auto/01b45645.log +0 -0
- package/examples/saucedemo/.waygraph-auto/03764153.log +0 -0
- package/examples/saucedemo/.waygraph-auto/0593587e.log +0 -0
- package/examples/saucedemo/.waygraph-auto/06d12823.log +0 -0
- package/examples/saucedemo/.waygraph-auto/083cc5b9.log +0 -0
- package/examples/saucedemo/.waygraph-auto/0b1f5b26.json +8 -0
- package/examples/saucedemo/.waygraph-auto/0c00f25f.log +0 -0
- package/examples/saucedemo/.waygraph-auto/0e480591.log +0 -0
- package/examples/saucedemo/.waygraph-auto/104751ef.log +0 -0
- package/examples/saucedemo/.waygraph-auto/110958b8.log +0 -0
- package/examples/saucedemo/.waygraph-auto/138107c1.log +0 -0
- package/examples/saucedemo/.waygraph-auto/159d541b.log +0 -0
- package/examples/saucedemo/.waygraph-auto/16aa2c01.log +0 -0
- package/examples/saucedemo/.waygraph-auto/16c35dd5.log +0 -0
- package/examples/saucedemo/.waygraph-auto/1706547d.log +0 -0
- package/examples/saucedemo/.waygraph-auto/17537e42.log +0 -0
- package/examples/saucedemo/.waygraph-auto/175655f7.log +0 -0
- package/examples/saucedemo/.waygraph-auto/17ede493.log +0 -0
- package/examples/saucedemo/.waygraph-auto/1fe2414f.log +0 -0
- package/examples/saucedemo/.waygraph-auto/1fe2e3b8.log +0 -0
- package/examples/saucedemo/.waygraph-auto/2219f00b.log +0 -0
- package/examples/saucedemo/.waygraph-auto/23e62571.log +0 -0
- package/examples/saucedemo/.waygraph-auto/25f68ada.log +0 -0
- package/examples/saucedemo/.waygraph-auto/26ca9cd8.log +0 -0
- package/examples/saucedemo/.waygraph-auto/2bb6c4e8.log +0 -0
- package/examples/saucedemo/.waygraph-auto/2d425004.log +0 -0
- package/examples/saucedemo/.waygraph-auto/2f5b3ea6.log +0 -0
- package/examples/saucedemo/.waygraph-auto/31bb303d.log +0 -0
- package/examples/saucedemo/.waygraph-auto/31f2042f.log +0 -0
- package/examples/saucedemo/.waygraph-auto/36551ec1.log +0 -0
- package/examples/saucedemo/.waygraph-auto/36a1c274.log +0 -0
- package/examples/saucedemo/.waygraph-auto/381aa338.log +0 -0
- package/examples/saucedemo/.waygraph-auto/3882bce1.log +0 -0
- package/examples/saucedemo/.waygraph-auto/38acd1dc.log +0 -0
- package/examples/saucedemo/.waygraph-auto/3b8b77b9.log +0 -0
- package/examples/saucedemo/.waygraph-auto/4028d2a2.log +0 -0
- package/examples/saucedemo/.waygraph-auto/4168b208.log +0 -0
- package/examples/saucedemo/.waygraph-auto/42cc9113.log +0 -0
- package/examples/saucedemo/.waygraph-auto/439d30aa.log +0 -0
- package/examples/saucedemo/.waygraph-auto/43ab66ce.log +0 -0
- package/examples/saucedemo/.waygraph-auto/43f66838.log +0 -0
- package/examples/saucedemo/.waygraph-auto/442171d4.log +0 -0
- package/examples/saucedemo/.waygraph-auto/453b1ce1.log +0 -0
- package/examples/saucedemo/.waygraph-auto/457322bd.log +0 -0
- package/examples/saucedemo/.waygraph-auto/46197027.log +0 -0
- package/examples/saucedemo/.waygraph-auto/46889468.log +0 -0
- package/examples/saucedemo/.waygraph-auto/4890da1c.log +0 -0
- package/examples/saucedemo/.waygraph-auto/4893a63b.log +0 -0
- package/examples/saucedemo/.waygraph-auto/4a85f496.log +0 -0
- package/examples/saucedemo/.waygraph-auto/4af71440.log +0 -0
- package/examples/saucedemo/.waygraph-auto/4f7496d1.log +0 -0
- package/examples/saucedemo/.waygraph-auto/50e8baaa.log +0 -0
- package/examples/saucedemo/.waygraph-auto/52b3a455.log +0 -0
- package/examples/saucedemo/.waygraph-auto/532dd9b8.log +0 -0
- package/examples/saucedemo/.waygraph-auto/5391ce40.log +0 -0
- package/examples/saucedemo/.waygraph-auto/57dbddb3.log +0 -0
- package/examples/saucedemo/.waygraph-auto/5897f501.log +0 -0
- package/examples/saucedemo/.waygraph-auto/59c0b57d.log +0 -0
- package/examples/saucedemo/.waygraph-auto/5b511794.log +0 -0
- package/examples/saucedemo/.waygraph-auto/5c0eef7f.log +0 -0
- package/examples/saucedemo/.waygraph-auto/5c47910f.log +0 -0
- package/examples/saucedemo/.waygraph-auto/5d60da77.log +0 -0
- package/examples/saucedemo/.waygraph-auto/5eda8273.log +0 -0
- package/examples/saucedemo/.waygraph-auto/5fc3a33b.log +0 -0
- package/examples/saucedemo/.waygraph-auto/61b6546d.log +0 -0
- package/examples/saucedemo/.waygraph-auto/621518ad.log +0 -0
- package/examples/saucedemo/.waygraph-auto/632b7118.log +0 -0
- package/examples/saucedemo/.waygraph-auto/64314c2b.log +0 -0
- package/examples/saucedemo/.waygraph-auto/650ed066.log +0 -0
- package/examples/saucedemo/.waygraph-auto/66516213.log +0 -0
- package/examples/saucedemo/.waygraph-auto/66c17079.log +0 -0
- package/examples/saucedemo/.waygraph-auto/69bf0b80.log +0 -0
- package/examples/saucedemo/.waygraph-auto/69c2347a.log +0 -0
- package/examples/saucedemo/.waygraph-auto/6d22bdb0.log +0 -0
- package/examples/saucedemo/.waygraph-auto/6d9aaad3.log +0 -0
- package/examples/saucedemo/.waygraph-auto/7103bebb.log +0 -0
- package/examples/saucedemo/.waygraph-auto/740c9faa.log +0 -0
- package/examples/saucedemo/.waygraph-auto/74872fc5.log +0 -0
- package/examples/saucedemo/.waygraph-auto/75846ca9.log +0 -0
- package/examples/saucedemo/.waygraph-auto/7626c85b.log +0 -0
- package/examples/saucedemo/.waygraph-auto/76308eec.log +0 -0
- package/examples/saucedemo/.waygraph-auto/76c1650e.log +0 -0
- package/examples/saucedemo/.waygraph-auto/7861f38f.log +0 -0
- package/examples/saucedemo/.waygraph-auto/78b21219.log +0 -0
- package/examples/saucedemo/.waygraph-auto/7af224ed.log +0 -0
- package/examples/saucedemo/.waygraph-auto/7c3be585.log +0 -0
- package/examples/saucedemo/.waygraph-auto/7ed55a2c.log +0 -0
- package/examples/saucedemo/.waygraph-auto/80086ba2.log +0 -0
- package/examples/saucedemo/.waygraph-auto/80206369.log +0 -0
- package/examples/saucedemo/.waygraph-auto/847f1092.log +0 -0
- package/examples/saucedemo/.waygraph-auto/84d6d293.log +0 -0
- package/examples/saucedemo/.waygraph-auto/8581abfa.log +0 -0
- package/examples/saucedemo/.waygraph-auto/87b7e0fd.log +0 -0
- package/examples/saucedemo/.waygraph-auto/87c79256.log +0 -0
- package/examples/saucedemo/.waygraph-auto/88af2495.log +0 -0
- package/examples/saucedemo/.waygraph-auto/8a3eb088.log +0 -0
- package/examples/saucedemo/.waygraph-auto/8c04a403.log +0 -0
- package/examples/saucedemo/.waygraph-auto/8c9ab09e.log +0 -0
- package/examples/saucedemo/.waygraph-auto/8cc5db51.log +0 -0
- package/examples/saucedemo/.waygraph-auto/8ea3a69c.log +0 -0
- package/examples/saucedemo/.waygraph-auto/9150f913.log +0 -0
- package/examples/saucedemo/.waygraph-auto/929a4313.log +0 -0
- package/examples/saucedemo/.waygraph-auto/95a599e4.log +0 -0
- package/examples/saucedemo/.waygraph-auto/96c45350.log +0 -0
- package/examples/saucedemo/.waygraph-auto/986030e6.log +0 -0
- package/examples/saucedemo/.waygraph-auto/99787abb.log +0 -0
- package/examples/saucedemo/.waygraph-auto/99ddb62c.log +0 -0
- package/examples/saucedemo/.waygraph-auto/a2dd30dd.log +0 -0
- package/examples/saucedemo/.waygraph-auto/a63a2d20.log +0 -0
- package/examples/saucedemo/.waygraph-auto/a78befb7.log +0 -0
- package/examples/saucedemo/.waygraph-auto/a84d9b79.log +0 -0
- package/examples/saucedemo/.waygraph-auto/a87bb3ee.log +0 -0
- package/examples/saucedemo/.waygraph-auto/a9270890.log +0 -0
- package/examples/saucedemo/.waygraph-auto/aa440153.log +0 -0
- package/examples/saucedemo/.waygraph-auto/ab7561e0.log +0 -0
- package/examples/saucedemo/.waygraph-auto/ac19ae60.log +0 -0
- package/examples/saucedemo/.waygraph-auto/ae21ad8e.log +0 -0
- package/examples/saucedemo/.waygraph-auto/af09042f.log +0 -0
- package/examples/saucedemo/.waygraph-auto/b1684126.log +0 -0
- package/examples/saucedemo/.waygraph-auto/b21e9d12.log +0 -0
- package/examples/saucedemo/.waygraph-auto/b5a838be.log +0 -0
- package/examples/saucedemo/.waygraph-auto/b603549d.log +0 -0
- package/examples/saucedemo/.waygraph-auto/b81e074f.log +0 -0
- package/examples/saucedemo/.waygraph-auto/b83e6259.log +0 -0
- package/examples/saucedemo/.waygraph-auto/b9cb2796.log +0 -0
- package/examples/saucedemo/.waygraph-auto/ba58abb7.log +0 -0
- package/examples/saucedemo/.waygraph-auto/bb0a0018.log +0 -0
- package/examples/saucedemo/.waygraph-auto/bb9fd384.log +0 -0
- package/examples/saucedemo/.waygraph-auto/bc0bdd0e.log +0 -0
- package/examples/saucedemo/.waygraph-auto/bc7d4a83.log +0 -0
- package/examples/saucedemo/.waygraph-auto/bd8e082a.log +0 -0
- package/examples/saucedemo/.waygraph-auto/bea0c93e.log +0 -0
- package/examples/saucedemo/.waygraph-auto/bf35201a.log +0 -0
- package/examples/saucedemo/.waygraph-auto/bffa3a7a.log +0 -0
- package/examples/saucedemo/.waygraph-auto/c02ea583.log +0 -0
- package/examples/saucedemo/.waygraph-auto/c2caf0a8.log +0 -0
- package/examples/saucedemo/.waygraph-auto/c3bdc714.log +0 -0
- package/examples/saucedemo/.waygraph-auto/c4afb8bc.log +0 -0
- package/examples/saucedemo/.waygraph-auto/c916a654.log +0 -0
- package/examples/saucedemo/.waygraph-auto/c9b8d69e.log +0 -0
- package/examples/saucedemo/.waygraph-auto/cd68bbc4.log +0 -0
- package/examples/saucedemo/.waygraph-auto/cdc6db50.log +0 -0
- package/examples/saucedemo/.waygraph-auto/d01906a7.log +0 -0
- package/examples/saucedemo/.waygraph-auto/d02e5e7e.log +0 -0
- package/examples/saucedemo/.waygraph-auto/d09aff71.log +0 -0
- package/examples/saucedemo/.waygraph-auto/d0e41396.log +0 -0
- package/examples/saucedemo/.waygraph-auto/d1370d76.log +0 -0
- package/examples/saucedemo/.waygraph-auto/d3714ae4.log +0 -0
- package/examples/saucedemo/.waygraph-auto/d9e5f8a4.log +0 -0
- package/examples/saucedemo/.waygraph-auto/da0685dc.log +0 -0
- package/examples/saucedemo/.waygraph-auto/da894ad8.log +0 -0
- package/examples/saucedemo/.waygraph-auto/daa2f922.log +0 -0
- package/examples/saucedemo/.waygraph-auto/daefb614.log +0 -0
- package/examples/saucedemo/.waygraph-auto/db97e833.log +0 -0
- package/examples/saucedemo/.waygraph-auto/dec3076e.log +0 -0
- package/examples/saucedemo/.waygraph-auto/e101d19a.log +0 -0
- package/examples/saucedemo/.waygraph-auto/e1973991.log +0 -0
- package/examples/saucedemo/.waygraph-auto/e207c989.log +0 -0
- package/examples/saucedemo/.waygraph-auto/e633e545.log +0 -0
- package/examples/saucedemo/.waygraph-auto/e69aec68.log +0 -0
- package/examples/saucedemo/.waygraph-auto/e70e2d06.log +0 -0
- package/examples/saucedemo/.waygraph-auto/e8306a4b.log +0 -0
- package/examples/saucedemo/.waygraph-auto/ebad3410.log +0 -0
- package/examples/saucedemo/.waygraph-auto/ec88b3ef.log +0 -0
- package/examples/saucedemo/.waygraph-auto/ecbb0966.log +0 -0
- package/examples/saucedemo/.waygraph-auto/ecdee753.log +0 -0
- package/examples/saucedemo/.waygraph-auto/ed888783.log +0 -0
- package/examples/saucedemo/.waygraph-auto/ed931dac.log +0 -0
- package/examples/saucedemo/.waygraph-auto/ef655a3f.log +0 -0
- package/examples/saucedemo/.waygraph-auto/f34c9a26.log +0 -0
- package/examples/saucedemo/.waygraph-auto/f3c29b21.log +0 -0
- package/examples/saucedemo/.waygraph-auto/f53f7cfc.log +0 -0
- package/examples/saucedemo/.waygraph-auto/f5525d53.log +0 -0
- package/examples/saucedemo/.waygraph-auto/f5ad5830.log +0 -0
- package/examples/saucedemo/.waygraph-auto/f90035b3.log +0 -0
- package/examples/saucedemo/.waygraph-auto/fa687bc2.log +0 -0
- package/examples/saucedemo/.waygraph-auto/faed36dd.log +0 -0
- package/examples/saucedemo/.waygraph-auto/fb66fba0.log +0 -0
- package/examples/saucedemo/.waygraph-auto/fc48fd76.log +0 -0
- package/examples/saucedemo/docs/CONVENTION.md +25 -5
- package/examples/saucedemo/docs/HELPERS.md +15 -4
- package/examples/saucedemo/scripts/capture-wrong-login.mjs +8 -2
- package/examples/saucedemo/scripts/prove-wrong-login-runtime.mjs +8 -2
- package/examples/saucedemo/src/blocks/SITE-MAP.md +14 -3
- package/examples/saucedemo/src/blocks/saucedemo-web/NAV.md +15 -1
- package/examples/saucedemo/src/blocks/saucedemo-web/cart/NAV.md +1 -0
- package/examples/saucedemo/src/blocks/saucedemo-web/cart/cart.sel.ts +9 -0
- package/examples/saucedemo/src/blocks/saucedemo-web/cart/nav-cart.block.ts +3 -2
- package/examples/saucedemo/src/blocks/saucedemo-web/cart/nav-checkout-info.block.ts +2 -1
- package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/NAV.md +6 -1
- package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/methods/checkout-info.sel.ts +11 -0
- package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/methods/fill-first-name.method.block.ts +22 -0
- package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/methods/fill-last-name.method.block.ts +21 -0
- package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/methods/fill-postal-code.method.block.ts +21 -0
- package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/methods/submit-checkout-info.method.block.ts +6 -7
- package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-two/NAV.md +2 -0
- package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-two/methods/checkout-overview.sel.ts +9 -0
- package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-two/methods/finish-order.method.block.ts +7 -6
- package/examples/saucedemo/src/blocks/saucedemo-web/ff-owner-auth.block.ts +7 -2
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory-item/NAV.md +1 -0
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory-item/item-detail.sel.ts +9 -0
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory-item/nav-back-to-inventory.block.ts +2 -1
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory-item/nav-back-to-products.block.ts +2 -1
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory-item/nav-continue-shopping.block.ts +2 -1
- package/examples/saucedemo/src/blocks/saucedemo-web/methods/fill-password.method.block.ts +51 -0
- package/examples/saucedemo/src/blocks/saucedemo-web/methods/fill-username.method.block.ts +69 -0
- package/examples/saucedemo/src/blocks/saucedemo-web/methods/login.sel.ts +13 -0
- package/examples/saucedemo/src/blocks/saucedemo-web/methods/submit-login-for-flow.ts +4 -4
- package/examples/saucedemo/src/blocks/saucedemo-web/methods/submit-login.method.block.ts +13 -51
- package/examples/saucedemo/src/blocks/saucedemo-web/methods/submit-logout.method.block.ts +4 -3
- package/examples/saucedemo/src/blocks/saucedemo-web/nav-login.block.ts +14 -6
- package/examples/saucedemo/src/flows/checkout-then-browse-again.flow.ts +15 -0
- package/examples/saucedemo/src/flows/checkout.flow.ts +20 -2
- package/examples/saucedemo/src/flows/device-showcase.flow.ts +4 -0
- package/examples/saucedemo/src/flows/login.flow.ts +3 -1
- package/examples/saucedemo/src/flows/shop.flow.ts +6 -0
- package/examples/saucedemo/src/flows/smoke.flow.ts +13 -7
- package/examples/saucedemo/src/flows/stub-on-error.flow.ts +4 -2
- package/examples/saucedemo/src/flows/viewer-blocked.flow.ts +6 -2
- package/examples/saucedemo/tests/flow-block-verify.spec.ts +3 -3
- package/examples/saucedemo/tests/submit-login-branch.spec.ts +5 -3
- package/package.json +2 -1
- package/templates/agents/waygraph-author.agent.md +43 -5
- package/templates/agents/waygraph-planner.agent.md +33 -2
- package/templates/quickstart/src/blocks/saucedemo-web/NAV.md +15 -1
- package/templates/quickstart/src/blocks/saucedemo-web/cart/NAV.md +1 -0
- package/templates/quickstart/src/blocks/saucedemo-web/cart/cart.sel.ts +9 -0
- package/templates/quickstart/src/blocks/saucedemo-web/cart/nav-cart.block.ts +19 -15
- package/templates/quickstart/src/blocks/saucedemo-web/cart/nav-checkout-info.block.ts +2 -1
- package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/NAV.md +6 -1
- package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/methods/checkout-info.sel.ts +11 -0
- package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/methods/fill-first-name.method.block.ts +22 -0
- package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/methods/fill-last-name.method.block.ts +21 -0
- package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/methods/fill-postal-code.method.block.ts +21 -0
- package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/methods/submit-checkout-info.method.block.ts +6 -7
- package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-two/NAV.md +2 -0
- package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-two/methods/checkout-overview.sel.ts +9 -0
- package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-two/methods/finish-order.method.block.ts +7 -6
- package/templates/quickstart/src/blocks/saucedemo-web/ff-owner-auth.block.ts +7 -2
- package/templates/quickstart/src/blocks/saucedemo-web/inventory/methods/add-to-cart.effect.block.ts +24 -16
- package/templates/quickstart/src/blocks/saucedemo-web/inventory/nav-item-detail.block.ts +3 -3
- package/templates/quickstart/src/blocks/saucedemo-web/inventory-item/NAV.md +1 -0
- package/templates/quickstart/src/blocks/saucedemo-web/inventory-item/item-detail.sel.ts +9 -0
- package/templates/quickstart/src/blocks/saucedemo-web/inventory-item/nav-back-to-inventory.block.ts +2 -1
- package/templates/quickstart/src/blocks/saucedemo-web/inventory-item/nav-back-to-products.block.ts +2 -1
- package/templates/quickstart/src/blocks/saucedemo-web/inventory-item/nav-continue-shopping.block.ts +2 -1
- package/templates/quickstart/src/blocks/saucedemo-web/methods/fill-password.method.block.ts +51 -0
- package/templates/quickstart/src/blocks/saucedemo-web/methods/fill-username.method.block.ts +69 -0
- package/templates/quickstart/src/blocks/saucedemo-web/methods/login.sel.ts +13 -0
- package/templates/quickstart/src/blocks/saucedemo-web/methods/submit-login-for-flow.ts +4 -4
- package/templates/quickstart/src/blocks/saucedemo-web/methods/submit-login.method.block.ts +35 -63
- package/templates/quickstart/src/blocks/saucedemo-web/methods/submit-logout.method.block.ts +4 -3
- package/templates/quickstart/src/blocks/saucedemo-web/nav-login.block.ts +14 -6
- package/templates/quickstart/src/flows/checkout-then-browse-again.flow.ts +15 -0
- package/templates/quickstart/src/flows/checkout.flow.ts +29 -2
- package/templates/quickstart/src/flows/device-showcase.flow.ts +4 -0
- package/templates/quickstart/src/flows/login.flow.ts +3 -1
- package/templates/quickstart/src/flows/shop.flow.ts +6 -0
- package/templates/quickstart/src/flows/smoke.flow.ts +13 -7
- package/templates/quickstart/src/flows/viewer-blocked.flow.ts +6 -2
- package/templates/quickstart/tests/chain-flow.spec.ts +8 -1
- package/templates/scaffold/STRUCTURE.md +23 -3
- package/templates/scaffold/scripts/fixture-server.mjs +11 -2
- package/templates/scaffold/src/flows/example.flow.ts +8 -6
- package/templates/scaffold/src/flows/mail-verify.flow.ts +85 -0
- package/templates/scaffold/src/flows/shop.flow.ts +23 -6
- package/templates/scaffold/src/map/(app_base)/docs/_nav.block.ts +20 -0
- package/templates/scaffold/src/map/(app_base)/docs/_page.block.ts +15 -0
- package/templates/scaffold/src/map/(app_base)/docs/_sel.ts +7 -0
- package/templates/scaffold/src/map/(app_base)/docs/docs.html +8 -0
- package/templates/scaffold/src/{blocks/demo-web/methods → map/(app_base)/home/_methods}/add-item.effect.block.ts +3 -3
- package/templates/scaffold/src/map/(app_base)/home/_methods/assert-hello.method.block.ts +46 -0
- package/templates/scaffold/src/map/(app_base)/home/_methods/assert-item-added.method.block.ts +38 -0
- package/templates/scaffold/src/{blocks/demo-web/methods → map/(app_base)/home/_methods}/clear-cart.method.block.ts +9 -3
- package/templates/scaffold/src/{blocks/demo-web/methods → map/(app_base)/home/_methods}/remove-item.effect.block.ts +3 -3
- package/templates/scaffold/src/{blocks/demo-web/nav-home.block.ts → map/(app_base)/home/_nav.block.ts} +2 -2
- package/templates/scaffold/src/{blocks/demo-web/home.page.block.ts → map/(app_base)/home/_page.block.ts} +7 -7
- package/templates/scaffold/src/{blocks/demo-web/demo-sel.ts → map/(app_base)/home/_sel.ts} +1 -0
- package/templates/scaffold/src/{blocks/demo-web → map/(app_base)/home}/home.html +4 -0
- package/templates/scaffold/src/map/(app_base)/home/nav-verification-link.block.ts +34 -0
- package/templates/scaffold/src/map/(external)/mailpit/_methods/assert-email-content.method.block.ts +48 -0
- package/templates/scaffold/src/map/(external)/mailpit/_methods/assert-email-received.method.block.ts +49 -0
- package/templates/scaffold/src/map/(external)/mailpit/_methods/extract-email-link.method.block.ts +41 -0
- package/templates/scaffold/src/map/(external)/mailpit/_methods/open-message.method.block.ts +39 -0
- package/templates/scaffold/src/map/(external)/mailpit/_nav.block.ts +20 -0
- package/templates/scaffold/src/map/(external)/mailpit/_page.block.ts +30 -0
- package/templates/scaffold/src/map/(external)/mailpit/_sel.ts +5 -0
- package/templates/scaffold/src/states/demo.mem-keys.ts +25 -1
- package/templates/scaffold/src/states/demo.states.ts +11 -0
- package/templates/scaffold/test-results/.last-run.json +4 -0
- package/templates/scaffold/tests/example.spec.ts +2 -2
- package/templates/scaffold/tests/mail-verify.spec.ts +191 -0
- package/templates/skills/waygraph-blind-pilot.skill.md +61 -0
- package/templates/skills/waygraph-pilot.skill.md +108 -0
- package/templates/quickstart/README-saucedemo-commands.md +0 -72
- package/templates/scaffold/src/blocks/SITE-MAP.md +0 -12
- package/templates/scaffold/src/blocks/demo-web/NAV.md +0 -29
- package/templates/scaffold/src/blocks/demo-web/methods/assert-hello.method.block.ts +0 -50
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unix-socket transport for `waygraph auto --cli --detach` / `send` / `status` /
|
|
3
|
+
* `attach`. Session identity lives under a per-project `.waygraph-auto/`
|
|
4
|
+
* directory, mirroring the existing `.waygraph-traverse/` dotdir convention.
|
|
5
|
+
* See openspec/changes/waygraph-auto-cli-session-control.
|
|
6
|
+
*/
|
|
7
|
+
import { createServer, connect } from "node:net";
|
|
8
|
+
import { spawn } from "node:child_process";
|
|
9
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, rmSync, openSync, } from "node:fs";
|
|
10
|
+
import { join, dirname } from "node:path";
|
|
11
|
+
import { tmpdir } from "node:os";
|
|
12
|
+
import { fileURLToPath } from "node:url";
|
|
13
|
+
import { randomBytes } from "node:crypto";
|
|
14
|
+
import { createInterface } from "node:readline/promises";
|
|
15
|
+
import { stdin as input, stdout as output } from "node:process";
|
|
16
|
+
import { AutoSession, } from "./auto-session.js";
|
|
17
|
+
function sessionDir(projectDir) {
|
|
18
|
+
return join(projectDir, ".waygraph-auto");
|
|
19
|
+
}
|
|
20
|
+
function metaPath(projectDir, sessionId) {
|
|
21
|
+
return join(sessionDir(projectDir), `${sessionId}.json`);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Deliberately NOT under the project directory (unlike meta/log files) -
|
|
25
|
+
* a real bug found while proving out openspec/changes/waygraph-map's own
|
|
26
|
+
* "waypack" loading claim: a project loaded through a consumer's own deeply
|
|
27
|
+
* nested `node_modules/<pkg>` path can push the socket's absolute path past
|
|
28
|
+
* the OS's AF_UNIX `sun_path` limit (~108 bytes on Linux), failing with
|
|
29
|
+
* `listen EINVAL`. A short, fixed-location directory sidesteps this
|
|
30
|
+
* regardless of how deep `projectDir` itself is nested. `sessionId` alone
|
|
31
|
+
* (8 hex chars, `generateSessionId()`) is enough to keep this collision-safe
|
|
32
|
+
* across every project on the machine sharing this one flat directory - the
|
|
33
|
+
* same randomness space this package already relied on per-project.
|
|
34
|
+
*/
|
|
35
|
+
function socketDir() {
|
|
36
|
+
return join(tmpdir(), "waygraph-auto");
|
|
37
|
+
}
|
|
38
|
+
function socketPathFor(sessionId) {
|
|
39
|
+
return join(socketDir(), `${sessionId}.sock`);
|
|
40
|
+
}
|
|
41
|
+
function logPathFor(projectDir, sessionId) {
|
|
42
|
+
return join(sessionDir(projectDir), `${sessionId}.log`);
|
|
43
|
+
}
|
|
44
|
+
function generateSessionId() {
|
|
45
|
+
return randomBytes(4).toString("hex");
|
|
46
|
+
}
|
|
47
|
+
function readSessionMeta(projectDir, sessionId) {
|
|
48
|
+
const p = metaPath(projectDir, sessionId);
|
|
49
|
+
if (!existsSync(p))
|
|
50
|
+
return null;
|
|
51
|
+
try {
|
|
52
|
+
return JSON.parse(readFileSync(p, "utf-8"));
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function removeSessionFiles(projectDir, sessionId) {
|
|
59
|
+
for (const p of [
|
|
60
|
+
metaPath(projectDir, sessionId),
|
|
61
|
+
socketPathFor(sessionId),
|
|
62
|
+
]) {
|
|
63
|
+
try {
|
|
64
|
+
rmSync(p, { force: true });
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
/* ignore */
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/** Reads newline-delimited JSON off a socket, one message at a time. */
|
|
72
|
+
function readOneMessage(sock, timeoutMs) {
|
|
73
|
+
return new Promise((resolvePromise, reject) => {
|
|
74
|
+
let buf = "";
|
|
75
|
+
const timer = setTimeout(() => {
|
|
76
|
+
cleanup();
|
|
77
|
+
reject(new Error(`timed out after ${timeoutMs}ms waiting for a response`));
|
|
78
|
+
}, timeoutMs);
|
|
79
|
+
const onData = (chunk) => {
|
|
80
|
+
buf += chunk.toString("utf-8");
|
|
81
|
+
const nl = buf.indexOf("\n");
|
|
82
|
+
if (nl === -1)
|
|
83
|
+
return;
|
|
84
|
+
const line = buf.slice(0, nl);
|
|
85
|
+
cleanup();
|
|
86
|
+
try {
|
|
87
|
+
resolvePromise(JSON.parse(line));
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
reject(new Error(`malformed response: ${err instanceof Error ? err.message : String(err)}`));
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
const onError = (err) => {
|
|
94
|
+
cleanup();
|
|
95
|
+
reject(err);
|
|
96
|
+
};
|
|
97
|
+
const onClose = () => {
|
|
98
|
+
cleanup();
|
|
99
|
+
reject(new Error("connection closed before a response arrived"));
|
|
100
|
+
};
|
|
101
|
+
function cleanup() {
|
|
102
|
+
clearTimeout(timer);
|
|
103
|
+
sock.off("data", onData);
|
|
104
|
+
sock.off("error", onError);
|
|
105
|
+
sock.off("close", onClose);
|
|
106
|
+
}
|
|
107
|
+
sock.on("data", onData);
|
|
108
|
+
sock.on("error", onError);
|
|
109
|
+
sock.on("close", onClose);
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
export async function requestSession(projectDir, sessionId, request, timeoutMs = 15_000) {
|
|
113
|
+
const meta = readSessionMeta(projectDir, sessionId);
|
|
114
|
+
if (!meta) {
|
|
115
|
+
return { ok: false, error: `no such session "${sessionId}" (no metadata under .waygraph-auto/)` };
|
|
116
|
+
}
|
|
117
|
+
return new Promise((resolvePromise) => {
|
|
118
|
+
const sock = connect(meta.socketPath);
|
|
119
|
+
const connectTimer = setTimeout(() => {
|
|
120
|
+
sock.destroy();
|
|
121
|
+
resolvePromise({ ok: false, error: `session "${sessionId}" is unreachable (socket did not respond)` });
|
|
122
|
+
}, timeoutMs);
|
|
123
|
+
sock.on("connect", () => {
|
|
124
|
+
sock.write(JSON.stringify(request) + "\n");
|
|
125
|
+
});
|
|
126
|
+
sock.on("error", () => {
|
|
127
|
+
clearTimeout(connectTimer);
|
|
128
|
+
resolvePromise({
|
|
129
|
+
ok: false,
|
|
130
|
+
error: `session "${sessionId}" is unreachable (stale socket - the process may have crashed)`,
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
readOneMessage(sock, timeoutMs)
|
|
134
|
+
.then((res) => {
|
|
135
|
+
clearTimeout(connectTimer);
|
|
136
|
+
resolvePromise(res);
|
|
137
|
+
})
|
|
138
|
+
.catch((err) => {
|
|
139
|
+
clearTimeout(connectTimer);
|
|
140
|
+
resolvePromise({ ok: false, error: err instanceof Error ? err.message : String(err) });
|
|
141
|
+
})
|
|
142
|
+
.finally(() => sock.end());
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Server-side: runs `session` behind a unix socket at
|
|
147
|
+
* `.waygraph-auto/<sessionId>.sock`, writing session metadata only once the
|
|
148
|
+
* socket is actually listening (the metadata file's existence is the
|
|
149
|
+
* "session is ready" signal a spawning parent polls for). Requests are
|
|
150
|
+
* processed one at a time via a queue - Node's single-threaded event loop
|
|
151
|
+
* already prevents true parallelism, but two overlapping `await`-heavy
|
|
152
|
+
* handlers could still interleave against the same page/mem.
|
|
153
|
+
*/
|
|
154
|
+
export async function serveSession(session, projectDir, sessionId, headless = true) {
|
|
155
|
+
mkdirSync(sessionDir(projectDir), { recursive: true });
|
|
156
|
+
mkdirSync(socketDir(), { recursive: true });
|
|
157
|
+
const socketPath = socketPathFor(sessionId);
|
|
158
|
+
rmSync(socketPath, { force: true });
|
|
159
|
+
let queue = Promise.resolve();
|
|
160
|
+
const enqueue = (fn) => {
|
|
161
|
+
const next = queue.then(fn, fn);
|
|
162
|
+
queue = next.catch(() => { });
|
|
163
|
+
return next;
|
|
164
|
+
};
|
|
165
|
+
const server = createServer((sock) => {
|
|
166
|
+
let buf = "";
|
|
167
|
+
sock.on("data", (chunk) => {
|
|
168
|
+
buf += chunk.toString("utf-8");
|
|
169
|
+
let nl;
|
|
170
|
+
while ((nl = buf.indexOf("\n")) !== -1) {
|
|
171
|
+
const line = buf.slice(0, nl);
|
|
172
|
+
buf = buf.slice(nl + 1);
|
|
173
|
+
void handleLine(line, sock);
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
async function handleLine(line, sock) {
|
|
178
|
+
let request;
|
|
179
|
+
try {
|
|
180
|
+
request = JSON.parse(line);
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
sock.write(JSON.stringify({ ok: false, error: "malformed request (invalid JSON)" }) + "\n");
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
await enqueue(async () => {
|
|
187
|
+
let response;
|
|
188
|
+
let shouldQuit = false;
|
|
189
|
+
try {
|
|
190
|
+
if (request.op === "status") {
|
|
191
|
+
response = { ok: true, snapshot: await session.currentSnapshot(), quit: false };
|
|
192
|
+
}
|
|
193
|
+
else if (request.op === "send") {
|
|
194
|
+
const result = await session.applyPick(request.pick);
|
|
195
|
+
response = result.ok
|
|
196
|
+
? { ok: true, snapshot: result.snapshot, quit: result.quit }
|
|
197
|
+
: { ok: false, error: result.error };
|
|
198
|
+
shouldQuit = result.ok && result.quit;
|
|
199
|
+
}
|
|
200
|
+
else if (request.op === "dom") {
|
|
201
|
+
const { op: _op, ...domOpts } = request;
|
|
202
|
+
response = await session.inspectDom(domOpts);
|
|
203
|
+
}
|
|
204
|
+
else if (request.op === "trace") {
|
|
205
|
+
response = { ok: true, trace: session.getTrace() };
|
|
206
|
+
}
|
|
207
|
+
else if (request.op === "console") {
|
|
208
|
+
response = { ok: true, consoleLog: session.getConsoleLog() };
|
|
209
|
+
}
|
|
210
|
+
else if (request.op === "storage") {
|
|
211
|
+
response = { ok: true, ...(await session.inspectStorage()) };
|
|
212
|
+
}
|
|
213
|
+
else if (request.op === "upload") {
|
|
214
|
+
response = await session.rawUpload(request.selector, request.stub);
|
|
215
|
+
}
|
|
216
|
+
else if (request.op === "click") {
|
|
217
|
+
response = await session.rawClick(request.selector);
|
|
218
|
+
}
|
|
219
|
+
else if (request.op === "type") {
|
|
220
|
+
response = await session.rawType(request.selector, request.text);
|
|
221
|
+
}
|
|
222
|
+
else if (request.op === "press") {
|
|
223
|
+
response = await session.rawPress(request.selector, request.key);
|
|
224
|
+
}
|
|
225
|
+
else if (request.op === "goto") {
|
|
226
|
+
response = await session.rawGoto(request.url);
|
|
227
|
+
}
|
|
228
|
+
else if (request.op === "reload") {
|
|
229
|
+
await session.reloadLibrary();
|
|
230
|
+
response = { ok: true, snapshot: await session.currentSnapshot(), quit: false };
|
|
231
|
+
}
|
|
232
|
+
else if (request.op === "reach") {
|
|
233
|
+
response = await session.applyPath(request.checkpoint);
|
|
234
|
+
}
|
|
235
|
+
else if (request.op === "resync") {
|
|
236
|
+
response = await session.resync();
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
response = { ok: false, error: `unknown op "${request.op}"` };
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
catch (err) {
|
|
243
|
+
// Real, confirmed bug this fixes: an uncaught rejection here (e.g. a
|
|
244
|
+
// Playwright locator timing out because the element it found a
|
|
245
|
+
// moment ago - via `.count()`, which does NOT auto-wait - is gone by
|
|
246
|
+
// the time a slower call like `.evaluate()` re-resolves it, which
|
|
247
|
+
// DOES auto-wait) used to escape `handleLine`'s returned promise
|
|
248
|
+
// uncaught, crashing the whole detached session process on a single
|
|
249
|
+
// bad request. One request failing must never take the rest of the
|
|
250
|
+
// still-live session (browser/page/socket) down with it.
|
|
251
|
+
response = { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
252
|
+
}
|
|
253
|
+
sock.write(JSON.stringify(response) + "\n");
|
|
254
|
+
if (shouldQuit) {
|
|
255
|
+
setImmediate(() => void shutdown());
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
let shuttingDown = false;
|
|
260
|
+
async function shutdown() {
|
|
261
|
+
if (shuttingDown)
|
|
262
|
+
return;
|
|
263
|
+
shuttingDown = true;
|
|
264
|
+
server.close();
|
|
265
|
+
await session.close().catch(() => { });
|
|
266
|
+
removeSessionFiles(projectDir, sessionId);
|
|
267
|
+
process.exit(0);
|
|
268
|
+
}
|
|
269
|
+
await new Promise((resolvePromise, reject) => {
|
|
270
|
+
server.on("error", reject);
|
|
271
|
+
server.listen(socketPath, resolvePromise);
|
|
272
|
+
});
|
|
273
|
+
const meta = {
|
|
274
|
+
sessionId,
|
|
275
|
+
socketPath,
|
|
276
|
+
pid: process.pid,
|
|
277
|
+
projectDir,
|
|
278
|
+
startedAt: new Date().toISOString(),
|
|
279
|
+
headless,
|
|
280
|
+
};
|
|
281
|
+
writeFileSync(metaPath(projectDir, sessionId), JSON.stringify(meta, null, 2));
|
|
282
|
+
process.on("SIGTERM", () => void shutdown());
|
|
283
|
+
process.on("SIGINT", () => void shutdown());
|
|
284
|
+
}
|
|
285
|
+
/** Entry point for the hidden `__auto-serve` CLI command (runs in the detached child). */
|
|
286
|
+
export async function runAutoServeCommand(init, sessionId) {
|
|
287
|
+
const session = await AutoSession.start({ ...init, sessionId });
|
|
288
|
+
await serveSession(session, init.projectDir, sessionId, init.headless ?? true);
|
|
289
|
+
// Keep the event loop alive - the listening server already does this,
|
|
290
|
+
// but await forever here documents the intent for a reader.
|
|
291
|
+
await new Promise(() => { });
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Parent-side: spawns a detached background process running the same
|
|
295
|
+
* explore session as a socket server, waits for it to signal readiness (its
|
|
296
|
+
* metadata file appearing), and returns its identity. Recurses through the
|
|
297
|
+
* existing `bin/waygraph` launcher (same tsx/esm registration every other
|
|
298
|
+
* invocation already gets) with the hidden `__auto-serve` command, rather
|
|
299
|
+
* than re-implementing that resolution here.
|
|
300
|
+
*/
|
|
301
|
+
export async function spawnDetachedSession(init, readyTimeoutMs = 20_000) {
|
|
302
|
+
const sessionId = generateSessionId();
|
|
303
|
+
mkdirSync(sessionDir(init.projectDir), { recursive: true });
|
|
304
|
+
const launcher = join(dirname(fileURLToPath(import.meta.url)), "..", "bin", "waygraph");
|
|
305
|
+
const logFd = openSync(logPathFor(init.projectDir, sessionId), "a");
|
|
306
|
+
const args = ["__auto-serve", init.projectDir, "--session-id", sessionId];
|
|
307
|
+
if (init.baseURL)
|
|
308
|
+
args.push("--base-url", init.baseURL);
|
|
309
|
+
if (init.headless === false)
|
|
310
|
+
args.push("--non-headless");
|
|
311
|
+
const child = spawn(process.execPath, [launcher, ...args], {
|
|
312
|
+
detached: true,
|
|
313
|
+
stdio: ["ignore", logFd, logFd],
|
|
314
|
+
windowsHide: true,
|
|
315
|
+
});
|
|
316
|
+
child.unref();
|
|
317
|
+
const deadline = Date.now() + readyTimeoutMs;
|
|
318
|
+
while (Date.now() < deadline) {
|
|
319
|
+
const meta = readSessionMeta(init.projectDir, sessionId);
|
|
320
|
+
if (meta)
|
|
321
|
+
return meta;
|
|
322
|
+
await new Promise((r) => setTimeout(r, 150));
|
|
323
|
+
}
|
|
324
|
+
throw new Error(`session "${sessionId}" did not become ready within ${readyTimeoutMs}ms - ` +
|
|
325
|
+
`check ${logPathFor(init.projectDir, sessionId)} for errors`);
|
|
326
|
+
}
|
|
327
|
+
function printSnapshotMenu(snapshot) {
|
|
328
|
+
console.log("");
|
|
329
|
+
console.log(`You are here: ${snapshot.here ?? "Unknown (pick Start here)"}`);
|
|
330
|
+
if (snapshot.lastRunNote)
|
|
331
|
+
console.log(snapshot.lastRunNote);
|
|
332
|
+
console.log("");
|
|
333
|
+
if (snapshot.done) {
|
|
334
|
+
console.log(" (no moves available on this page)");
|
|
335
|
+
}
|
|
336
|
+
for (const section of snapshot.sections) {
|
|
337
|
+
console.log(` -- ${section.title} --`);
|
|
338
|
+
for (const edge of section.edges) {
|
|
339
|
+
if (edge.label) {
|
|
340
|
+
console.log(` [${edge.index}] ${edge.label}`);
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
const desc = edge.description ? ` - ${edge.description}` : "";
|
|
344
|
+
console.log(` [${edge.index}] ${edge.block} (${edge.kind}) -> ${edge.to}${desc}`);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
console.log(" [q] quit");
|
|
349
|
+
console.log("");
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Client-only interactive loop against a running detached session - reopens
|
|
353
|
+
* the same rendering/parsing the foreground `--cli` loop uses, driven purely
|
|
354
|
+
* through `status`/`send`. No server-side support beyond those two ops.
|
|
355
|
+
*/
|
|
356
|
+
export async function runAttachLoop(projectDir, sessionId) {
|
|
357
|
+
const rl = createInterface({ input, output });
|
|
358
|
+
try {
|
|
359
|
+
for (;;) {
|
|
360
|
+
const statusRes = await requestSession(projectDir, sessionId, { op: "status" });
|
|
361
|
+
if (!statusRes.ok) {
|
|
362
|
+
console.error(`waygraph auto attach: ${statusRes.error}`);
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
printSnapshotMenu(statusRes.snapshot);
|
|
366
|
+
const ans = await rl.question("Choose: ");
|
|
367
|
+
const sendRes = await requestSession(projectDir, sessionId, { op: "send", pick: ans });
|
|
368
|
+
if (!sendRes.ok) {
|
|
369
|
+
console.error(`waygraph auto attach: ${sendRes.error}`);
|
|
370
|
+
continue;
|
|
371
|
+
}
|
|
372
|
+
if (sendRes.quit) {
|
|
373
|
+
console.error("waygraph auto attach: session quit.");
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
finally {
|
|
379
|
+
rl.close();
|
|
380
|
+
}
|
|
381
|
+
}
|