waygraph 0.15.53 → 0.16.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 (556) hide show
  1. package/README.md +8 -3
  2. package/bin/waygraph +2 -2
  3. package/dist/analysis/check.d.ts +38 -0
  4. package/dist/analysis/check.js +87 -0
  5. package/dist/analysis/coverage-gap.d.ts +1 -1
  6. package/dist/analysis/coverage-gap.js +14 -37
  7. package/dist/analysis/flow-source.d.ts +9 -0
  8. package/dist/analysis/flow-source.js +25 -0
  9. package/dist/analysis/graph.d.ts +13 -14
  10. package/dist/analysis/graph.js +48 -371
  11. package/dist/analysis/map-check.js +4 -39
  12. package/dist/analysis/practices-check.d.ts +1 -1
  13. package/dist/analysis/practices-check.js +24 -45
  14. package/dist/cli/args.d.ts +23 -0
  15. package/dist/cli/args.js +20 -0
  16. package/dist/{cli.d.ts → cli/cli.d.ts} +0 -1
  17. package/dist/{cli.js → cli/cli.js} +10 -9
  18. package/dist/{commands → cli/commands}/agent-dive-scaffold.js +35 -64
  19. package/dist/cli/commands/agent-dive.js +42 -0
  20. package/dist/{commands → cli/commands}/check.d.ts +0 -1
  21. package/dist/cli/commands/check.js +104 -0
  22. package/dist/cli/commands/codemod-checkpoints.d.ts +18 -0
  23. package/dist/cli/commands/codemod-checkpoints.js +186 -0
  24. package/dist/cli/commands/codemod-flows.d.ts +18 -0
  25. package/dist/cli/commands/codemod-flows.js +284 -0
  26. package/dist/cli/commands/codemod-stubs.d.ts +10 -0
  27. package/dist/cli/commands/codemod-stubs.js +187 -0
  28. package/dist/{commands → cli/commands}/extensions.js +5 -4
  29. package/dist/{commands → cli/commands}/init.js +1 -2
  30. package/dist/{commands → cli/commands}/list.js +9 -7
  31. package/dist/cli/commands/manifest.d.ts +2 -0
  32. package/dist/cli/commands/manifest.js +20 -0
  33. package/dist/cli/commands/map.js +57 -0
  34. package/dist/{commands → cli/commands}/run.d.ts +0 -1
  35. package/dist/cli/commands/run.js +64 -0
  36. package/dist/{commands → cli/commands}/session.js +61 -88
  37. package/dist/{commands → cli/commands}/test.js +11 -14
  38. package/dist/cli/commands/traverse.js +105 -0
  39. package/dist/{commands → cli/commands}/try.js +29 -25
  40. package/dist/{commands → cli/commands}/upgrade.js +40 -4
  41. package/dist/cli/flags.d.ts +193 -16
  42. package/dist/cli/flags.js +179 -234
  43. package/dist/cli/run-chain.d.ts +1 -0
  44. package/dist/cli/run-chain.js +42 -7
  45. package/dist/cli/usage.d.ts +1 -1
  46. package/dist/cli/usage.js +21 -53
  47. package/dist/cli/util.d.ts +2 -2
  48. package/dist/cli/util.js +2 -3
  49. package/dist/{highlights → demo/narration}/css.d.ts +1 -1
  50. package/dist/{highlights → demo/narration}/css.js +2 -3
  51. package/dist/{highlights → demo/narration}/demo-pace.d.ts +7 -11
  52. package/dist/{highlights → demo/narration}/demo-pace.js +9 -11
  53. package/dist/{highlights → demo/narration}/device.d.ts +4 -2
  54. package/dist/{highlights → demo/narration}/device.js +3 -1
  55. package/dist/demo/narration/merge.d.ts +8 -0
  56. package/dist/demo/narration/merge.js +71 -0
  57. package/dist/{highlights/run-phase.d.ts → demo/narration/narration.d.ts} +10 -14
  58. package/dist/{highlights/run-phase.js → demo/narration/narration.js} +25 -94
  59. package/dist/{highlights → demo/narration}/shorthand.d.ts +1 -1
  60. package/dist/demo/narration/stub-ctx.d.ts +8 -0
  61. package/dist/demo/narration/stub-ctx.js +164 -0
  62. package/dist/{highlights → demo/narration}/style.d.ts +1 -7
  63. package/dist/{highlights → demo/narration}/style.js +1 -41
  64. package/dist/{highlights → demo/narration}/todo-dock.d.ts +3 -3
  65. package/dist/{highlights → demo/narration}/todo-dock.js +13 -30
  66. package/dist/demo/overlay/auto-chrome.d.ts +7 -0
  67. package/dist/demo/overlay/auto-chrome.js +97 -0
  68. package/dist/{session/overlay-beacon.d.ts → demo/overlay/beacon.d.ts} +7 -0
  69. package/dist/{session/overlay-beacon.js → demo/overlay/beacon.js} +5 -0
  70. package/dist/demo/overlay/cursor.d.ts +12 -0
  71. package/dist/demo/overlay/cursor.js +142 -0
  72. package/dist/demo/overlay/device-stage.d.ts +13 -0
  73. package/dist/demo/overlay/device-stage.js +396 -0
  74. package/dist/demo/overlay/inpage/banner.d.ts +1 -0
  75. package/dist/demo/overlay/inpage/banner.js +160 -0
  76. package/dist/demo/overlay/inpage/caption.d.ts +2 -0
  77. package/dist/demo/overlay/inpage/caption.js +24 -0
  78. package/dist/demo/overlay/inpage/core.d.ts +1 -0
  79. package/dist/demo/overlay/inpage/core.js +345 -0
  80. package/dist/demo/overlay/inpage/device-chip.d.ts +1 -0
  81. package/dist/demo/overlay/inpage/device-chip.js +191 -0
  82. package/dist/demo/overlay/inpage/network.d.ts +9 -0
  83. package/dist/demo/overlay/inpage/network.js +200 -0
  84. package/dist/demo/overlay/inpage/panel-chrome.d.ts +1 -0
  85. package/dist/demo/overlay/inpage/panel-chrome.js +203 -0
  86. package/dist/demo/overlay/inpage/stamp.d.ts +1 -0
  87. package/dist/demo/overlay/inpage/stamp.js +46 -0
  88. package/dist/demo/overlay/inpage/swipe-zoom.d.ts +1 -0
  89. package/dist/demo/overlay/inpage/swipe-zoom.js +220 -0
  90. package/dist/demo/overlay/inpage/todos.d.ts +1 -0
  91. package/dist/demo/overlay/inpage/todos.js +294 -0
  92. package/dist/demo/overlay/locator-theater.d.ts +25 -0
  93. package/dist/demo/overlay/locator-theater.js +76 -0
  94. package/dist/demo/overlay/network-capture.d.ts +22 -0
  95. package/dist/demo/overlay/network-capture.js +127 -0
  96. package/dist/demo/overlay/overlay-css.d.ts +3 -0
  97. package/dist/demo/overlay/overlay-css.js +369 -0
  98. package/dist/demo/overlay/overlay-stage.d.ts +23 -0
  99. package/dist/demo/overlay/overlay-stage.js +106 -0
  100. package/dist/demo/overlay/overlay.d.ts +10 -0
  101. package/dist/demo/overlay/overlay.js +89 -0
  102. package/dist/{pilot-overlay/overlay-fixtures.d.ts → demo/overlay/phase-fixtures.d.ts} +2 -2
  103. package/dist/{pilot-overlay/overlay-fixtures.js → demo/overlay/phase-fixtures.js} +2 -2
  104. package/dist/{pilot-overlay/action-ring.js → demo/overlay/pilot/actions.js} +2 -1
  105. package/dist/{pilot-overlay → demo/overlay/pilot}/fixtures.d.ts +6 -5
  106. package/dist/{pilot-overlay → demo/overlay/pilot}/fixtures.js +19 -18
  107. package/dist/{pilot-overlay → demo/overlay/pilot}/shell.d.ts +2 -2
  108. package/dist/{pilot-overlay → demo/overlay/pilot}/shell.js +13 -22
  109. package/dist/demo/overlay/reattach.d.ts +7 -0
  110. package/dist/demo/overlay/reattach.js +23 -0
  111. package/dist/demo/overlay/rings.d.ts +33 -0
  112. package/dist/demo/overlay/rings.js +448 -0
  113. package/dist/{ui → demo/overlay/ui}/components/ring.js +2 -2
  114. package/dist/{ui → demo/overlay/ui}/overlay.css +4 -4
  115. package/dist/{ui → demo/overlay/ui}/shadow.d.ts +1 -1
  116. package/dist/{ui → demo/overlay/ui}/shadow.js +39 -2
  117. package/dist/demo/stepper/after.d.ts +3 -0
  118. package/dist/demo/stepper/after.js +113 -0
  119. package/dist/demo/stepper/banner-log.d.ts +37 -0
  120. package/dist/demo/stepper/banner-log.js +63 -0
  121. package/dist/demo/stepper/before.d.ts +4 -0
  122. package/dist/demo/stepper/before.js +110 -0
  123. package/dist/demo/stepper/demo-log.d.ts +31 -0
  124. package/dist/demo/stepper/demo-log.js +309 -0
  125. package/dist/demo/stepper/gate.d.ts +11 -0
  126. package/dist/demo/stepper/gate.js +78 -0
  127. package/dist/demo/stepper/interaction-patch.d.ts +3 -0
  128. package/dist/demo/stepper/interaction-patch.js +323 -0
  129. package/dist/demo/stepper/pacing.d.ts +21 -0
  130. package/dist/demo/stepper/pacing.js +23 -0
  131. package/dist/demo/stepper/slides.d.ts +11 -0
  132. package/dist/demo/stepper/slides.js +233 -0
  133. package/dist/demo/stepper/step-panels.d.ts +21 -0
  134. package/dist/demo/stepper/step-panels.js +589 -0
  135. package/dist/demo/stepper/stepper.d.ts +24 -0
  136. package/dist/demo/stepper/stepper.js +122 -0
  137. package/dist/demo/stepper/teardown.d.ts +48 -0
  138. package/dist/demo/stepper/teardown.js +179 -0
  139. package/dist/demo/stepper/todo-advance.d.ts +14 -0
  140. package/dist/demo/stepper/todo-advance.js +110 -0
  141. package/dist/demo/stepper/view.d.ts +68 -0
  142. package/dist/demo/stepper/view.js +31 -0
  143. package/dist/demo/types.d.ts +17 -0
  144. package/dist/demo/verbose-log.js +15 -0
  145. package/dist/{types.d.ts → engine/block/block.d.ts} +106 -91
  146. package/dist/{core → engine/block}/block.js +10 -53
  147. package/dist/{core → engine/block}/compose.d.ts +10 -7
  148. package/dist/{core → engine/block}/compose.js +1 -1
  149. package/dist/{core/blocks → engine/block/kinds}/api.d.ts +17 -12
  150. package/dist/{core/blocks → engine/block/kinds}/api.js +26 -18
  151. package/dist/{core/blocks → engine/block/kinds}/effect.d.ts +13 -18
  152. package/dist/engine/block/kinds/effect.js +17 -0
  153. package/dist/{core/blocks → engine/block/kinds}/method.d.ts +19 -29
  154. package/dist/{core/blocks → engine/block/kinds}/method.js +7 -21
  155. package/dist/{core/blocks → engine/block/kinds}/nav.d.ts +22 -31
  156. package/dist/{core/blocks → engine/block/kinds}/nav.js +6 -12
  157. package/dist/{core/blocks → engine/block/kinds}/page.d.ts +15 -20
  158. package/dist/{core/blocks → engine/block/kinds}/page.js +5 -7
  159. package/dist/engine/checkpoint/checkpoint.d.ts +22 -0
  160. package/dist/engine/checkpoint/checkpoint.js +8 -0
  161. package/dist/engine/checkpoint/route.d.ts +28 -0
  162. package/dist/engine/checkpoint/route.js +28 -0
  163. package/dist/{core → engine}/config.d.ts +7 -2
  164. package/dist/engine/config.js +6 -0
  165. package/dist/engine/engine.d.ts +45 -0
  166. package/dist/{core → engine}/engine.js +6 -10
  167. package/dist/engine/env.d.ts +59 -0
  168. package/dist/engine/env.js +83 -0
  169. package/dist/{errors.d.ts → engine/errors.d.ts} +23 -22
  170. package/dist/{errors.js → engine/errors.js} +22 -22
  171. package/dist/{core → engine/flow}/branch-regression.d.ts +8 -7
  172. package/dist/{core → engine/flow}/branch-regression.js +4 -3
  173. package/dist/engine/flow/flow.d.ts +162 -0
  174. package/dist/engine/flow/flow.js +244 -0
  175. package/dist/{core → engine/flow}/map-builder.d.ts +42 -40
  176. package/dist/{core → engine/flow}/map-builder.js +46 -48
  177. package/dist/{core → engine}/locate.d.ts +1 -1
  178. package/dist/{core → engine}/locate.js +1 -2
  179. package/dist/{mem-stub.d.ts → engine/mem/mem-stub.d.ts} +9 -8
  180. package/dist/{mem-stub.js → engine/mem/mem-stub.js} +2 -2
  181. package/dist/{mem-page.d.ts → engine/mem/mem.d.ts} +1 -1
  182. package/dist/{mem-page.js → engine/mem/mem.js} +2 -1
  183. package/dist/engine/page-gone.d.ts +5 -0
  184. package/dist/engine/page-gone.js +20 -0
  185. package/dist/engine/run/connect.d.ts +28 -0
  186. package/dist/{types.js → engine/run/connect.js} +11 -10
  187. package/dist/engine/run/events.d.ts +67 -0
  188. package/dist/engine/run/events.js +90 -0
  189. package/dist/engine/run/hooks.d.ts +16 -0
  190. package/dist/engine/run/hooks.js +8 -0
  191. package/dist/engine/run/launch.d.ts +13 -0
  192. package/dist/engine/run/launch.js +27 -0
  193. package/dist/{core/run-graph.d.ts → engine/run/run.d.ts} +9 -11
  194. package/dist/{core/run-graph.js → engine/run/run.js} +22 -11
  195. package/dist/engine/stub/pace.d.ts +12 -0
  196. package/dist/engine/stub/pace.js +2 -0
  197. package/dist/engine/stub/ring.d.ts +130 -0
  198. package/dist/engine/stub/ring.js +41 -0
  199. package/dist/engine/stub/stub.d.ts +268 -0
  200. package/dist/engine/stub/stub.js +1 -0
  201. package/dist/engine/stub/todos.d.ts +104 -0
  202. package/dist/engine/stub/todos.js +2 -0
  203. package/dist/engine/stub/viewport.d.ts +26 -0
  204. package/dist/engine/stub/viewport.js +2 -0
  205. package/dist/{trait.d.ts → engine/trait/trait.d.ts} +1 -1
  206. package/dist/index.d.ts +84 -36
  207. package/dist/index.js +44 -19
  208. package/dist/{session/auto-explore-run.d.ts → live/auto/auto.d.ts} +10 -16
  209. package/dist/{session/auto-explore-run.js → live/auto/auto.js} +164 -248
  210. package/dist/{session/auto-explore.d.ts → live/auto/explore.d.ts} +4 -14
  211. package/dist/{session/auto-explore.js → live/auto/explore.js} +21 -127
  212. package/dist/{auto-session/session.d.ts → live/auto-session/auto-session.d.ts} +1 -1
  213. package/dist/{auto-session/session.js → live/auto-session/auto-session.js} +27 -24
  214. package/dist/{auto-session → live/auto-session}/helpers.d.ts +16 -5
  215. package/dist/{auto-session → live/auto-session}/helpers.js +1 -1
  216. package/dist/{session/auto-session-ipc.d.ts → live/auto-session/ipc.d.ts} +7 -5
  217. package/dist/{session/auto-session-ipc.js → live/auto-session/ipc.js} +31 -16
  218. package/dist/{session/browser.d.ts → live/auto-session/start.d.ts} +1 -2
  219. package/dist/{session/browser.js → live/auto-session/start.js} +2 -3
  220. package/dist/{pilot-overlay → live/pilot}/panel.d.ts +1 -1
  221. package/dist/{pilot-overlay → live/pilot}/panel.js +23 -31
  222. package/dist/{session → live/pilot}/pilot.d.ts +4 -3
  223. package/dist/{session → live/pilot}/pilot.js +4 -4
  224. package/dist/{traverse → live/traverse}/coverage.d.ts +4 -0
  225. package/dist/{traverse → live/traverse}/coverage.js +3 -0
  226. package/dist/{traverse → live/traverse}/lease.d.ts +1 -0
  227. package/dist/{traverse → live/traverse}/lease.js +1 -0
  228. package/dist/{traverse/run.d.ts → live/traverse/traverse.d.ts} +4 -1
  229. package/dist/{traverse/run.js → live/traverse/traverse.js} +26 -43
  230. package/dist/manifest/manifest.d.ts +52 -0
  231. package/dist/manifest/manifest.js +93 -0
  232. package/dist/manifest/map-imports.d.ts +7 -0
  233. package/dist/manifest/map-imports.js +22 -0
  234. package/dist/manifest/maps.d.ts +33 -0
  235. package/dist/manifest/maps.js +62 -0
  236. package/dist/manifest/pack.d.ts +21 -0
  237. package/dist/manifest/pack.js +109 -0
  238. package/dist/manifest/project.d.ts +60 -0
  239. package/dist/manifest/project.js +101 -0
  240. package/dist/{session/block-inject.js → manifest/roots.js} +1 -18
  241. package/dist/manifest/scan.d.ts +19 -0
  242. package/dist/manifest/scan.js +57 -0
  243. package/dist/{blocks-select.d.ts → manifest/select.d.ts} +3 -0
  244. package/dist/{blocks-select.js → manifest/select.js} +2 -0
  245. package/dist/manifest/source.d.ts +23 -0
  246. package/dist/manifest/source.js +86 -0
  247. package/dist/runner/mode.d.ts +71 -0
  248. package/dist/runner/mode.js +1 -0
  249. package/dist/runner/modes/branches.d.ts +5 -0
  250. package/dist/runner/modes/branches.js +37 -0
  251. package/dist/runner/modes/demo.d.ts +3 -0
  252. package/dist/runner/modes/demo.js +13 -0
  253. package/dist/runner/modes/report.d.ts +2 -0
  254. package/dist/runner/modes/report.js +54 -0
  255. package/dist/runner/modes/run.d.ts +2 -0
  256. package/dist/runner/modes/run.js +3 -0
  257. package/dist/runner/options.d.ts +31 -0
  258. package/dist/runner/options.js +42 -0
  259. package/dist/runner/plan/find.d.ts +18 -0
  260. package/dist/runner/plan/find.js +65 -0
  261. package/dist/runner/plan/plan.d.ts +11 -0
  262. package/dist/runner/plan/plan.js +97 -0
  263. package/dist/runner/plan/seed-mem.d.ts +12 -0
  264. package/dist/runner/plan/seed-mem.js +98 -0
  265. package/dist/runner/plan/spec.d.ts +5 -0
  266. package/dist/runner/plan/spec.js +17 -0
  267. package/dist/runner/play-steps.d.ts +2 -0
  268. package/dist/runner/play-steps.js +59 -0
  269. package/dist/runner/runner.d.ts +4 -0
  270. package/dist/runner/runner.js +64 -0
  271. package/dist/runner/session.d.ts +9 -0
  272. package/dist/runner/session.js +87 -0
  273. package/dist/{browser.js → runtime/browser.js} +4 -2
  274. package/dist/{env-file.js → runtime/env-file.js} +7 -12
  275. package/dist/{extensions.d.ts → runtime/extensions.d.ts} +2 -5
  276. package/dist/{extensions.js → runtime/extensions.js} +3 -1
  277. package/dist/runtime/full-launch.d.ts +1 -0
  278. package/dist/runtime/full-launch.js +34 -0
  279. package/dist/runtime/global-flag.d.ts +5 -0
  280. package/dist/runtime/global-flag.js +18 -0
  281. package/dist/{playwright-config.d.ts → runtime/playwright-config.d.ts} +1 -1
  282. package/dist/{playwright.config.js → runtime/playwright.config.js} +3 -2
  283. package/dist/runtime/run-log.d.ts +2 -0
  284. package/dist/runtime/run-log.js +17 -0
  285. package/dist/{video-dir.js → runtime/video-dir.js} +3 -2
  286. package/dist/{config.d.ts → runtime/waygraph-config.d.ts} +8 -9
  287. package/dist/{config.js → runtime/waygraph-config.js} +21 -51
  288. package/dist/{webserver.js → runtime/webserver.js} +5 -30
  289. package/examples/routed-demo/config/waygraph.config.ts +20 -0
  290. package/examples/routed-demo/package.json +1 -4
  291. package/examples/routed-demo/scripts/fixture-server.mjs +1 -1
  292. package/examples/routed-demo/src/flows/routed-demo-map.flow.ts +2 -4
  293. package/examples/routed-demo/src/flows/routed-demo.flow.ts +2 -3
  294. package/examples/routed-demo/src/map/(app_base)/dashboard/_methods/click-widget.block.ts +5 -4
  295. package/examples/routed-demo/src/map/(app_base)/dashboard/_nav.block.ts +3 -3
  296. package/examples/routed-demo/src/map/(app_base)/dashboard/_page.block.ts +3 -3
  297. package/examples/routed-demo/src/map/(external)/docs/_nav.block.ts +3 -3
  298. package/examples/routed-demo/src/map/(external)/docs/_page.block.ts +3 -3
  299. package/examples/routed-demo/src/states/routed-demo.states.ts +5 -3
  300. package/examples/routed-demo/tests/routed-demo.spec.ts +4 -4
  301. package/examples/routed-demo/tsconfig.json +1 -1
  302. package/examples/saucedemo/README.md +11 -12
  303. package/examples/saucedemo/config/waygraph.config.ts +17 -0
  304. package/examples/saucedemo/docs/CONVENTION.md +5 -7
  305. package/examples/saucedemo/docs/HELPERS.md +12 -12
  306. package/examples/saucedemo/package-lock.json +10 -3
  307. package/examples/saucedemo/package.json +12 -29
  308. package/examples/saucedemo/src/blocks/SITE-MAP.md +0 -1
  309. package/examples/saucedemo/src/blocks/saucedemo-web/NAV.md +1 -5
  310. package/examples/saucedemo/src/blocks/saucedemo-web/cart/nav-cart.block.ts +3 -52
  311. package/examples/saucedemo/src/blocks/saucedemo-web/cart/nav-checkout-info.block.ts +3 -3
  312. package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/methods/fill-first-name.method.block.ts +5 -4
  313. package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/methods/fill-last-name.method.block.ts +5 -4
  314. package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/methods/fill-postal-code.method.block.ts +5 -4
  315. package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/methods/submit-checkout-info.method.block.ts +5 -4
  316. package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-two/methods/finish-order.method.block.ts +21 -27
  317. package/examples/saucedemo/src/blocks/saucedemo-web/inventory/inventory.page.block.ts +3 -9
  318. package/examples/saucedemo/src/blocks/saucedemo-web/inventory/methods/add-all-to-cart.method.block.ts +4 -6
  319. package/examples/saucedemo/src/blocks/saucedemo-web/inventory/methods/add-to-cart.effect.block.ts +10 -76
  320. package/examples/saucedemo/src/blocks/saucedemo-web/inventory/methods/remove-all-from-cart.method.block.ts +4 -6
  321. package/examples/saucedemo/src/blocks/saucedemo-web/inventory/methods/remove-from-cart.effect.block.ts +4 -3
  322. package/examples/saucedemo/src/blocks/saucedemo-web/inventory/nav-item-detail.block.ts +3 -3
  323. package/examples/saucedemo/src/blocks/saucedemo-web/inventory-item/nav-back-to-inventory.block.ts +3 -3
  324. package/examples/saucedemo/src/blocks/saucedemo-web/inventory-item/nav-back-to-products.block.ts +3 -3
  325. package/examples/saucedemo/src/blocks/saucedemo-web/inventory-item/nav-continue-shopping.block.ts +3 -3
  326. package/examples/saucedemo/src/blocks/saucedemo-web/methods/fill-password.method.block.ts +5 -29
  327. package/examples/saucedemo/src/blocks/saucedemo-web/methods/fill-username.method.block.ts +5 -48
  328. package/examples/saucedemo/src/blocks/saucedemo-web/methods/submit-login.method.block.ts +13 -77
  329. package/examples/saucedemo/src/blocks/saucedemo-web/methods/submit-logout.method.block.ts +5 -4
  330. package/examples/saucedemo/src/blocks/saucedemo-web/nav-login.block.ts +3 -3
  331. package/examples/saucedemo/src/flows/api-demo.flow.ts +26 -18
  332. package/examples/saucedemo/src/flows/cart-bulk.flow.ts +19 -14
  333. package/examples/saucedemo/src/flows/cart-continue.flow.ts +10 -8
  334. package/examples/saucedemo/src/flows/cart-mem.flow.ts +7 -7
  335. package/examples/saucedemo/src/flows/catalog-logout.flow.ts +13 -8
  336. package/examples/saucedemo/src/flows/checkout-then-browse-again.flow.ts +26 -48
  337. package/examples/saucedemo/src/flows/checkout.flow.ts +70 -86
  338. package/examples/saucedemo/src/flows/device-showcase.flow.ts +24 -25
  339. package/examples/saucedemo/src/flows/login.flow.ts +11 -18
  340. package/examples/saucedemo/src/flows/mem-stub-demo.flow.ts +9 -20
  341. package/examples/saucedemo/src/flows/shop.flow.ts +15 -20
  342. package/examples/saucedemo/src/flows/smoke.flow.ts +12 -27
  343. package/examples/saucedemo/src/flows/stub-on-error.flow.ts +24 -43
  344. package/examples/saucedemo/src/flows/viewer-blocked.flow.ts +26 -34
  345. package/examples/saucedemo/src/states/checkout.mem-stubs.ts +11 -0
  346. package/examples/saucedemo/src/states/checkout.states.ts +21 -11
  347. package/examples/saucedemo/src/stubs/device-showcase.ts +191 -0
  348. package/examples/saucedemo/src/stubs/login.ts +37 -0
  349. package/examples/saucedemo/tests/auto-graph.spec.ts +4 -12
  350. package/examples/saucedemo/tests/chain-flow-episodes.spec.ts +7 -9
  351. package/examples/saucedemo/tests/submit-login-branch.spec.ts +18 -5
  352. package/package.json +12 -7
  353. package/templates/agents/waygraph-planner.agent.md +2 -2
  354. package/templates/quickstart/README.md +4 -7
  355. package/templates/quickstart/config/waygraph.config.ts +17 -0
  356. package/templates/quickstart/docs/CONVENTION.md +5 -6
  357. package/templates/quickstart/docs/HELPERS.md +11 -9
  358. package/templates/quickstart/package.json +14 -17
  359. package/templates/quickstart/src/blocks/SITE-MAP.md +13 -3
  360. package/templates/quickstart/src/blocks/saucedemo-web/NAV.md +1 -5
  361. package/templates/quickstart/src/blocks/saucedemo-web/cart/nav-cart.block.ts +3 -52
  362. package/templates/quickstart/src/blocks/saucedemo-web/cart/nav-checkout-info.block.ts +3 -3
  363. package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/methods/fill-first-name.method.block.ts +5 -4
  364. package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/methods/fill-last-name.method.block.ts +5 -4
  365. package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/methods/fill-postal-code.method.block.ts +5 -4
  366. package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/methods/submit-checkout-info.method.block.ts +5 -4
  367. package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-two/methods/finish-order.method.block.ts +21 -27
  368. package/templates/quickstart/src/blocks/saucedemo-web/inventory/inventory.page.block.ts +3 -9
  369. package/templates/quickstart/src/blocks/saucedemo-web/inventory/methods/add-all-to-cart.method.block.ts +4 -6
  370. package/templates/quickstart/src/blocks/saucedemo-web/inventory/methods/add-to-cart.effect.block.ts +10 -76
  371. package/templates/quickstart/src/blocks/saucedemo-web/inventory/methods/remove-all-from-cart.method.block.ts +4 -6
  372. package/templates/quickstart/src/blocks/saucedemo-web/inventory/methods/remove-from-cart.effect.block.ts +4 -3
  373. package/templates/quickstart/src/blocks/saucedemo-web/inventory/nav-item-detail.block.ts +3 -3
  374. package/templates/quickstart/src/blocks/saucedemo-web/inventory-item/nav-back-to-inventory.block.ts +3 -3
  375. package/templates/quickstart/src/blocks/saucedemo-web/inventory-item/nav-back-to-products.block.ts +3 -3
  376. package/templates/quickstart/src/blocks/saucedemo-web/inventory-item/nav-continue-shopping.block.ts +3 -3
  377. package/templates/quickstart/src/blocks/saucedemo-web/methods/fill-password.method.block.ts +5 -29
  378. package/templates/quickstart/src/blocks/saucedemo-web/methods/fill-username.method.block.ts +5 -48
  379. package/templates/quickstart/src/blocks/saucedemo-web/methods/submit-login.method.block.ts +13 -77
  380. package/templates/quickstart/src/blocks/saucedemo-web/methods/submit-logout.method.block.ts +5 -4
  381. package/templates/quickstart/src/blocks/saucedemo-web/nav-login.block.ts +3 -3
  382. package/templates/quickstart/src/flows/api-demo.flow.ts +45 -0
  383. package/templates/quickstart/src/flows/cart-bulk.flow.ts +19 -14
  384. package/templates/quickstart/src/flows/cart-continue.flow.ts +10 -8
  385. package/templates/quickstart/src/flows/cart-mem.flow.ts +7 -7
  386. package/templates/quickstart/src/flows/catalog-logout.flow.ts +13 -8
  387. package/templates/quickstart/src/flows/checkout-then-browse-again.flow.ts +26 -48
  388. package/templates/quickstart/src/flows/checkout.flow.ts +70 -63
  389. package/templates/quickstart/src/flows/device-showcase.flow.ts +24 -25
  390. package/templates/quickstart/src/flows/login.flow.ts +11 -18
  391. package/templates/quickstart/src/flows/mem-stub-demo.flow.ts +12 -0
  392. package/templates/quickstart/src/flows/shop.flow.ts +15 -20
  393. package/templates/quickstart/src/flows/smoke.flow.ts +12 -27
  394. package/templates/quickstart/src/flows/stub-on-error.flow.ts +31 -0
  395. package/templates/quickstart/src/flows/viewer-blocked.flow.ts +26 -34
  396. package/templates/quickstart/src/states/checkout.mem-stubs.ts +11 -0
  397. package/templates/quickstart/src/states/checkout.states.ts +21 -11
  398. package/templates/quickstart/src/stubs/device-showcase.ts +191 -0
  399. package/templates/quickstart/src/stubs/login.ts +37 -0
  400. package/templates/quickstart/tests/chain-flow.spec.ts +7 -10
  401. package/templates/scaffold/README.md +2 -1
  402. package/templates/scaffold/STRUCTURE.md +5 -4
  403. package/templates/scaffold/config/waygraph.config.ts +1 -0
  404. package/templates/scaffold/gitignore +1 -0
  405. package/templates/scaffold/src/flows/README.md +2 -2
  406. package/templates/scaffold/src/map/(app_base)/docs/_nav.block.ts +3 -3
  407. package/templates/scaffold/src/map/(app_base)/docs/_page.block.ts +3 -3
  408. package/templates/scaffold/src/map/(app_base)/home/_methods/add-item.effect.block.ts +4 -4
  409. package/templates/scaffold/src/map/(app_base)/home/_methods/assert-hello.method.block.ts +3 -3
  410. package/templates/scaffold/src/map/(app_base)/home/_methods/assert-item-added.method.block.ts +3 -3
  411. package/templates/scaffold/src/map/(app_base)/home/_methods/clear-cart.method.block.ts +5 -4
  412. package/templates/scaffold/src/map/(app_base)/home/_methods/remove-item.effect.block.ts +4 -4
  413. package/templates/scaffold/src/map/(app_base)/home/_nav.block.ts +3 -3
  414. package/templates/scaffold/src/map/(app_base)/home/_page.block.ts +3 -3
  415. package/templates/scaffold/src/map/(app_base)/home/nav-verification-link.block.ts +4 -4
  416. package/templates/scaffold/src/map/(external)/hoppscotch/_keys.ts +21 -0
  417. package/templates/scaffold/src/map/(external)/hoppscotch/_methods/assert-response-body.method.block.ts +4 -4
  418. package/templates/scaffold/src/map/(external)/hoppscotch/_methods/assert-response-header.method.block.ts +4 -4
  419. package/templates/scaffold/src/map/(external)/hoppscotch/_methods/assert-status.method.block.ts +4 -4
  420. package/templates/scaffold/src/map/(external)/hoppscotch/_methods/pick-extension-interceptor.method.block.ts +5 -4
  421. package/templates/scaffold/src/map/(external)/hoppscotch/_methods/read-response-body.method.block.ts +6 -5
  422. package/templates/scaffold/src/map/(external)/hoppscotch/_methods/read-response-headers.method.block.ts +6 -5
  423. package/templates/scaffold/src/map/(external)/hoppscotch/_methods/send-request.method.block.ts +5 -4
  424. package/templates/scaffold/src/map/(external)/hoppscotch/_methods/set-bearer-token.method.block.ts +6 -5
  425. package/templates/scaffold/src/map/(external)/hoppscotch/_methods/set-headers.method.block.ts +6 -5
  426. package/templates/scaffold/src/map/(external)/hoppscotch/_methods/set-json-body.method.block.ts +6 -5
  427. package/templates/scaffold/src/map/(external)/hoppscotch/_methods/set-method.method.block.ts +6 -5
  428. package/templates/scaffold/src/map/(external)/hoppscotch/_methods/set-query-params.method.block.ts +6 -5
  429. package/templates/scaffold/src/map/(external)/hoppscotch/_methods/set-url.method.block.ts +6 -5
  430. package/templates/scaffold/src/map/(external)/hoppscotch/_nav.block.ts +3 -3
  431. package/templates/scaffold/src/map/(external)/hoppscotch/_page.block.ts +3 -3
  432. package/templates/scaffold/src/map/(external)/hoppscotch/_states.ts +6 -0
  433. package/templates/scaffold/src/map/(external)/hoppscotch/settings/_nav.block.ts +3 -3
  434. package/templates/scaffold/src/map/(external)/mailpit/_keys.ts +13 -0
  435. package/templates/scaffold/src/map/(external)/mailpit/_methods/assert-email-content.method.block.ts +4 -4
  436. package/templates/scaffold/src/map/(external)/mailpit/_methods/assert-email-received.method.block.ts +4 -4
  437. package/templates/scaffold/src/map/(external)/mailpit/_methods/extract-email-link.method.block.ts +6 -5
  438. package/templates/scaffold/src/map/(external)/mailpit/_methods/open-message.method.block.ts +6 -5
  439. package/templates/scaffold/src/map/(external)/mailpit/_nav.block.ts +3 -3
  440. package/templates/scaffold/src/map/(external)/mailpit/_page.block.ts +3 -3
  441. package/templates/scaffold/src/map/(external)/mailpit/_states.ts +9 -0
  442. package/templates/scaffold/src/map/README.md +7 -0
  443. package/templates/scaffold/src/states/README.md +4 -1
  444. package/templates/scaffold/src/states/demo.mem-keys.ts +1 -29
  445. package/templates/scaffold/src/states/demo.states.ts +14 -20
  446. package/templates/scaffold/tests/hoppscotch.spec.ts +1 -11
  447. package/templates/scaffold/tests/mail-verify.spec.ts +2 -2
  448. package/templates/skills/waygraph-blind-pilot.skill.md +2 -6
  449. package/templates/skills/waygraph-convention.skill.md +23 -14
  450. package/templates/skills/waygraph-pilot.skill.md +7 -4
  451. package/dist/auto-session/verbose-log.js +0 -16
  452. package/dist/auto-session.d.ts +0 -2
  453. package/dist/auto-session.js +0 -3
  454. package/dist/cli/discover.d.ts +0 -40
  455. package/dist/cli/discover.js +0 -148
  456. package/dist/commands/agent-dive.js +0 -52
  457. package/dist/commands/check.js +0 -192
  458. package/dist/commands/map.js +0 -29
  459. package/dist/commands/run.js +0 -104
  460. package/dist/commands/traverse.js +0 -177
  461. package/dist/core/block.d.ts +0 -109
  462. package/dist/core/blocks/effect.js +0 -23
  463. package/dist/core/config.js +0 -17
  464. package/dist/core/engine.d.ts +0 -198
  465. package/dist/core/flow.d.ts +0 -293
  466. package/dist/core/flow.js +0 -432
  467. package/dist/core.d.ts +0 -14
  468. package/dist/core.js +0 -15
  469. package/dist/highlights/merge.d.ts +0 -8
  470. package/dist/highlights/merge.js +0 -173
  471. package/dist/highlights/stub-ctx.d.ts +0 -10
  472. package/dist/highlights/stub-ctx.js +0 -331
  473. package/dist/highlights/types.d.ts +0 -607
  474. package/dist/highlights.d.ts +0 -9
  475. package/dist/highlights.js +0 -10
  476. package/dist/pilot-overlay.d.ts +0 -5
  477. package/dist/pilot-overlay.js +0 -6
  478. package/dist/runner/banner-log.js +0 -63
  479. package/dist/runner/chain-run.js +0 -102
  480. package/dist/runner/cursor.js +0 -140
  481. package/dist/runner/demo-log.js +0 -316
  482. package/dist/runner/device-stage.d.ts +0 -9
  483. package/dist/runner/device-stage.js +0 -420
  484. package/dist/runner/discovery.js +0 -105
  485. package/dist/runner/index.js +0 -2
  486. package/dist/runner/inpage/banner.d.ts +0 -21
  487. package/dist/runner/inpage/banner.js +0 -156
  488. package/dist/runner/inpage/caption.d.ts +0 -3
  489. package/dist/runner/inpage/caption.js +0 -23
  490. package/dist/runner/inpage/core.d.ts +0 -4
  491. package/dist/runner/inpage/core.js +0 -316
  492. package/dist/runner/inpage/device.d.ts +0 -3
  493. package/dist/runner/inpage/device.js +0 -211
  494. package/dist/runner/inpage/network.d.ts +0 -15
  495. package/dist/runner/inpage/network.js +0 -217
  496. package/dist/runner/inpage/panel-chrome.js +0 -192
  497. package/dist/runner/inpage/stamp.js +0 -46
  498. package/dist/runner/inpage/swipe-zoom.js +0 -220
  499. package/dist/runner/inpage/todos.js +0 -337
  500. package/dist/runner/interaction-patch.js +0 -384
  501. package/dist/runner/main.js +0 -469
  502. package/dist/runner/network-capture.d.ts +0 -9
  503. package/dist/runner/network-capture.js +0 -126
  504. package/dist/runner/overlay-css.d.ts +0 -3
  505. package/dist/runner/overlay-css.js +0 -377
  506. package/dist/runner/overlay-install.js +0 -90
  507. package/dist/runner/overlay-stage.js +0 -110
  508. package/dist/runner/rings.js +0 -514
  509. package/dist/runner/seed-mem.js +0 -110
  510. package/dist/runner/slides.js +0 -278
  511. package/dist/runner/step-mode.js +0 -703
  512. package/dist/runner/step-panels.js +0 -729
  513. package/dist/runner/teardown.js +0 -202
  514. package/dist/runner/todo-dock.js +0 -142
  515. package/dist/session/step-overlay.d.ts +0 -37
  516. package/dist/session/step-overlay.js +0 -244
  517. package/examples/routed-demo/playwright.config.ts +0 -21
  518. package/examples/saucedemo/playwright.config.ts +0 -19
  519. package/examples/saucedemo/scripts/drive-auto-cli.mjs +0 -93
  520. package/examples/saucedemo/scripts/prove-add-to-cart-menu.mjs +0 -126
  521. package/examples/saucedemo/scripts/prove-auto-graph.mjs +0 -92
  522. package/examples/saucedemo/scripts/prove-wrong-login-runtime.mjs +0 -63
  523. package/examples/saucedemo/src/blocks/saucedemo-web/ff-owner-auth.block.ts +0 -22
  524. package/templates/quickstart/playwright.config.ts +0 -14
  525. package/templates/quickstart/scripts/drive-auto-cli.mjs +0 -93
  526. package/templates/quickstart/src/blocks/saucedemo-web/ff-owner-auth.block.ts +0 -22
  527. /package/dist/{commands → cli/commands}/agent-dive-scaffold.d.ts +0 -0
  528. /package/dist/{commands → cli/commands}/agent-dive.d.ts +0 -0
  529. /package/dist/{commands → cli/commands}/extensions.d.ts +0 -0
  530. /package/dist/{commands → cli/commands}/init.d.ts +0 -0
  531. /package/dist/{commands → cli/commands}/list.d.ts +0 -0
  532. /package/dist/{commands → cli/commands}/map.d.ts +0 -0
  533. /package/dist/{commands → cli/commands}/session.d.ts +0 -0
  534. /package/dist/{commands → cli/commands}/test.d.ts +0 -0
  535. /package/dist/{commands → cli/commands}/traverse.d.ts +0 -0
  536. /package/dist/{commands → cli/commands}/try.d.ts +0 -0
  537. /package/dist/{commands → cli/commands}/upgrade.d.ts +0 -0
  538. /package/dist/{highlights → demo/narration}/shorthand.js +0 -0
  539. /package/dist/{pilot-overlay/action-ring.d.ts → demo/overlay/pilot/actions.d.ts} +0 -0
  540. /package/dist/{ui → demo/overlay/ui}/components/ring.d.ts +0 -0
  541. /package/dist/{ui → demo/overlay/ui}/stylesheet.d.ts +0 -0
  542. /package/dist/{ui → demo/overlay/ui}/stylesheet.js +0 -0
  543. /package/dist/{ui → demo/overlay/ui}/tokens.d.ts +0 -0
  544. /package/dist/{ui → demo/overlay/ui}/tokens.js +0 -0
  545. /package/dist/{highlights → demo}/types.js +0 -0
  546. /package/dist/{auto-session → demo}/verbose-log.d.ts +0 -0
  547. /package/dist/{selector.d.ts → engine/trait/selector.d.ts} +0 -0
  548. /package/dist/{selector.js → engine/trait/selector.js} +0 -0
  549. /package/dist/{trait.js → engine/trait/trait.js} +0 -0
  550. /package/dist/{session/block-inject.d.ts → manifest/roots.d.ts} +0 -0
  551. /package/dist/{browser.d.ts → runtime/browser.d.ts} +0 -0
  552. /package/dist/{env-file.d.ts → runtime/env-file.d.ts} +0 -0
  553. /package/dist/{playwright-config.js → runtime/playwright-config.js} +0 -0
  554. /package/dist/{playwright.config.d.ts → runtime/playwright.config.d.ts} +0 -0
  555. /package/dist/{video-dir.d.ts → runtime/video-dir.d.ts} +0 -0
  556. /package/dist/{webserver.d.ts → runtime/webserver.d.ts} +0 -0
