waygraph 0.15.51 → 0.15.52

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 (130) hide show
  1. package/dist/analysis/graph.d.ts +1 -1
  2. package/dist/analysis/graph.js +10 -15
  3. package/dist/analysis/practices-check.d.ts +0 -1
  4. package/dist/analysis/practices-check.js +0 -13
  5. package/dist/auto-session/session.d.ts +1 -1
  6. package/dist/auto-session/session.js +13 -8
  7. package/dist/blocks-select.d.ts +7 -4
  8. package/dist/blocks-select.js +0 -14
  9. package/dist/browser.d.ts +27 -0
  10. package/dist/browser.js +62 -0
  11. package/dist/cli/run-chain.js +4 -0
  12. package/dist/cli/usage.js +14 -1
  13. package/dist/cli.js +10 -1
  14. package/dist/commands/agent-dive-scaffold.d.ts +5 -0
  15. package/dist/commands/agent-dive-scaffold.js +7 -0
  16. package/dist/commands/extensions.d.ts +1 -0
  17. package/dist/commands/extensions.js +22 -0
  18. package/dist/commands/init.js +42 -4
  19. package/dist/commands/test.js +16 -2
  20. package/dist/commands/try.js +2 -1
  21. package/dist/commands/upgrade.d.ts +6 -0
  22. package/dist/commands/upgrade.js +107 -0
  23. package/dist/config.d.ts +47 -3
  24. package/dist/config.js +45 -12
  25. package/dist/core/block.d.ts +12 -0
  26. package/dist/core/block.js +36 -0
  27. package/dist/core/blocks/nav.d.ts +11 -0
  28. package/dist/core/blocks/nav.js +8 -0
  29. package/dist/core/config.d.ts +5 -0
  30. package/dist/core/engine.d.ts +17 -16
  31. package/dist/core/engine.js +3 -3
  32. package/dist/core/flow.d.ts +17 -0
  33. package/dist/core/flow.js +44 -21
  34. package/dist/core/map-builder.d.ts +3 -3
  35. package/dist/core/map-builder.js +3 -3
  36. package/dist/env-file.d.ts +7 -7
  37. package/dist/env-file.js +29 -16
  38. package/dist/extensions.d.ts +21 -0
  39. package/dist/extensions.js +178 -0
  40. package/dist/index.d.ts +6 -4
  41. package/dist/index.js +3 -2
  42. package/dist/pilot-overlay/overlay-fixtures.d.ts +0 -7
  43. package/dist/pilot-overlay/overlay-fixtures.js +0 -45
  44. package/dist/playwright-config.d.ts +4 -0
  45. package/dist/playwright-config.js +15 -0
  46. package/dist/playwright.config.d.ts +2 -0
  47. package/dist/playwright.config.js +6 -0
  48. package/dist/runner/demo-log.js +1 -7
  49. package/dist/runner/inpage/core.d.ts +1 -1
  50. package/dist/runner/inpage/core.js +8 -7
  51. package/dist/runner/main.js +18 -10
  52. package/dist/runner/rings.js +0 -49
  53. package/dist/session/auto-explore-run.js +9 -5
  54. package/dist/session/auto-explore.js +6 -4
  55. package/dist/session/step-overlay.js +3 -1
  56. package/dist/traverse/run.js +3 -1
  57. package/dist/ui/components/ring.js +1 -0
  58. package/dist/ui/overlay.css +1 -0
  59. package/dist/ui/shadow.d.ts +1 -3
  60. package/dist/ui/shadow.js +0 -4
  61. package/dist/ui/tokens.d.ts +0 -11
  62. package/dist/ui/tokens.js +0 -5
  63. package/dist/video-dir.d.ts +8 -0
  64. package/dist/video-dir.js +60 -0
  65. package/dist/webserver.js +5 -1
  66. package/package.json +1 -1
  67. package/templates/scaffold/README.md +4 -2
  68. package/templates/scaffold/STRUCTURE.md +5 -2
  69. package/templates/scaffold/config/waygraph.config.ts +26 -0
  70. package/templates/scaffold/package.json +1 -1
  71. package/templates/scaffold/src/flows/README.md +5 -5
  72. package/templates/scaffold/src/flows/example.flow.ts +31 -17
  73. package/templates/scaffold/src/flows/hoppscotch-auth.flow.ts +35 -0
  74. package/templates/scaffold/src/flows/hoppscotch-get.flow.ts +23 -0
  75. package/templates/scaffold/src/flows/hoppscotch-post.flow.ts +33 -0
  76. package/templates/scaffold/src/flows/mail-verify.flow.ts +36 -75
  77. package/templates/scaffold/src/flows/shop.flow.ts +41 -65
  78. package/templates/scaffold/src/map/(app_base)/docs/_nav.block.ts +0 -9
  79. package/templates/scaffold/src/map/(app_base)/docs/_page.block.ts +0 -5
  80. package/templates/scaffold/src/map/(app_base)/docs/_sel.ts +1 -1
  81. package/templates/scaffold/src/map/(app_base)/home/_methods/add-item.effect.block.ts +3 -19
  82. package/templates/scaffold/src/map/(app_base)/home/_methods/assert-hello.method.block.ts +2 -25
  83. package/templates/scaffold/src/map/(app_base)/home/_methods/assert-item-added.method.block.ts +2 -19
  84. package/templates/scaffold/src/map/(app_base)/home/_methods/clear-cart.method.block.ts +1 -17
  85. package/templates/scaffold/src/map/(app_base)/home/_methods/remove-item.effect.block.ts +1 -10
  86. package/templates/scaffold/src/map/(app_base)/home/_nav.block.ts +1 -12
  87. package/templates/scaffold/src/map/(app_base)/home/_page.block.ts +0 -9
  88. package/templates/scaffold/src/map/(app_base)/home/_sel.ts +3 -1
  89. package/templates/scaffold/src/map/(app_base)/home/nav-verification-link.block.ts +1 -23
  90. package/templates/scaffold/src/map/(external)/hoppscotch/_methods/assert-response-body.method.block.ts +21 -0
  91. package/templates/scaffold/src/map/(external)/hoppscotch/_methods/assert-response-header.method.block.ts +19 -0
  92. package/templates/scaffold/src/map/(external)/hoppscotch/_methods/assert-status.method.block.ts +20 -0
  93. package/templates/scaffold/src/map/(external)/hoppscotch/_methods/pick-extension-interceptor.method.block.ts +18 -0
  94. package/templates/scaffold/src/map/(external)/hoppscotch/_methods/read-response-body.method.block.ts +21 -0
  95. package/templates/scaffold/src/map/(external)/hoppscotch/_methods/read-response-headers.method.block.ts +21 -0
  96. package/templates/scaffold/src/map/(external)/hoppscotch/_methods/send-request.method.block.ts +15 -0
  97. package/templates/scaffold/src/map/(external)/hoppscotch/_methods/set-bearer-token.method.block.ts +20 -0
  98. package/templates/scaffold/src/map/(external)/hoppscotch/_methods/set-headers.method.block.ts +23 -0
  99. package/templates/scaffold/src/map/(external)/hoppscotch/_methods/set-json-body.method.block.ts +36 -0
  100. package/templates/scaffold/src/map/(external)/hoppscotch/_methods/set-method.method.block.ts +17 -0
  101. package/templates/scaffold/src/map/(external)/hoppscotch/_methods/set-query-params.method.block.ts +22 -0
  102. package/templates/scaffold/src/map/(external)/hoppscotch/_methods/set-url.method.block.ts +18 -0
  103. package/templates/scaffold/src/map/(external)/hoppscotch/_nav.block.ts +11 -0
  104. package/templates/scaffold/src/map/(external)/hoppscotch/_page.block.ts +36 -0
  105. package/templates/scaffold/src/map/(external)/hoppscotch/_sel.ts +27 -0
  106. package/templates/scaffold/src/map/(external)/hoppscotch/settings/_nav.block.ts +10 -0
  107. package/templates/scaffold/src/map/(external)/mailpit/_methods/assert-email-content.method.block.ts +2 -27
  108. package/templates/scaffold/src/map/(external)/mailpit/_methods/assert-email-received.method.block.ts +2 -21
  109. package/templates/scaffold/src/map/(external)/mailpit/_methods/extract-email-link.method.block.ts +1 -19
  110. package/templates/scaffold/src/map/(external)/mailpit/_methods/open-message.method.block.ts +1 -11
  111. package/templates/scaffold/src/map/(external)/mailpit/_nav.block.ts +1 -9
  112. package/templates/scaffold/src/map/(external)/mailpit/_page.block.ts +0 -11
  113. package/templates/scaffold/src/states/demo.mem-keys.ts +20 -19
  114. package/templates/scaffold/src/states/demo.mem-stubs.ts +4 -0
  115. package/templates/scaffold/src/states/demo.states.ts +5 -1
  116. package/templates/scaffold/tests/example.spec.ts +2 -3
  117. package/templates/scaffold/tests/hoppscotch.spec.ts +97 -0
  118. package/templates/scaffold/tests/mail-verify.spec.ts +2 -11
  119. package/templates/scaffold/tsconfig.json +1 -1
  120. package/templates/skills/waygraph-convention.skill.md +32 -3
  121. package/templates/skills/waygraph-pilot.skill.md +4 -5
  122. package/dist/browser-path.d.ts +0 -5
  123. package/dist/browser-path.js +0 -18
  124. package/dist/runner/overlay-present.d.ts +0 -8
  125. package/dist/runner/overlay-present.js +0 -57
  126. package/dist/ui/components/banner.d.ts +0 -2
  127. package/dist/ui/components/banner.js +0 -10
  128. package/dist/ui/components/cursor.d.ts +0 -2
  129. package/dist/ui/components/cursor.js +0 -19
  130. package/templates/scaffold/playwright.config.ts +0 -12
@@ -0,0 +1,97 @@
1
+ import { test, expect } from "@playwright/test";
2
+ import { createServer, type Server } from "node:http";
3
+ import { MemPage, checkpoint } from "waygraph";
4
+ import config from "../config/waygraph.config.js";
5
+ import { hoppscotchGetFlow } from "../src/flows/hoppscotch-get.flow.js";
6
+ import { hoppscotchAuthFlow } from "../src/flows/hoppscotch-auth.flow.js";
7
+ import { hoppscotchPostFlow } from "../src/flows/hoppscotch-post.flow.js";
8
+ import {
9
+ ExpectedResponseHeader,
10
+ ExpectedResponseText,
11
+ ExpectedStatus,
12
+ RequestBearerToken,
13
+ RequestBody,
14
+ RequestHeaders,
15
+ RequestMethod,
16
+ RequestParams,
17
+ RequestUrl,
18
+ } from "../src/states/demo.mem-keys.js";
19
+
20
+ // The API under test: no CORS headers, so only the extension can reach it from hoppscotch.io.
21
+ let server: Server;
22
+ let apiUrl: string;
23
+
24
+ test.beforeAll(async () => {
25
+ server = createServer((req, res) => {
26
+ let body = "";
27
+ req.on("data", (chunk) => (body += chunk));
28
+ req.on("end", () => {
29
+ res.statusCode = req.method === "POST" ? 201 : 200;
30
+ res.setHeader("content-type", "application/json");
31
+ res.setHeader("x-request-id", "req-42");
32
+ res.end(JSON.stringify({ method: req.method, url: req.url, token: req.headers["x-token"], auth: req.headers.authorization, body }));
33
+ });
34
+ });
35
+ await new Promise<void>((resolve) => server.listen(0, "127.0.0.1", resolve));
36
+ apiUrl = `http://127.0.0.1:${(server.address() as { port: number }).port}/items`;
37
+ });
38
+
39
+ test.afterAll(() => server.close());
40
+
41
+ test.skip(!config.extensions?.includes("hoppscotch"), 'add extensions: ["hoppscotch"] to config/waygraph.config.ts to run these');
42
+ test.setTimeout(120_000);
43
+
44
+ test("GET returns 200", async () => {
45
+ const mem = new MemPage();
46
+ mem.set(RequestUrl, apiUrl);
47
+ mem.set(ExpectedStatus, 200);
48
+ expect(await hoppscotchGetFlow.run(mem, {})).toEqual(checkpoint("HoppscotchRest"));
49
+ });
50
+
51
+ test("POST sends the header and JSON body, returns 201", async () => {
52
+ const mem = new MemPage();
53
+ mem.set(RequestMethod, "POST");
54
+ mem.set(RequestUrl, apiUrl);
55
+ mem.set(RequestHeaders, { "x-token": "abc123" });
56
+ mem.set(RequestBody, '{"name":"waygraph"}');
57
+ mem.set(ExpectedStatus, 201);
58
+ mem.set(ExpectedResponseText, '"token":"abc123"');
59
+ expect(await hoppscotchPostFlow.run(mem, {})).toEqual(checkpoint("HoppscotchRest"));
60
+ });
61
+
62
+ test("a wrong expected status fails the flow, naming assert-status", async () => {
63
+ const mem = new MemPage();
64
+ mem.set(RequestUrl, apiUrl);
65
+ mem.set(ExpectedStatus, 404);
66
+ await expect(hoppscotchGetFlow.run(mem, {})).rejects.toThrow(/assert-status/);
67
+ });
68
+
69
+ test("a response body without the expected text fails the flow, naming assert-response-body", async () => {
70
+ const mem = new MemPage();
71
+ mem.set(RequestMethod, "POST");
72
+ mem.set(RequestUrl, apiUrl);
73
+ mem.set(RequestHeaders, { "x-token": "abc123" });
74
+ mem.set(RequestBody, '{"name":"waygraph"}');
75
+ mem.set(ExpectedStatus, 201);
76
+ mem.set(ExpectedResponseText, '"token":"nope"');
77
+ await expect(hoppscotchPostFlow.run(mem, {})).rejects.toThrow(/assert-response-body/);
78
+ });
79
+
80
+ const authMem = (headerValue: string): MemPage => {
81
+ const mem = new MemPage();
82
+ mem.set(RequestUrl, apiUrl);
83
+ mem.set(RequestParams, { q: "waygraph" });
84
+ mem.set(RequestBearerToken, "tok-9");
85
+ mem.set(ExpectedStatus, 200);
86
+ mem.set(ExpectedResponseText, '"url":"/items?q=waygraph","auth":"Bearer tok-9"');
87
+ mem.set(ExpectedResponseHeader({ name: "X-Request-Id", value: headerValue }));
88
+ return mem;
89
+ };
90
+
91
+ test("query params and a bearer token reach the API; a response header is checked", async () => {
92
+ expect(await hoppscotchAuthFlow.run(authMem("req-42"), {})).toEqual(checkpoint("HoppscotchRest"));
93
+ });
94
+
95
+ test("a wrong response header value fails the flow, naming assert-response-header", async () => {
96
+ await expect(hoppscotchAuthFlow.run(authMem("other"), {})).rejects.toThrow(/assert-response-header/);
97
+ });
@@ -6,17 +6,8 @@ import { mailVerifyFlow } from "../src/flows/mail-verify.flow.js";
6
6
  import { ExpectedRecipient, ExpectedLinkPattern, ExpectedEmailContent } from "../src/states/demo.mem-keys.js";