@@ -1,7 +1,5 @@
1
- import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
2
- import { join, dirname, relative, resolve } from "node:path";
3
- import { matchBlocksSelect, } from "../blocks-select.js";
4
- import { exploreRoots, injectTaggedFile } from "../session/block-inject.js";
1
+ import { relative } from "node:path";
2
+ import { scanProject } from "../manifest/project.js";
5
3
  /**
6
4
  * Renders a `WaygraphGraph` as Mermaid `stateDiagram-v2` text - paste
7
5
  * straight into a `.md` file's ```mermaid fence or a live editor. `"*"`
@@ -17,127 +15,32 @@ export function toMermaid(graph) {
17
15
  }
18
16
  return lines.join("\n");
19
17
  }
20
- // ---------------------------------------------------------------------------
21
- // Discovery - deliberately self-contained (no import from cli.ts): cli.ts
22
- // runs its own main() unconditionally at module load, so it can't safely be
23
- // imported from a test (or from here) without also running the whole CLI.
24
- // These are small, stable duplicates of cli.ts's own discoverBlocks/
25
- // isBlockLike/isNavBlockMarked/importModule, not a shared abstraction -
26
- // simpler and lower-risk than a circular import between the two modules.
27
- // ---------------------------------------------------------------------------
28
- function walkDir(dir, pattern) {
29
- const results = [];
30
- let entries;
31
- try {
32
- entries = readdirSync(dir, { withFileTypes: true });
33
- }
34
- catch {
35
- return results;
36
- }
37
- for (const entry of entries) {
38
- const full = join(dir, entry.name);
39
- if (entry.isDirectory()) {
40
- if (entry.name === "node_modules" || entry.name === "dist" || entry.name === ".git")
41
- continue;
42
- results.push(...walkDir(full, pattern));
43
- }
44
- else if (pattern.test(entry.name)) {
45
- results.push(full);
46
- }
47
- }
48
- return results;
49
- }
50
- function discoverBlocks(projectDir) {
51
- return walkDir(projectDir, /\.block\.ts$/);
52
- }
53
- function discoverFlows(projectDir) {
54
- return walkDir(projectDir, /\.flow\.ts$/);
55
- }
56
- /** Block export ids a flow file uses: every identifier outside its import lines (a Block can sit in the array or in a local like `const AddShown = AddBlock.stubAfter(...)`). */
57
- function extractFlowBlockRefs(flowSrc) {
58
- const body = flowSrc.replace(/^\s*import[\s\S]*?;\s*$/gm, "").replace(/\/\/.*$/gm, "");
59
- return body.match(/[A-Za-z_$][\w$]*/g) ?? [];
60
- }
61
- function exportNameToBlockName(exportName) {
62
- const base = exportName.replace(/Block$/, "");
63
- return base
64
- .replace(/([a-z0-9])([A-Z])/g, "$1-$2")
65
- .replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2")
66
- .toLowerCase();
67
- }
68
18
  /**
69
- * Blocks present on disk but never wired into a `.flow.ts` defineFlow array.
70
- * Required before `chain auto` can build a path from the discovered graph -
71
- * orphan Blocks are intentionally excluded from auto shorthand. Arrival-only
72
- * Page hubs and Blocks listed on a Page's `methods` are not orphans.
19
+ * Blocks the project exports but no flow plays. Read at runtime: every flow's `blocks()` (nested flows flattened, plus
20
+ * the Blocks a `branch()` routes to) against every scanned Block. Page hubs and the Blocks a Page lists as its
21
+ * `methods` are not orphans.
73
22
  */
74
23
  export async function findOrphanBlocks(projectDir) {
75
- const blockFiles = discoverBlocks(projectDir);
76
- const flowFiles = discoverFlows(projectDir);
77
- const referenced = new Set();
78
- for (const flowFile of flowFiles) {
79
- for (const ref of extractFlowBlockRefs(readFileSync(flowFile, "utf-8"))) {
80
- referenced.add(ref);
24
+ const scan = await scanProject(projectDir, { maps: false });
25
+ const used = new Set();
26
+ for (const { flow } of scan.flows) {
27
+ for (const info of flow.blocks()) {
28
+ used.add(info.name);
29
+ for (const target of Object.values(info.routes ?? {}))
30
+ if (target)
31
+ used.add(target);
81
32
  }
82
33
  }
83
- const pageMethodNames = new Set();
84
- for (const file of blockFiles) {
85
- let mod;
86
- try {
87
- mod = await importModule(file);
88
- }
89
- catch {
34
+ for (const b of scan.blocks) {
35
+ if (b.kind !== "page")
90
36
  continue;
91
- }
92
- for (const exported of Object.values(mod)) {
93
- if (!exported || typeof exported !== "object")
94
- continue;
95
- if (exported.__waygraphKind !== "page")
96
- continue;
97
- const names = exported.__waygraphMethods;
98
- if (Array.isArray(names)) {
99
- for (const n of names)
100
- pageMethodNames.add(n);
101
- }
102
- }
37
+ for (const name of b.block.__waygraphMethods ?? [])
38
+ used.add(name);
103
39
  }
104
- const orphans = [];
105
- for (const file of blockFiles) {
106
- const relFile = relative(projectDir, file);
107
- const src = readFileSync(file, "utf-8");
108
- const exportRe = /export\s+const\s+([A-Za-z_$][\w]*)\s*=/g;
109
- let m;
110
- while ((m = exportRe.exec(src)) !== null) {
111
- const exportName = m[1];
112
- if (referenced.has(exportName))
113
- continue;
114
- if (!/defineBlock|defineMethodBlock|defineActionBlock|definePageBlock|defineEffectBlock|defineMemEffectBlock|defineNavBlock|defineNavClickBlock|defineMemNavBlock/.test(src))
115
- continue;
116
- // Arrival-only Page hubs are never orphans (even if import fails without tsx).
117
- const assignSlice = src.slice(m.index, m.index + exportName.length + 80);
118
- if (/=\s*definePageBlock\b/.test(assignSlice))
119
- continue;
120
- let block = exportNameToBlockName(exportName);
121
- try {
122
- const mod = await importModule(file);
123
- const exported = mod[exportName];
124
- if (isBlockLike(exported))
125
- block = exported.name;
126
- if (exported &&
127
- typeof exported === "object" &&
128
- exported.__waygraphKind === "page") {
129
- continue;
130
- }
131
- if (pageMethodNames.has(block))
132
- continue;
133
- }
134
- catch {
135
- // import may fail in partial projects - keep derived name
136
- }
137
- orphans.push({ exportName, block, file: relFile });
138
- }
139
- }
140
- return orphans.sort((a, b) => a.file.localeCompare(b.file) || a.exportName.localeCompare(b.exportName));
40
+ return scan.blocks
41
+ .filter((b) => b.kind !== "page" && !used.has(b.name))
42
+ .map((b) => ({ exportName: b.exportName, block: b.name, file: relative(projectDir, b.absFile) }))
43
+ .sort((a, b) => a.file.localeCompare(b.file) || a.exportName.localeCompare(b.exportName));
141
44
  }
142
45
  /**
143
46
  * Shortest Block-name path between two Checkpoint tags using `discoverGraph`
@@ -193,270 +96,44 @@ export function findBlockPathDetailed(graph, fromTag, toTag) {
193
96
  return null;
194
97
  }
195
98
  /**
196
- * Same real, confirmed reload-caching bug `auto-explore.ts`'s own copy of
197
- * this function fixes (see its own comment) - `discoverGraph` (used for
198
- * `this.graph`/path-finding) and `loadBlockLibrary` (used for `this.library`/
199
- * the live menu) are two independent importers, each with their own
200
- * duplicate `importModule`, so each needed the same mtime-based cache-bust
201
- * fix separately - fixing only one left the other still serving a session's
202
- * `reloadLibrary()` a stale (or, for a brand-new file only ever discovered
203
- * through THIS path, silently absent) graph.
204
- */
205
- async function importModule(filePath) {
206
- const resolved = resolve(filePath);
207
- const url = new URL(`file://${resolved}`);
208
- const mtimeMs = statSync(resolved).mtimeMs;
209
- url.searchParams.set("t", String(mtimeMs));
210
- return (await import(url.href));
211
- }
212
- function isBlockLike(val) {
213
- if (val === null || typeof val !== "object")
214
- return false;
215
- const obj = val;
216
- if (typeof obj.name !== "string")
217
- return false;
218
- const instruction = obj.instruction;
219
- return instruction !== null && typeof instruction === "object" && typeof instruction?.act === "function";
220
- }
221
- /** Set by `defineNavBlock` (non-enumerable) - see src/core.ts. */
222
- function isNavBlockMarked(val) {
223
- const kind = val.__waygraphKind;
224
- return kind === "nav" || kind === "page";
225
- }
226
- /** Set by `defineAssertBlock` (non-enumerable) - see src/core.ts. */
227
- function isAssertBlockMarked(val) {
228
- return val.__waygraphKind === "assert";
229
- }
230
- /**
231
- * Resolves `typeName` to every literal Checkpoint tag it can mean, within
232
- * one `*.states.ts` file's own source text - `type X = Checkpoint<"Tag">`
233
- * directly, or `type X = A | B | Checkpoint<"C">` (a union of other type
234
- * names and/or inline Checkpoint literals) recursively. A cycle or unknown
235
- * identifier just contributes no tags, rather than throwing - callers treat
236
- * an empty result as "couldn't resolve," not a crash.
237
- */
238
- function resolveCheckpointTags(statesSrc, typeName, seen = new Set()) {
239
- if (seen.has(typeName))
240
- return [];
241
- seen.add(typeName);
242
- const direct = new RegExp(`type\\s+${typeName}\\s*=\\s*Checkpoint<"([^"]+)">`).exec(statesSrc);
243
- if (direct)
244
- return [direct[1]];
245
- const aliased = new RegExp(`type\\s+${typeName}\\s*=\\s*([^;]+);`).exec(statesSrc);
246
- if (!aliased)
247
- return [];
248
- const tags = [];
249
- for (const member of aliased[1].split("|").map((s) => s.trim()).filter(Boolean)) {
250
- const inline = /^Checkpoint<"([^"]+)">$/.exec(member);
251
- if (inline) {
252
- tags.push(inline[1]);
253
- }
254
- else if (/^[A-Za-z_$][\w]*$/.test(member)) {
255
- tags.push(...resolveCheckpointTags(statesSrc, member, seen));
256
- }
257
- }
258
- return tags;
259
- }
260
- /**
261
- * Finds which file `blockFilePath`'s own `import type { ... }` statements
262
- * say `typeName` comes from, resolved to a real path on disk (`.js` ->
263
- * `.ts`, matching this project's own NodeNext import convention). Only
264
- * follows relative imports - `typeName` imported from a package (e.g.
265
- * `waygraph` itself, for `Checkpoint`) has no project file to read.
266
- */
267
- function findTypeSourceFile(blockFilePath, typeName) {
268
- const src = readFileSync(blockFilePath, "utf-8");
269
- const importRe = /import\s+type\s*\{([^}]*)\}\s*from\s*["']([^"']+)["']/g;
270
- let m;
271
- while ((m = importRe.exec(src)) !== null) {
272
- const names = m[1].split(",").map((s) => s.trim());
273
- if (!names.includes(typeName))
274
- continue;
275
- const importPath = m[2];
276
- if (!importPath.startsWith("."))
277
- continue;
278
- const resolved = join(dirname(blockFilePath), importPath.replace(/\.js$/, ".ts"));
279
- if (existsSync(resolved))
280
- return resolved;
281
- }
282
- return null;
283
- }
284
- /** `findTypeSourceFile` + `resolveCheckpointTags`, chained - `[]` on any failure along the way. */
285
- function resolveTypeToTags(blockFilePath, typeName) {
286
- const statesFile = findTypeSourceFile(blockFilePath, typeName);
287
- if (!statesFile)
288
- return [];
289
- return resolveCheckpointTags(readFileSync(statesFile, "utf-8"), typeName);
290
- }
291
- /**
292
- * Resolves one `defineBlock<In, Out>` generic argument, as captured by
293
- * `extractDefineBlockGenerics` - either a plain type identifier (goes
294
- * through `resolveTypeToTags`), an inline `Checkpoint<"Tag">` literal, or
295
- * the documented wildcard forms `Checkpoint<string>`/`Checkpoint<any>` (a
296
- * Block reused across several entry points, e.g. this project's own
297
- * `AddToCartBlock` - reachable from anywhere, same as a NavBlock's own `"*"`).
298
- */
299
- function resolveGenericArg(blockFilePath, arg) {
300
- if (arg === "Checkpoint<string>" || arg === "Checkpoint<any>")
301
- return ["*"];
302
- const inline = /^Checkpoint<"([^"]+)">$/.exec(arg);
303
- if (inline)
304
- return [inline[1]];
305
- return resolveTypeToTags(blockFilePath, arg);
306
- }
307
- /** Every `defineBlock` / `defineEffectBlock` / `defineMemEffectBlock` `<In, Out>` call site. */
308
- function extractDefineBlockGenerics(src) {
309
- // Each argument is either a plain identifier or an inline `Checkpoint<...>`
310
- // (its own angle brackets, so the outer defineX<...> pair alone won't
311
- // balance correctly against a naive greedy match) - captured as a single
312
- // alternation so both shapes come out of the same two capture groups.
313
- // Effect helpers are TypeScript salt over defineBlock - same In/Out edges.
314
- const arg = String.raw `(Checkpoint<[^>]*>|[A-Za-z_$][\w]*)`;
315
- const re = new RegExp(String.raw `define(?:(?:Mem)?Effect|Method|Action)?Block<\s*${arg}\s*,\s*${arg}\s*>`, "g");
316
- // Matches: defineBlock | defineMethodBlock | defineActionBlock | defineEffectBlock |
317
- // defineMemEffectBlock (Nav / NavClick / Page use runtime markers, not this regex.)
318
- const calls = [];
319
- let m;
320
- while ((m = re.exec(src)) !== null) {
321
- calls.push({ in: m[1], out: m[2] });
322
- }
323
- return calls;
324
- }
325
- /**
326
- * Walks every `*.block.ts` file under `projectDir` and builds the app's own
327
- * state graph. Shares the same in-process-import limitation `waygraph
328
- * check` already has: a target project whose own `waygraph`/`playwright`
329
- * are genuinely separate installs (not symlinked into this same
330
- * node_modules resolution) can crash Playwright's own "second copy" guard
331
- * on import - acceptable for an introspection command the same way it
332
- * already is for `check`, unlike `chain`, which spawns a child process
333
- * specifically because it also EXECUTES Blocks, not just imports them.
99
+ * The project's state graph: Checkpoints are nodes, Blocks are edges. Built from the manifest scan, which reads each Block's
100
+ * route at runtime.
334
101
  */