7
7
  import { HOME_URL } from "../src/map/(app_base)/home/_sel.js";
8
8
 
9
- /**
10
- * This scaffold has no real backend, so these tests play the role of "the
11
- * app sent a verification email" themselves: spin up a real, throwaway
12
- * Mailpit container, send a real SMTP message, then run mailVerifyFlow for
13
- * real - a real cross-origin browser hop into Mailpit's own web UI and
14
- * back, no mail-catcher REST API anywhere. Covers the happy path, both
15
- * failure paths its QA-facing asserts exist for (no email arrived, wrong
16
- * content), and - the actual point of making the mail-reading Blocks
17
- * mem-driven - a second, entirely different email scenario running through
18
- * the exact same four Blocks with zero new code.
19
- */
9
+ // Plays "the app sent a verification email": starts a throwaway Mailpit container, sends a real SMTP message,
10
+ // then runs mailVerifyFlow against it, including the no-email and wrong-content failure paths.
20
11
 
21
12
  function runMailpit(): { containerId: string; smtpPort: number; httpPort: number } {
22
13
  const run = spawnSync("docker", ["run", "--rm", "-d", "-p", "0:1025", "-p", "0:8025", "axllent/mailpit"], {
@@ -10,5 +10,5 @@
10
10
  "skipLibCheck": true,
11
11
  "forceConsistentCasingInFileNames": true
12
12
  },
13
- "include": ["src/**/*.ts", "tests/**/*.ts", "scripts/**/*.ts"]
13
+ "include": ["config/**/*.ts", "src/**/*.ts", "tests/**/*.ts", "scripts/**/*.ts"]
14
14
  }
@@ -17,6 +17,9 @@ against a live site, use `--skill-pilot-blind`.
17
17
  2. **Navigation only inside Nav.** `page.goto` / NavBlock `click` live in
18
18
  `defineNavBlock` / `defineNavClickBlock` only. Method/Effect `act` uses ActionPage
19
19
  (no goto) even when the app changes URL as a side effect of a button click.
20
+ A Nav for a page that only exists after something else (every in-app page after sign-in)
21
+ declares `from: [...]` with the Checkpoints it is valid from (a `SIGNED_IN` list in
22
+ `src/states/`); without it, routing jumps there from anywhere, skipping sign-in.
20
23
  3. **Selectors in `*Sel`, never inline.** DOM strings live in a `*Sel` next to the page - `_sel.ts`
21
24
  in the Map layout (one per page folder, next to `_nav`/`_page`/`_methods`), `<name>.sel.ts` in a
22
25
  freeform layout (one per concern) - never a fresh file-naming convention per project (`_sel.ts`,
@@ -39,7 +42,7 @@ against a live site, use `--skill-pilot-blind`.
39
42
  5. **`requires` = externally supplied.** A key an earlier Block in the same chain produces
40
43
  is never listed under `requires` - preflight checks the whole chain up front. For a
41
44
  genuinely arbitrary key (a username, an email) that a demo/dev run shouldn't need
42
- hand-supplied every time, `registerMemStub(key, fake)` + `withMemStub(flow)` (or
45
+ hand-supplied every time, `registerMemStub(key, fake)` + `memStub: true` on the flow (or
43
46
  `--mem-stub`) fills it from a registry instead - a key with no registration still fails
44
47
  preflight exactly as before, so this narrows what needs real input, never removes the guard.
45
48
  6. **Keep Checkpoints typed.** Block helpers take concrete Checkpoint types from `src/states/`
@@ -63,6 +66,33 @@ against a live site, use `--skill-pilot-blind`.
63
66
  when a *different* Block right after it in the `.flow.ts` is what actually confirms the
64
67
  transition (e.g. an `AssertXBlock`) - `// waygraph-ignore: empty-verify`.
65
68
 
69
+ ## Flows, stubs and config (the scaffold's shape)
70
+
71
+ - **Build flows with `map()`** (`.start().gotoPage(Nav).method(B).assert(A).end({ ... })`; `.gotoExternal` for another origin),
72
+ not a raw `defineFlow([start, ...])` array. Flow settings go in `.end`'s options:
73
+ `.end({ title: "Shop", memStub: true, sessionReset: true })`. Never `withMemStub(withTitle(withSessionReset(...)))`.
74
+ (`defineFlow(blocks, options)` takes the same options.)
75
+ - **Blocks carry no stubs; the flow does.** Demo highlights are ctx stubs chained on the Block where the flow uses it:
76
+ `AddItemBlock.stubAfter((ctx) => { ctx.ring("cart", { selector: DemoSel.cartCount, label: "AC · item in cart" }); })`.
77
+ Not a static `withHighlightFixtures({ "add-item": { stubAfter: {...} } })` map, and not an inline
78
+ `instruction: { stubAfter() {} }`. A Block used twice gets one `const AddShown = AddItemBlock.stubAfter(...)`.
79
+ - **Reading a value into `mem` happens in `act`** (`mem.set(Key, value)`), like Mailpit's `extract-email-link`.
80
+ `observe` is only for a Block that branches (it feeds `resolve`); an empty `act(){}` plus an `observe` that
81
+ writes `mem` is a misuse.
82
+ - **Per-environment values** (a different `baseUrl` for staging) come from `.env` files read in the config function:
83
+ `defineConfig(({ env }) => ({ baseUrl: env.BASE_URL }))`; `--env staging` loads `.env.staging`. Never edit the config to switch.
84
+ - **A browser dialog (`confirm`, `beforeunload`) is answered with `withDialog(block, { accept, into })`**, not inside the
85
+ Block's `act`; the click Block stays a plain click.
86
+ - **Project settings live in `config/waygraph.config.ts`** (`defineConfig({ baseUrl, testDir, webServer,
87
+ extensions, playwright: {...} })`). Flows import it and build the Engine from it (`new Engine(config)`); a project needs no
88
+ `playwright.config.ts` - `waygraph test` builds one from it. A leftover `playwright.config.*` is deprecated.
89
+ - **Another origin the test needs is a Map external** under `src/map/(external)/<tool>/`. For REST API
90
+ tests, `(external)/hoppscotch` (list `extensions: ["hoppscotch"]` in the config) drives hoppscotch.io's client
91
+ with the extension, so requests skip CORS: `set-method`, `set-url`, `set-headers`, `set-json-body`,
92
+ `send-request`, `assert-status`, `read-response-body`, `assert-response-body`.
93
+ - **Updating an older project:** `npm install waygraph@latest`, then `waygraph upgrade` (dry run) to see new
94
+ and differing scaffold files; copy the paths you want with `--apply`.
95
+
66
96
  ## Block kinds (file convention)
67
97
 
68
98
  | Kind | File | Helper | `page.goto`? |
@@ -113,8 +143,7 @@ src/map/
113
143
  - `(group)` parentheses and leading-underscore segments (`_methods/`, `_page…`) are
114
144
  **not** URL segments. `waygraph map` excludes them when checking folder-vs-URL.
115
145
  - A bare non-underscore folder always means a real child Checkpoint/URL segment.
116
- - Prefer `map()` over a hand-assembled `defineFlow([start, ...])` when wiring Map Blocks -
117
- it rejects Blocks that didn't come from a real factory (no silent teleporting).
146
+ - `map()` rejects Blocks that didn't come from a real factory (no silent teleporting).
118
147
 
119
148
  Mail / external tools: under `*-external/<tool>/` or `map/(external)/<tool>/`, never under
120
149
  the site's `*-web/` tree. Browser-driven (DOM / iframe Traits), not the catcher's REST API.
@@ -104,13 +104,12 @@ thing that differs from demo is *who* triggers the paint:
104
104
 
105
105
  | Mode | Who paints | How |
106
106
  |------|------------|-----|
107
- | `waygraph demo` | Engine, automatically | Block `stubBefore` / `stubAfter` / `withHighlightFixtures` run each step |
107
+ | `waygraph demo` | Engine, automatically | ctx stubs chained in the flow run each step |
108
108
  | Pilot / `auto --detach` | **You (the agent)** | `waygraph auto highlight <sessionId> '<json>'` before (or between) sends |
109
109
 
110
- Block-authored `stubBefore` / `withHighlightFixtures` still exist on Blocks in Pilot —
111
- they show up in `auto trace` as metadata — but they do **not** auto-draw. You re-express
112
- the same intent with `auto highlight` (copy selectors/labels from the Block stubs or from
113
- `auto dom`). Paint, then `auto send` the real Block. Clear when done.
110
+ The ctx stubs a flow chains onto Blocks show up in Pilot's `auto trace` as metadata, but they do **not**
111
+ auto-draw. You re-express the same intent with `auto highlight` (copy selectors/labels from the flow's stubs or
112
+ from `auto dom`). Paint, then `auto send` the real Block. Clear when done.
114
113
 
115
114
  ```
116
115
  # Headful watch session (rings visible to a human audience):
@@ -1,5 +0,0 @@
1
- /**
2
- * CHROME_PATH / CHROMIUM_PATH, if set and the file exists. A stale path (browser uninstalled)
3
- * falls back to Playwright's bundled Chromium with a one-time warning instead of failing the run.
4
- */
5
- export declare function chromiumExecutablePath(): string | undefined;
@@ -1,18 +0,0 @@
1
- import { existsSync } from "node:fs";
2
- let warned = false;
3
- /**
4
- * CHROME_PATH / CHROMIUM_PATH, if set and the file exists. A stale path (browser uninstalled)
5
- * falls back to Playwright's bundled Chromium with a one-time warning instead of failing the run.
6
- */
7
- export function chromiumExecutablePath() {
8
- const path = process.env.CHROME_PATH || process.env.CHROMIUM_PATH;
9
- if (!path)
10
- return undefined;
11
- if (existsSync(path))
12
- return path;
13
- if (!warned) {
14
- warned = true;
15
- console.error(`waygraph: CHROME_PATH/CHROMIUM_PATH "${path}" does not exist - using Playwright's bundled Chromium`);
16
- }
17
- return undefined;
18
- }
@@ -1,8 +0,0 @@
1
- import type { Page } from "@playwright/test";
2
- import type { StubPhaseResult } from "../highlights/types.js";
3
-
4
- export interface SessionOverlay {
5
- present(tag: string, phase: Partial<StubPhaseResult>): Promise<void>;
6
- restore(): Promise<void>;
7
- }
8
- export function createSessionOverlay(page: Page, surface: string): SessionOverlay;
@@ -1,57 +0,0 @@
1
- // Presents a resolved stub phase ("waygraph overlay fixtures": ctx.todos / device / title / banner ...) on a LIVE page
2
- // for the session surfaces (auto / browser / pilot). Same OverlayStage + same in-page installers + same verbose log
3
- // lines as `waygraph demo`, so an overlay fixture behaves identically on every surface. Rings are painted separately
4
- // (pilot holds them; demo cycles them) - that is the only intended difference.
5
- import { installOverlay } from "./overlay-install.js";
6
- import { createOverlayStage } from "./overlay-stage.js";
7
- import { demoLog, logStubPhaseFixtures, logTodoDockFull, setDemoLogSurface, summarizeDevice } from "./demo-log.js";
8
- import { logBannerDom, probeBanner } from "./banner-log.js";
9
- import { probeTodoDocksOnPage } from "./todo-dock.js";
10
-
11
- export function createSessionOverlay(page, surface) {
12
- setDemoLogSurface(surface);
13
- const stage = createOverlayStage(page, { todoDockRef: { current: undefined }, deviceRef: { current: undefined } });
14
- let title = undefined;
15
- let painted = false;
16
-
17
- const paintChrome = async (phaseParallel) => {
18
- await installOverlay(page, title, stage.state.lastBannerUi);
19
- await stage.syncAllTodoDocks({ parallel: !!phaseParallel });
20
- };
21
-
22
- return {
23
- stage,
24
- /** Apply one phase (tag = before | after | error | highlight) and log the resulting overlay state. */
25
- async present(tag, phase) {
26
- setDemoLogSurface(surface);
27
- logStubPhaseFixtures(tag, phase);
28
- await stage.pushTodoDockUi(phase.todoDockUi);
29
- const { appliedTodo, appliedDevice } = await stage.applyPhase(phase, { reapplyDeviceOnKeep: true });
30
- if (phase.title && String(phase.title).trim()) title = String(phase.title).trim();
31
- const wantsChrome = !!(title || stage.state.lastTodoDock || phase.todoSync === "set");
32
- if (wantsChrome) {
33
- painted = true;
34
- await paintChrome(phase.todoParallel);
35
- }
36
- logTodoDockFull(stage.state.lastTodoDock, " " + tag);
37
- demoLog(" " + tag + " device=" + summarizeDevice(stage.state.lastDevice) + " deviceSync=" + appliedDevice.sync);
38
- demoLog(" " + tag + " todoSync=" + appliedTodo.sync);
39
- const docks = await probeTodoDocksOnPage(page);
40
- if (!docks.length && stage.state.lastTodoDock && appliedTodo.sync !== "clear") {
41
- demoLog(" WARN " + tag + ": todos authored but dock-dom empty (not painted?)");
42
- }
43
- for (const d of docks) {
44
- demoLog(
45
- " " + tag + " dock-dom " + d.key + "@" + d.pos + " " + d.left + "," + d.top + " " + d.w + "x" + d.h +
46
- (d.onScreen ? "" : " OFFSCREEN") + " n=" + d.n + (d.current ? ' cur="' + d.current + '"' : ""),
47
- );
48
- }
49
- if (title || painted) logBannerDom(tag, await probeBanner(page));
50
- },
51
- /** A navigation wipes the overlay DOM: rebuild what was authored (same job as the demo's post-navigation restore). */
52
- async restore() {
53
- if (!painted) return;
54
- await paintChrome(false);
55
- },
56
- };
57
- }
@@ -1,2 +0,0 @@
1
- /** Top-left demo banner (`#wg-banner`). */
2
- export declare function bannerCss(): string;
@@ -1,10 +0,0 @@
1
- import { ACCENT_SOFT, SURFACE } from "../tokens.js";
2
- /** Top-left demo banner (`#wg-banner`). */
3
- export function bannerCss() {
4
- return ("#wg-banner{position:fixed;z-index:2147483647;top:14px;left:14px;" +
5
- `background:${SURFACE};color:#fff;border-radius:12px;padding:10px 16px;` +
6
- "font:14px/1.4 system-ui,sans-serif;box-shadow:0 8px 20px rgba(0,0,0,.3);" +
7
- "border:1px solid rgba(124,58,237,.4);}" +
8
- `#wg-banner .wg-banner-tag{display:block;font-size:10px;font-weight:700;color:${ACCENT_SOFT};` +
9
- "letter-spacing:.05em;text-transform:uppercase;margin-bottom:2px;}");
10
- }
@@ -1,2 +0,0 @@
1
- /** Travelling mouse cursor + click ripple (`#wg-cursor`, `#wg-click-pulse`). */
2
- export declare function cursorCss(): string;
@@ -1,19 +0,0 @@
1
- import { TONES } from "../tokens.js";
2
- /** Travelling mouse cursor + click ripple (`#wg-cursor`, `#wg-click-pulse`). */
3
- export function cursorCss() {
4
- const p = TONES.planned;
5
- const pulseTones = ["auto", "info", "warning", "danger", "success"]
6
- .map((n) => `#wg-click-pulse[data-tone=${n}]{border-color:${TONES[n].ring};background:${TONES[n].pulse};}`)
7
- .join("");
8
- return ("#wg-cursor{position:fixed;z-index:2147483647;width:24px;height:24px;pointer-events:none;" +
9
- "left:0;top:0;opacity:0;margin:0;" +
10
- // Travel time is JS-driven via --wg-cursor-ms (a hardcoded duration would make speed a no-op).
11
- "transition:transform var(--wg-cursor-ms,600ms) cubic-bezier(.22,1,.36,1),opacity .2s ease;" +
12
- "filter:drop-shadow(0 2px 4px rgba(12,12,26,.4));}" +
13
- "#wg-click-pulse{position:fixed;z-index:2147483647;width:14px;height:14px;" +
14
- "margin-left:-7px;margin-top:-7px;border-radius:50%;pointer-events:none;opacity:0;" +
15
- `border:2px solid ${p.ring};background:${p.pulse};}` +
16
- pulseTones +
17
- "#wg-click-pulse.wg-pulse{animation:wg-pulse .5s ease-out;}" +
18
- "@keyframes wg-pulse{0%{opacity:.9;transform:scale(.4);}100%{opacity:0;transform:scale(2.4);}}");
19
- }
@@ -1,12 +0,0 @@
1
- import { defineConfig } from "@playwright/test";
2
-
3
- export default defineConfig({
4
- testDir: "./tests",
5
- fullyParallel: true,
6
- reporter: [["list"], ["html", { open: "never" }]],
7
- use: {
8
- // Demo pages open via file:// - no server. Filled in by `waygraph init`.
9
- baseURL: "__APP_BASE_URL__",
10
- trace: "retain-on-failure",
11
- },
12
- });