335
102
  export async function discoverGraph(projectDir, opts) {
336
- const select = opts?.blocksSelect;
103
+ const scan = await scanProject(projectDir, { blocksSelect: opts?.blocksSelect, inject: opts?.inject, flows: false });
104
+ return graphFromScan(scan);
105
+ }
106
+ /** The graph of an existing scan. */
107
+ export function graphFromScan(scan) {
337
108
  const nodeTags = new Set();
338
109
  const edges = [];
339
- const skipped = [];
340
- const edgeSeen = new Set();
341
- for (const root of exploreRoots(projectDir, opts?.inject)) {
342
- let files = discoverBlocks(root);
343
- // Glob/bare: drop files early. Regex needs block names — filter per export below.
344
- if (select && select.kind !== "regex") {
345
- files = files.filter((file) => matchBlocksSelect(select, {
346
- relFile: relative(root, file).replace(/\\/g, "/"),
347
- }));
110
+ const seen = new Set();
111
+ for (const b of scan.blocks) {
112
+ if (b.to.length === 0)
113
+ continue;
114
+ // Arrival-only Page hubs register the Checkpoint but are not a way to get there; a deep-linking Page is.
115
+ if (b.kind === "page" && b.block.__waygraphPageDeepLink !== true) {
116
+ for (const to of b.to)
117
+ nodeTags.add(to);
118
+ continue;
348
119
  }
349
- for (const file of files) {
350
- const relFile = injectTaggedFile(projectDir, root, relative(root, file).replace(/\\/g, "/"));
351
- let mod;
352
- try {
353
- mod = await importModule(file);
354
- }
355
- catch (err) {
356
- const msg = err instanceof Error ? err.message : String(err);
357
- // Dual @playwright/test installs fail here - surface instead of empty graph.
358
- if (/second time|playwright/i.test(msg)) {
359
- console.error(`waygraph graph: skip ${relFile}: ${msg.split("\n")[0]}`);
360
- }
361
- continue;
362
- }
363
- const src = readFileSync(file, "utf-8");
364
- // Assumes source order matches export-object iteration order - true for
365
- // this codebase's own convention of one Block per file; a file with
366
- // several regular Blocks in an unusual order is a known edge case, not
367
- // handled specially here.
368
- const calls = extractDefineBlockGenerics(src);
369
- let callIndex = 0;
370
- for (const exported of Object.values(mod)) {
371
- if (!isBlockLike(exported))
372
- continue;
373
- const blockName = exported.name;
374
- if (select &&
375
- !matchBlocksSelect(select, {
376
- relFile: relFile.replace(/\\/g, "/"),
377
- blockName,
378
- })) {
379
- continue;
380
- }
381
- if (isAssertBlockMarked(exported)) {
382
- try {
383
- // Same input-independent resolve() shape Nav/Page Blocks already
384
- // get this shortcut for - defineAssertBlock's own resolve() is
385
- // always `() => checkpoint(options.checkpoint)`, so no <In, Out>
386
- // generic needs to appear in source text for this to be found.
387
- const resolveFn = exported.instruction.resolve;
388
- const resolved = await resolveFn(undefined);
389
- const to = resolved.__state;
390
- nodeTags.add(to);
391
- // Self-loop by construction (defineAssertBlock is self-loop-only).
392
- edges.push({ block: blockName, file: relFile, from: to, to, kind: "action" });
393
- }
394
- catch {
395
- skipped.push({ block: blockName, file: relFile, reason: "assertBlock resolve() threw" });
396
- }
397
- continue;
398
- }
399
- if (isNavBlockMarked(exported)) {
400
- try {
401
- // NavBlock / PageBlock resolve() ignores input - always checkpoint(tag).
402
- const resolveFn = exported.instruction.resolve;
403
- const resolved = await resolveFn(undefined);
404
- const to = resolved.__state;
405
- nodeTags.add(to);
406
- // Arrival-only Page hubs register the Checkpoint node but do not emit
407
- // a Start-here edge (no deep link). Methods own the action edges.
408
- const isPage = exported.__waygraphKind === "page";
409
- const deepLink = !isPage ||
410
- exported.__waygraphPageDeepLink === true;
411
- if (deepLink) {
412
- // `from: [...]` on the Nav = only those Checkpoints; otherwise reachable from anywhere.
413
- const navFrom = exported.__waygraphNavFrom;
414
- for (const from of navFrom ?? ["*"]) {
415
- if (from !== "*")
416
- nodeTags.add(from);
417
- edges.push({ block: blockName, file: relFile, from, to, kind: "nav" });
418
- }
419
- }
420
- }
421
- catch {
422
- skipped.push({ block: blockName, file: relFile, reason: "NavBlock/PageBlock resolve() threw" });
423
- }
424
- continue;
425
- }
426
- const call = calls[callIndex++];
427
- if (!call) {
428
- skipped.push({
429
- block: blockName,
430
- file: relFile,
431
- reason: "no defineBlock/defineMethodBlock/defineEffectBlock<In, Out> generic call found",
432
- });
433
- continue;
434
- }
435
- const fromTags = resolveGenericArg(file, call.in);
436
- const toTags = resolveGenericArg(file, call.out);
437
- if (fromTags.length === 0 || toTags.length === 0) {
438
- const badName = fromTags.length === 0 ? call.in : call.out;
439
- skipped.push({ block: blockName, file: relFile, reason: `couldn't resolve "${badName}" to a Checkpoint tag` });
120
+ const kind = b.kind === "nav" || b.kind === "page" ? "nav" : "action";
121
+ for (const from of b.from) {
122
+ for (const to of b.to) {
123
+ if (from !== "*")
124
+ nodeTags.add(from);
125
+ nodeTags.add(to);
126
+ const key = `${b.name}\0${from}\0${to}`;
127
+ if (seen.has(key))
440
128
  continue;
441
- }
442
- for (const from of fromTags) {
443
- for (const to of toTags) {
444
- if (from !== "*")
445
- nodeTags.add(from);
446
- nodeTags.add(to);
447
- const key = `${blockName}\0${from}\0${to}`;
448
- if (edgeSeen.has(key))
449
- continue;
450
- edgeSeen.add(key);
451
- edges.push({ block: blockName, file: relFile, from, to, kind: "action" });
452
- }
453
- }
129
+ seen.add(key);
130
+ edges.push({ block: b.name, file: b.file, from, to, kind });
454
131
  }
455
132
  }
456
133
  }
457
134
  return {
458
135
  nodes: [...nodeTags].sort().map((checkpoint) => ({ checkpoint })),
459
136
  edges,
460
- skipped,
137
+ skipped: scan.skipped,
461
138
  };
462
139
  }
@@ -13,46 +13,11 @@
13
13
  * Self-contained (no import from cli.ts), same reasoning as graph.ts's own
14
14
  * header comment: cli.ts runs main() unconditionally at module load.
15
15
  */
16
- import { existsSync, readdirSync, statSync } from "node:fs";
16
+ import { existsSync } from "node:fs";
17
17
  import { join, dirname, relative, sep } from "node:path";
18
- import { pathToFileURL } from "node:url";
19
- function walkBlockFiles(dir) {
20
- const results = [];
21
- let entries;
22
- try {
23
- entries = readdirSync(dir, { withFileTypes: true });
24
- }
25
- catch {
26
- return results;
27
- }
28
- for (const entry of entries) {
29
- const full = join(dir, entry.name);
30
- if (entry.isDirectory()) {
31
- if (entry.name === "node_modules" || entry.name === "dist" || entry.name === ".git")
32
- continue;
33
- results.push(...walkBlockFiles(full));
34
- }
35
- else if (/\.block\.ts$/.test(entry.name)) {
36
- results.push(full);
37
- }
38
- }
39
- return results;
40
- }
41
- function isBlockLike(val) {
42
- if (val === null || typeof val !== "object")
43
- return false;
44
- const obj = val;
45
- if (typeof obj.name !== "string")
46
- return false;
47
- const instruction = obj.instruction;
48
- return instruction !== null && typeof instruction === "object" && typeof instruction?.act === "function";
49
- }
50
- async function importModule(filePath) {
51
- const url = pathToFileURL(filePath);
52
- const mtimeMs = statSync(filePath).mtimeMs;
53
- url.searchParams.set("t", String(mtimeMs));
54
- return (await import(url.href));
55
- }
18
+ import { importFresh, isBlockLike, walkDir } from "../manifest/scan.js";
19
+ const walkBlockFiles = (dir) => walkDir(dir, /\.block\.ts$/);
20
+ const importModule = importFresh;
56
21
  /**
57
22
  * `(group)` segments never appear in the real URL (Next.js route-group
58
23
  * convention this whole system is explicitly modeled on) - excluded from
@@ -1,4 +1,4 @@
1
- export type PracticeKind = "wildcard-checkpoint" | "assert-no-type-arg" | "multi-input" | "combined-action" | "empty-verify" | "overcomplex-selector" | "inline-selector-should-use-sel-file";
1
+ export type PracticeKind = "multi-input" | "combined-action" | "empty-verify" | "overcomplex-selector" | "inline-selector-should-use-sel-file";
2
2
  export interface PracticeWarning {
3
3
  kind: PracticeKind;
4
4
  file: string;
@@ -5,31 +5,29 @@
5
5
  */
6
6
  import { readFileSync, readdirSync } from "node:fs";
7
7
  import { dirname, relative } from "node:path";
8
- /** Every define*Block<In, Out> / <Out> generic list - args may themselves be Checkpoint<...>. */
9
- const BLOCK_GENERICS = /\bdefine(?:Method|Effect|MemEffect|Page|Nav|MemNav|NavClick|Action)Block\s*<\s*((?:Checkpoint\s*<[^>]*>|[^,<>])+?)\s*(?:,\s*((?:Checkpoint\s*<[^>]*>|[^,<>])+?)\s*)?>/g;
10
- /**
11
- * A wildcard Out (the Block's result is untyped). A wildcard In is fine - it's the documented
12
- * "reachable from anywhere" form (graph.ts treats it like a NavBlock's "*").
13
- */
14
- function hasWildcardOut(src) {
15
- for (const m of src.matchAll(BLOCK_GENERICS)) {
16
- const out = (m[2] ?? m[1]).trim();
17
- if (/^Checkpoint\s*<\s*string\s*>$/.test(out))
18
- return true;
19
- }
20
- return false;
21
- }
22
- /** defineAssertBlock({ … }) with no explicit Out type — defaults to wildcard. */
23
- const ASSERT_NO_TYPE_ARG = /\bdefineAssertBlock\s*\(\s*\{/;
8
+ import { Node, SyntaxKind } from "ts-morph";
9
+ import { parseSource } from "../manifest/source.js";
24
10
  /** defineAssertBlock, any form - used to scope the empty-verify check below. */
25
11
  const IS_ASSERT_BLOCK = /\bdefineAssertBlock\s*[<(]/;
26
- /**
27
- * define(Method|Effect)Block<In, Out> with two BARE identifier type args
28
- * (never a nested generic like Checkpoint<string> - that's WILDCARD_CHECKPOINT's
29
- * own warning) - lets a real transition (In !== Out) be told apart from a
30
- * self-loop (In === Out, e.g. fill-username) using only source text.
31
- */
32
- const METHOD_EFFECT_GENERIC = /\bdefine(?:Method|Effect)Block\s*<\s*([A-Za-z_$][\w$]*)\s*,\s*([A-Za-z_$][\w$]*)\s*>/;
12
+ /** A Method/Effect's route as written (`from: LoginPage, to: LoggedIn`), from the AST - a transition when they differ. */
13
+ function routeAsWritten(file) {
14
+ const sf = parseSource(file);
15
+ for (const call of sf.getDescendantsOfKind(SyntaxKind.CallExpression)) {
16
+ if (!/^define(Method|Effect)Block$/.test(call.getExpression().getText()))
17
+ continue;
18
+ const options = call.getArguments()[0];
19
+ if (!Node.isObjectLiteralExpression(options))
20
+ continue;
21
+ const text = (name) => {
22
+ const prop = options.getProperty(name);
23
+ return Node.isPropertyAssignment(prop) ? prop.getInitializerOrThrow().getText() : undefined;
24
+ };
25
+ const to = text("to");
26
+ if (to)
27
+ return { from: text("from") ?? "*", to };
28
+ }
29
+ return undefined;
30
+ }
33
31
  /** `verify: []` - a literal empty array, the codegen-stub shape this check exists for. */
34
32
  const EMPTY_VERIFY_ARRAY = /\bverify\s*:\s*\[\s*\]/;
35
33
  /** Any `verify:` key at all, empty or not. */
@@ -86,21 +84,6 @@ export function collectPracticeWarnings(projectDir, walkDir, opts) {
86
84
  const rel = relative(projectDir, file).replace(/\\/g, "/");
87
85
  const src = readFileSync(file, "utf-8");
88
86
  const ignore = ignoredKindsForFile(src);
89
- if (!isIgnored("wildcard-checkpoint", ignore) && hasWildcardOut(src)) {
90
- warnings.push({
91
- kind: "wildcard-checkpoint",
92
- file: rel,
93
- detail: "the Block's output is Checkpoint<string>, so its result is untyped — use a typed Checkpoint from " +
94
- "src/states/ (e.g. defineMethodBlock<LoginPage, LoggedIn>); a wildcard input is fine",
95
- });
96
- }
97
- if (!isIgnored("assert-no-type-arg", ignore) && ASSERT_NO_TYPE_ARG.test(src)) {
98
- warnings.push({
99
- kind: "assert-no-type-arg",
100
- file: rel,
101
- detail: "defineAssertBlock({…}) without an explicit type argument — add defineAssertBlock<YourCheckpoint>({…}) so defineFlow typing stays honest",
102
- });
103
- }
104
87
  const isMethodOrEffect = METHOD_OR_EFFECT_FILE.test(rel) || METHOD_OR_EFFECT_DEFINE.test(src);
105
88
  if (isMethodOrEffect) {
106
89
  const fills = countMatches(src, /\.fill\s*\(/g);
@@ -119,15 +102,15 @@ export function collectPracticeWarnings(projectDir, walkDir, opts) {
119
102
  detail: "Method/Effect act() mixes .fill() and .click() — fill and submit must be separate Blocks (see examples/saucedemo login split)",
120
103
  });
121
104
  }
122
- const genericMatch = METHOD_EFFECT_GENERIC.exec(src);
123
- const isTransition = !!genericMatch && genericMatch[1] !== genericMatch[2];
105
+ const route = routeAsWritten(file);
106
+ const isTransition = !!route && route.from !== route.to;
124
107
  if (isTransition &&
125
108
  !isIgnored("empty-verify", ignore) &&
126
109
  (!HAS_VERIFY_KEY.test(src) || EMPTY_VERIFY_ARRAY.test(src))) {
127
110
  warnings.push({
128
111
  kind: "empty-verify",
129
112
  file: rel,
130
- detail: `transition Block (${genericMatch[1]} → ${genericMatch[2]}) has no verify checks — resolve() moving ` +
113
+ detail: `transition Block (${route.from} → ${route.to}) has no verify checks — resolve() moving ` +
131
114
  "to a new Checkpoint is never confirmed by anything; add a Trait (or defineAssertBlock right after it), " +
132
115
  "or opt out explicitly with // waygraph-ignore: empty-verify if that's intentional",
133
116
  });
@@ -173,10 +156,6 @@ export function collectPracticeWarnings(projectDir, walkDir, opts) {
173
156
  }
174
157
  export function practiceKindLabel(kind) {
175
158
  switch (kind) {
176
- case "wildcard-checkpoint":
177
- return "wildcard Checkpoint<string>";
178
- case "assert-no-type-arg":
179
- return "assert block missing type arg";
180
159
  case "multi-input":
181
160
  return "multiple inputs in one Block";
182
161
  case "combined-action":
@@ -0,0 +1,23 @@
1
+ import { parseArgs } from "node:util";
2
+ export interface OptionSpec {
3
+ type: "boolean" | "string";
4
+ multiple?: boolean;
5
+ /** How the value reads in the help: `<url>`, `N`. */
6
+ value?: string;
7
+ help: string;
8
+ }
9
+ export type OptionTable = Readonly<Record<string, OptionSpec>>;
10
+ /** What a table parses to: a boolean, a string, or (multiple) a list, per flag; absent when not given. */
11
+ export type ParsedOptions<T extends OptionTable> = {
12
+ [K in keyof T]?: T[K]["type"] extends "boolean" ? boolean : T[K] extends {
13
+ multiple: true;
14
+ } ? string[] : string;
15
+ };
16
+ export interface ParsedCommand<T extends OptionTable> {
17
+ values: ParsedOptions<T>;
18
+ positionals: string[];
19
+ tokens: ReturnType<typeof parseArgs>["tokens"] & {};
20
+ }
21
+ export declare function parseCommand<T extends OptionTable>(command: string, table: T, argv: string[]): ParsedCommand<T>;
22
+ /** The table as aligned help lines (`--name <value> help`). */
23
+ export declare function helpLines(table: OptionTable, indent?: number): string;