@webhands/core 0.1.0 → 1.0.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 (49) hide show
  1. package/LICENSE +661 -0
  2. package/dist/cookies-export.d.ts +5 -5
  3. package/dist/cookies-export.d.ts.map +1 -1
  4. package/dist/cookies-export.js +4 -4
  5. package/dist/hand-host.d.ts +217 -0
  6. package/dist/hand-host.d.ts.map +1 -0
  7. package/dist/hand-host.js +351 -0
  8. package/dist/hand-host.js.map +1 -0
  9. package/dist/hand-loading.d.ts +128 -0
  10. package/dist/hand-loading.d.ts.map +1 -0
  11. package/dist/hand-loading.js +143 -0
  12. package/dist/hand-loading.js.map +1 -0
  13. package/dist/index.d.ts +4 -2
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +2 -1
  16. package/dist/index.js.map +1 -1
  17. package/dist/playwright-attach-transport.d.ts +9 -0
  18. package/dist/playwright-attach-transport.d.ts.map +1 -1
  19. package/dist/playwright-attach-transport.js +53 -91
  20. package/dist/playwright-attach-transport.js.map +1 -1
  21. package/dist/playwright-launch-transport.d.ts +7 -62
  22. package/dist/playwright-launch-transport.d.ts.map +1 -1
  23. package/dist/playwright-launch-transport.js +51 -204
  24. package/dist/playwright-launch-transport.js.map +1 -1
  25. package/dist/remote-session.d.ts +12 -2
  26. package/dist/remote-session.d.ts.map +1 -1
  27. package/dist/remote-session.js +37 -6
  28. package/dist/remote-session.js.map +1 -1
  29. package/dist/seam.d.ts +13 -5
  30. package/dist/seam.d.ts.map +1 -1
  31. package/dist/session-rpc.d.ts +76 -12
  32. package/dist/session-rpc.d.ts.map +1 -1
  33. package/dist/session-rpc.js +76 -8
  34. package/dist/session-rpc.js.map +1 -1
  35. package/dist/stub-transport.d.ts +2 -2
  36. package/dist/stub-transport.d.ts.map +1 -1
  37. package/dist/stub-transport.js +11 -0
  38. package/dist/stub-transport.js.map +1 -1
  39. package/package.json +18 -1
  40. package/src/cookies-export.ts +5 -5
  41. package/src/hand-host.ts +511 -0
  42. package/src/hand-loading.ts +254 -0
  43. package/src/index.ts +18 -1
  44. package/src/playwright-attach-transport.ts +65 -119
  45. package/src/playwright-launch-transport.ts +63 -244
  46. package/src/remote-session.ts +43 -5
  47. package/src/seam.ts +13 -5
  48. package/src/session-rpc.ts +121 -11
  49. package/src/stub-transport.ts +15 -3
@@ -2,8 +2,8 @@
2
2
  * The `cookies export` / `cookies import` verb's FILE FORMAT (PRD story 11).
3
3
  *
4
4
  * The seam already carries the transport-neutral cookie primitives:
5
- * {@link Page.cookies} reads the active context's cookies and
6
- * {@link Page.setCookies} loads cookies into it. The export/import VERB is built
5
+ * {@link WebHandsPage.cookies} reads the active context's cookies and
6
+ * {@link WebHandsPage.setCookies} loads cookies into it. The export/import VERB is built
7
7
  * ON TOP of those two methods (the forward-note: refine the existing seam,
8
8
  * do NOT add a parallel cookie path). What this module adds is only the
9
9
  * SERIALIZATION the verb needs to move a session to/from disk: how a
@@ -31,11 +31,11 @@ export declare const COOKIES_EXPORT_VERSION: 1;
31
31
  export interface CookiesExport {
32
32
  /** Format version (see {@link COOKIES_EXPORT_VERSION}). */
33
33
  readonly version: typeof COOKIES_EXPORT_VERSION;
34
- /** The exported cookies, exactly as the seam's {@link Page.cookies} returns them. */
34
+ /** The exported cookies, exactly as the seam's {@link WebHandsPage.cookies} returns them. */
35
35
  readonly cookies: readonly Cookie[];
36
36
  }
37
37
  /**
38
- * Serialize the cookies read from the seam ({@link Page.cookies}) into the
38
+ * Serialize the cookies read from the seam ({@link WebHandsPage.cookies}) into the
39
39
  * export file's text. Pretty-printed JSON so a human can read/diff a backed-up
40
40
  * session. This is pure: it does NO disk I/O, so the caller (the CLI verb, a
41
41
  * test) owns WHERE the file lands — which is what lets a test keep its export
@@ -44,7 +44,7 @@ export interface CookiesExport {
44
44
  export declare function serializeCookies(cookies: readonly Cookie[]): string;
45
45
  /**
46
46
  * Parse an export file's text back into the cookies to hand to the seam's
47
- * {@link Page.setCookies} ({@link parse} is pure; the caller does the disk read
47
+ * {@link WebHandsPage.setCookies} ({@link parse} is pure; the caller does the disk read
48
48
  * and the `setCookies` call). Rejects anything that is not a recognised export
49
49
  * envelope so a corrupt or wrong-version file surfaces as a clear error rather
50
50
  * than silently importing nothing or a half-parsed list.
@@ -1 +1 @@
1
- {"version":3,"file":"cookies-export.d.ts","sourceRoot":"","sources":["../src/cookies-export.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,WAAW,CAAC;AAEtC;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,EAAG,CAAU,CAAC;AAEjD;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC7B,2DAA2D;IAC3D,QAAQ,CAAC,OAAO,EAAE,OAAO,sBAAsB,CAAC;IAChD,qFAAqF;IACrF,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAMnE;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAyBlE"}
1
+ {"version":3,"file":"cookies-export.d.ts","sourceRoot":"","sources":["../src/cookies-export.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,WAAW,CAAC;AAEtC;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,EAAG,CAAU,CAAC;AAEjD;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC7B,2DAA2D;IAC3D,QAAQ,CAAC,OAAO,EAAE,OAAO,sBAAsB,CAAC;IAChD,6FAA6F;IAC7F,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAMnE;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAyBlE"}
@@ -2,8 +2,8 @@
2
2
  * The `cookies export` / `cookies import` verb's FILE FORMAT (PRD story 11).
3
3
  *
4
4
  * The seam already carries the transport-neutral cookie primitives:
5
- * {@link Page.cookies} reads the active context's cookies and
6
- * {@link Page.setCookies} loads cookies into it. The export/import VERB is built
5
+ * {@link WebHandsPage.cookies} reads the active context's cookies and
6
+ * {@link WebHandsPage.setCookies} loads cookies into it. The export/import VERB is built
7
7
  * ON TOP of those two methods (the forward-note: refine the existing seam,
8
8
  * do NOT add a parallel cookie path). What this module adds is only the
9
9
  * SERIALIZATION the verb needs to move a session to/from disk: how a
@@ -23,7 +23,7 @@
23
23
  */
24
24
  export const COOKIES_EXPORT_VERSION = 1;
25
25
  /**
26
- * Serialize the cookies read from the seam ({@link Page.cookies}) into the
26
+ * Serialize the cookies read from the seam ({@link WebHandsPage.cookies}) into the
27
27
  * export file's text. Pretty-printed JSON so a human can read/diff a backed-up
28
28
  * session. This is pure: it does NO disk I/O, so the caller (the CLI verb, a
29
29
  * test) owns WHERE the file lands — which is what lets a test keep its export
@@ -38,7 +38,7 @@ export function serializeCookies(cookies) {
38
38
  }
39
39
  /**
40
40
  * Parse an export file's text back into the cookies to hand to the seam's
41
- * {@link Page.setCookies} ({@link parse} is pure; the caller does the disk read
41
+ * {@link WebHandsPage.setCookies} ({@link parse} is pure; the caller does the disk read
42
42
  * and the `setCookies` call). Rejects anything that is not a recognised export
43
43
  * envelope so a corrupt or wrong-version file surfaces as a clear error rather
44
44
  * than silently importing nothing or a half-parsed list.
@@ -0,0 +1,217 @@
1
+ import { type BrowserContext, type Page } from 'playwright';
2
+ import type { WebHandsPage, WaitCondition } from './seam.js';
3
+ /**
4
+ * The hand-host primitive (Phase 1 of the "hands" prd,
5
+ * `work/prds/tasked/hands-pluggable-page-capabilities.md`).
6
+ *
7
+ * A **hand** is in-process code that closes over the WebHandsPage and contributes named
8
+ * verbs (+ an optional `dispose`). This module is the host: it builds the
9
+ * scoped-but-LIVE {@link HandContext} from the live Playwright objects, lets
10
+ * each hand contribute its verbs, and composes them into the same {@link WebHandsPage}
11
+ * object the seam already exposes (see {@link composePage}).
12
+ *
13
+ * webhands' OWN eight verbs are themselves built-in hands over this host
14
+ * ({@link BUILT_IN_HANDS}), so the primitive is proven by self-application: if
15
+ * it can express webhands' `click`/`snapshot`/`cookies`, it can host a
16
+ * third-party hand the same way (Phase 2). This is a purely INTERNAL,
17
+ * behavior-preserving refactor — the verb composition that lived as a
18
+ * duplicated `page` object literal in BOTH Playwright transports now lives here
19
+ * once.
20
+ *
21
+ * INTERNAL-ONLY BOUNDARY (the prd's resolved Q2): this whole module is
22
+ * package-internal. {@link Hand}/{@link HandContext}/{@link composePage} are
23
+ * NOT exported from the package entry point (`index.ts`) in Phase 1; they go
24
+ * public in the separate Phase 2 task. The public seam (`seam.ts`) is
25
+ * unchanged.
26
+ *
27
+ * NO-LEAK / CROSS-BROWSER (ADR-0003, refined by the prd): the host is built
28
+ * INSIDE the Playwright transport(s) and uses only the Playwright
29
+ * `Page`/`BrowserContext` API — no CDP/Chromium-only types — so the live
30
+ * `pwPage` stays in-process and never crosses the seam, and the host introduces
31
+ * no Chromium-only dependency that would foreclose a future Firefox launch
32
+ * (only CDP-`attach` stays Chromium-bound, as today).
33
+ *
34
+ * TRUST MODEL (stated, not enforced here): hands are trusted, local, in-process
35
+ * peers with ZERO isolation between them (one live page, one process).
36
+ * Inter-hand reuse is ordinary Node composition (import & call), NOT a
37
+ * sibling-hand registry in the context — so {@link HandContext} carries live
38
+ * page access only.
39
+ */
40
+ /**
41
+ * The scoped-but-LIVE access a hand receives. It carries live page access ONLY
42
+ * (the trust model note above): the real Playwright {@link Page} and
43
+ * {@link BrowserContext} the hand operates against in-process, plus the
44
+ * lifecycle guard.
45
+ *
46
+ * - `pwPage` — the live Node-side Playwright `Page`. NEVER crosses the seam.
47
+ * - `context` — the live `BrowserContext`; the built-in `cookies`/`setCookies`
48
+ * hand proves it is needed (cookies are a context-level, not page-level,
49
+ * concern).
50
+ * - `ensureOpen` — the per-session lifecycle guard. Each verb calls it first so
51
+ * a verb invoked after the session closed rejects with `session is closed`
52
+ * (the seam's lifetime contract). The guard's "closed" state is owned by the
53
+ * per-transport session wiring (launch vs attach differ); the host only reads
54
+ * it through this function.
55
+ */
56
+ export interface HandContext {
57
+ readonly pwPage: Page;
58
+ readonly context: BrowserContext;
59
+ readonly ensureOpen: () => void;
60
+ }
61
+ /**
62
+ * What a hand contributes once given its {@link HandContext}: a set of named
63
+ * verbs (a subset of webhands' (eight) seam verbs, i.e. a `Partial` of the
64
+ * seam {@link WebHandsPage}) and an optional `dispose` for any in-process
65
+ * resource it set up.
66
+ *
67
+ * A hand may contribute several verbs (the built-in interaction hand contributes
68
+ * both `click` and `type`) — a hand is NOT a single verb. It is NOT a transport
69
+ * either: it does not `open` sessions. Nothing more than this is allowed (no
70
+ * lifecycle hooks, no event handlers, no MCP-definition objects) — those are
71
+ * either the transport's job (session lifecycle) or a later phase's.
72
+ */
73
+ export interface HandContribution {
74
+ readonly verbs: Partial<WebHandsPage>;
75
+ readonly dispose?: () => Promise<void> | void;
76
+ }
77
+ /**
78
+ * A hand: a capability MODULE that, given live page access, contributes verbs.
79
+ * It is a plain factory function so a hand is just ordinary in-process Node
80
+ * code closing over the {@link HandContext} — the exact shape webhands' own
81
+ * verbs already had, made explicit.
82
+ */
83
+ export type Hand = (ctx: HandContext) => HandContribution;
84
+ /**
85
+ * The composed result the host hands back to a transport's session wiring: the
86
+ * {@link WebHandsPage} (the seam object the verbs were merged into) and a single
87
+ * `dispose` that tears down every hand.
88
+ */
89
+ export interface ComposedHands {
90
+ readonly page: WebHandsPage;
91
+ /**
92
+ * Dispose every hand's resources. Hands are disposed in REVERSE registration
93
+ * order (LIFO, the natural teardown order for layered setup), and every
94
+ * hand's `dispose` is awaited even if an earlier one rejects, so one failing
95
+ * hand cannot strand another's cleanup. This disposes the HANDS only; tearing
96
+ * down the browser/context (and the order relative to this) is the
97
+ * per-transport session lifecycle's job, NOT the host's.
98
+ */
99
+ dispose(): Promise<void>;
100
+ }
101
+ /**
102
+ * Compose a set of hands over one live {@link HandContext} into a single
103
+ * {@link WebHandsPage}. This is the host primitive both Playwright transports call to
104
+ * build their session's verb surface — the SINGLE shared composition (no
105
+ * duplicated page-object literal).
106
+ *
107
+ * Composition is EAGER (exactly as the page object literal was built before):
108
+ * each hand is invoked once at session-open time and its verbs are merged into
109
+ * one page object. There is no lazy registration and no ordering effect on the
110
+ * verbs themselves (the eight built-in verbs have disjoint names). The returned
111
+ * {@link WebHandsPage} is validated to carry every verb the seam requires, so a missing
112
+ * built-in verb is a build-time/open-time failure here rather than an `undefined
113
+ * is not a function` at the call site.
114
+ */
115
+ export declare function composePage(ctx: HandContext, hands: readonly Hand[]): ComposedHands;
116
+ /** The `navigate` verb: go to a URL and let it settle on the `load` event. */
117
+ export declare const navigationHand: Hand;
118
+ /** The `snapshot` verb: the token-cheap a11y view, or `--full` raw DOM. */
119
+ export declare const snapshotHand: Hand;
120
+ /** The `click` + `type` verbs: page interaction by raw locator (ADR-0004). */
121
+ export declare const interactionHand: Hand;
122
+ /** The `eval` escape hatch: run a JS EXPRESSION in the page, return by value. */
123
+ export declare const evalHand: Hand;
124
+ /** The `wait` verb: pace actions by a condition (timeout/locator/navigation). */
125
+ export declare const waitHand: Hand;
126
+ /**
127
+ * The `cookies` + `setCookies` verbs. These prove the {@link HandContext} needs
128
+ * the `context`: cookies are a context-level, not page-level, concern, so this
129
+ * hand reaches `ctx.context`, not `ctx.pwPage`.
130
+ */
131
+ export declare const cookiesHand: Hand;
132
+ /**
133
+ * webhands' eight built-in verbs as built-in hands, in composition order. Both
134
+ * Playwright transports compose THIS exact set, so the verb surface is
135
+ * identical across launch and attach (the only legitimate difference is the
136
+ * per-transport SESSION LIFECYCLE, which is not a hand's concern).
137
+ */
138
+ export declare const BUILT_IN_HANDS: readonly Hand[];
139
+ /**
140
+ * Compose webhands' built-in hands over a live context into the seam's
141
+ * {@link WebHandsPage}. The convenience both transports call: `composePage(ctx,
142
+ * BUILT_IN_HANDS)`. The built-in hands set up no in-process resources, so the
143
+ * returned `dispose` is a no-op today; it exists so a transport can sequence
144
+ * hand-teardown before its own browser/context teardown once third-party hands
145
+ * (which may hold resources) are added in Phase 2.
146
+ */
147
+ export declare function composeBuiltInPage(ctx: HandContext): ComposedHands;
148
+ /**
149
+ * Compose webhands' built-in hands together with any explicitly-loaded
150
+ * third-party hands (Phase 2) over a live context. The third-party hands are
151
+ * composed AFTER the built-ins through the EXACT same {@link composePage} the
152
+ * built-ins use, so a loaded hand plugs into the same host: its verbs merge into
153
+ * the same seam {@link WebHandsPage} and its `dispose` is sequenced LIFO with the rest.
154
+ * A third-party hand may add NEW verbs (the common case) and, because later
155
+ * contributions win the merge, may also override a built-in verb — that is the
156
+ * operator's choice, made by the trust act of naming the hand (ADR-0007).
157
+ */
158
+ export declare function composeWithHands(ctx: HandContext, extraHands: readonly Hand[]): ComposedHands;
159
+ /**
160
+ * Run the `wait` verb's three forms (PRD story 10) against a Playwright page.
161
+ *
162
+ * - `timeout` — pace by a fixed delay (`waitForTimeout`), so an agent can act
163
+ * like a human and let XHR-rendered content land.
164
+ * - `locator` — block until the addressed element appears (`Locator.waitFor()`),
165
+ * the form for content rendered AFTER `goto` settled on `load`.
166
+ * - `navigation` — block until the NEXT navigation settles to `load`. We use
167
+ * `waitForNavigation()` even though Playwright marks it `@deprecated` ("racy,
168
+ * use waitForURL"): that deprecation targets in-process TEST code that can arm
169
+ * the wait BEFORE the action and pass a target URL. Neither holds here. Across
170
+ * this seam verbs are DISCRETE sequential calls (`click` then `wait`), so we
171
+ * CANNOT arm before the trigger; and the realistic trigger is an async,
172
+ * JS-driven transition (a redirect / SPA route change that fires AFTER the
173
+ * agent's action, the "let XHR-rendered content load" case of story 10), so
174
+ * "wait for the NEXT navigation" is exactly right — whereas `waitForLoadState`
175
+ * would see the already-loaded current page and return before the pending
176
+ * transition. `waitForURL` is unusable because the verb has no target URL by
177
+ * design (the agent waits for "a navigation", not a known address). (See the
178
+ * task's ## Decisions note.)
179
+ *
180
+ * Shared by both Playwright transports (via the `wait` built-in hand) so the
181
+ * verb behaviour stays identical (no parallel second implementation).
182
+ */
183
+ export declare function waitFor(page: Page, condition: WaitCondition): Promise<void>;
184
+ /**
185
+ * Resolve a raw Playwright locator EXPRESSION (ADR-0004) against the page. The
186
+ * verb surface passes locator expressions like `getByRole('button', …)`; we
187
+ * evaluate them in a small sandbox where `page`/`p` is the page, so the full
188
+ * Playwright locator grammar is available without leaking the type across the
189
+ * seam.
190
+ *
191
+ * One resolution path for both transports (via the built-in interaction/wait
192
+ * hands), so there is no parallel addressing scheme.
193
+ */
194
+ export declare function resolveLocator(page: Page, expression: string): import("playwright").Locator;
195
+ /**
196
+ * Run the `click` verb against a Playwright page (PRD story 8), shared by both
197
+ * Playwright transports (via the built-in interaction hand) so the verb behaves
198
+ * identically (mirrors {@link waitFor}; no parallel second implementation).
199
+ *
200
+ * First try a normal `Locator.click()`, which AUTO-WAITS for the element to be
201
+ * visible and actionable — the right behaviour for a real button. A hidden
202
+ * custom input (the case the prd calls out) NEVER becomes actionable, so that
203
+ * click times out; on a Playwright `TimeoutError` we fall back to
204
+ * `dispatchEvent('click')`, which fires a click WITHOUT the actionability
205
+ * checks. The fallback is deliberately the documented Playwright escape (a
206
+ * sibling to the `eval` hatch, ADR-0004), not a reimplemented click: we keep
207
+ * the locator a raw resolved expression and only change HOW the resolved
208
+ * locator is clicked.
209
+ *
210
+ * Only a timeout triggers the fallback. The fallback `dispatchEvent` is itself
211
+ * bounded by the same short timeout, so a locator that resolves NO element (a
212
+ * bad locator) surfaces its timeout quickly instead of hanging the dispatch on
213
+ * Playwright's 30s default — the dispatch escape is for elements that EXIST but
214
+ * are not actionable (hidden custom inputs), not for absent ones.
215
+ */
216
+ export declare function clickLocator(page: Page, expression: string): Promise<void>;
217
+ //# sourceMappingURL=hand-host.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hand-host.d.ts","sourceRoot":"","sources":["../src/hand-host.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,cAAc,EAAE,KAAK,IAAI,EAAC,MAAM,YAAY,CAAC;AAC9E,OAAO,KAAK,EAEX,YAAY,EAGZ,aAAa,EACb,MAAM,WAAW,CAAC;AAEnB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,WAAW;IAC3B,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,IAAI,CAAC;CAChC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IACtC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CAC9C;AAED;;;;;GAKG;AACH,MAAM,MAAM,IAAI,GAAG,CAAC,GAAG,EAAE,WAAW,KAAK,gBAAgB,CAAC;AAE1D;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B;;;;;;;OAOG;IACH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACzB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAC1B,GAAG,EAAE,WAAW,EAChB,KAAK,EAAE,SAAS,IAAI,EAAE,GACpB,aAAa,CAgCf;AAsDD,8EAA8E;AAC9E,eAAO,MAAM,cAAc,EAAE,IAe3B,CAAC;AAEH,2EAA2E;AAC3E,eAAO,MAAM,YAAY,EAAE,IAyBzB,CAAC;AAEH,8EAA8E;AAC9E,eAAO,MAAM,eAAe,EAAE,IAW5B,CAAC;AAEH,iFAAiF;AACjF,eAAO,MAAM,QAAQ,EAAE,IAoBrB,CAAC;AAEH,iFAAiF;AACjF,eAAO,MAAM,QAAQ,EAAE,IAOrB,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,WAAW,EAAE,IAYxB,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,cAAc,EAAE,SAAS,IAAI,EAOzC,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,WAAW,GAAG,aAAa,CAElE;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC/B,GAAG,EAAE,WAAW,EAChB,UAAU,EAAE,SAAS,IAAI,EAAE,GACzB,aAAa,CAEf;AAOD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,OAAO,CAC5B,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,aAAa,GACtB,OAAO,CAAC,IAAI,CAAC,CAaf;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,gCAO5D;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,YAAY,CACjC,IAAI,EAAE,IAAI,EACV,UAAU,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAYf"}
@@ -0,0 +1,351 @@
1
+ import { errors as pwErrors } from 'playwright';
2
+ /**
3
+ * Compose a set of hands over one live {@link HandContext} into a single
4
+ * {@link WebHandsPage}. This is the host primitive both Playwright transports call to
5
+ * build their session's verb surface — the SINGLE shared composition (no
6
+ * duplicated page-object literal).
7
+ *
8
+ * Composition is EAGER (exactly as the page object literal was built before):
9
+ * each hand is invoked once at session-open time and its verbs are merged into
10
+ * one page object. There is no lazy registration and no ordering effect on the
11
+ * verbs themselves (the eight built-in verbs have disjoint names). The returned
12
+ * {@link WebHandsPage} is validated to carry every verb the seam requires, so a missing
13
+ * built-in verb is a build-time/open-time failure here rather than an `undefined
14
+ * is not a function` at the call site.
15
+ */
16
+ export function composePage(ctx, hands) {
17
+ const verbs = {};
18
+ const disposers = [];
19
+ for (const hand of hands) {
20
+ const contribution = hand(ctx);
21
+ Object.assign(verbs, contribution.verbs);
22
+ if (contribution.dispose !== undefined) {
23
+ disposers.push(contribution.dispose);
24
+ }
25
+ }
26
+ const page = assertCompletePage(verbs);
27
+ return {
28
+ page,
29
+ async dispose() {
30
+ // LIFO teardown; await every disposer even if one rejects so a single
31
+ // failing hand cannot strand the others' cleanup.
32
+ const failures = [];
33
+ for (let i = disposers.length - 1; i >= 0; i--) {
34
+ try {
35
+ await disposers[i]();
36
+ }
37
+ catch (cause) {
38
+ failures.push(cause);
39
+ }
40
+ }
41
+ if (failures.length > 0) {
42
+ throw failures[0];
43
+ }
44
+ },
45
+ };
46
+ }
47
+ /** The seam's full verb set; used to validate a composed page is complete. */
48
+ const REQUIRED_VERBS = [
49
+ 'navigate',
50
+ 'snapshot',
51
+ 'click',
52
+ 'type',
53
+ 'eval',
54
+ 'wait',
55
+ 'cookies',
56
+ 'setCookies',
57
+ ];
58
+ /**
59
+ * Assert the composed verbs cover the whole seam {@link WebHandsPage}, then return it
60
+ * as a `WebHandsPage`. A gap here means a built-in hand was dropped from the
61
+ * composition — surfacing it at open time is far cheaper than a runtime
62
+ * `undefined is not a function`.
63
+ */
64
+ function assertCompletePage(verbs) {
65
+ const missing = REQUIRED_VERBS.filter((name) => typeof verbs[name] !== 'function');
66
+ if (missing.length > 0) {
67
+ throw new Error(`hand-host: composed page is missing verb(s): ${missing.join(', ')}`);
68
+ }
69
+ return verbs;
70
+ }
71
+ /**
72
+ * How long a normal, actionability-checked `click` may wait before we treat the
73
+ * element as un-clickable and fall back to a dispatched click. Short on purpose:
74
+ * a hidden custom input never becomes actionable, so the regular click would
75
+ * otherwise burn Playwright's full default timeout (30s) before the escape path
76
+ * runs. The visible-element happy path clicks immediately and never hits this;
77
+ * this bound is the latency cost paid ONLY on the hidden/non-actionable path,
78
+ * and is long enough to tolerate a slow-but-eventually-actionable element
79
+ * (animations, late layout) before deciding to dispatch.
80
+ */
81
+ const NORMAL_CLICK_TIMEOUT_MS = 1_000;
82
+ // ---------------------------------------------------------------------------
83
+ // Built-in hands: webhands' OWN eight verbs, each a hand over the host.
84
+ //
85
+ // Grouped into cohesive capability modules (navigation, snapshot, interaction,
86
+ // eval, wait, cookies) to demonstrate that a hand can contribute several verbs
87
+ // + in-process logic (it is NOT one-verb-per-hand). The verb BODIES are moved
88
+ // verbatim from the two transports' page-object literals, so behavior is
89
+ // preserved byte-for-byte (the existing verb suite is the proof).
90
+ // ---------------------------------------------------------------------------
91
+ /** The `navigate` verb: go to a URL and let it settle on the `load` event. */
92
+ export const navigationHand = ({ pwPage, ensureOpen }) => ({
93
+ verbs: {
94
+ async navigate(url) {
95
+ ensureOpen();
96
+ // "Settled" for `goto` = the `load` event: the document and its
97
+ // subresources have loaded (PRD story 6, "navigate ... and wait for it
98
+ // to settle"). We deliberately do NOT wait for `networkidle`:
99
+ // Playwright discourages it, and it hangs forever on pages with
100
+ // long-poll / streaming / analytics beacons (exactly the logged-in apps
101
+ // this tool targets). Content rendered AFTER load (XHR-injected prices,
102
+ // hydrated lists) is the job of the explicit `wait` verb (story 10), not
103
+ // of `goto`.
104
+ await pwPage.goto(url, { waitUntil: 'load' });
105
+ },
106
+ },
107
+ });
108
+ /** The `snapshot` verb: the token-cheap a11y view, or `--full` raw DOM. */
109
+ export const snapshotHand = ({ pwPage, ensureOpen }) => ({
110
+ verbs: {
111
+ async snapshot(options) {
112
+ ensureOpen();
113
+ const url = pwPage.url();
114
+ if (options?.full === true) {
115
+ // `--full`: the raw DOM. `documentElement.outerHTML` is the serialized
116
+ // live DOM (post-script render), which is what an agent that wants the
117
+ // real HTML expects — not the original network response.
118
+ const content = await pwPage.evaluate(() => document.documentElement.outerHTML);
119
+ return { url, view: 'full', content };
120
+ }
121
+ // Default: the token-cheap accessibility tree + visible text with stable
122
+ // `[ref=...]` element refs. Playwright's `ariaSnapshot({mode: 'ai'})`
123
+ // emits exactly that — a YAML aria tree (roles + accessible names +
124
+ // text) where each node carries a stable `[ref=eN]` reference, assigned
125
+ // deterministically by traversal order so re-snapshotting an unchanged
126
+ // page yields the same refs. The string crosses the seam as opaque,
127
+ // transport-neutral text (no Playwright type leaks, ADR-0003).
128
+ const content = await pwPage.ariaSnapshot({ mode: 'ai' });
129
+ return { url, view: 'accessibility', content };
130
+ },
131
+ },
132
+ });
133
+ /** The `click` + `type` verbs: page interaction by raw locator (ADR-0004). */
134
+ export const interactionHand = ({ pwPage, ensureOpen }) => ({
135
+ verbs: {
136
+ async click(t) {
137
+ ensureOpen();
138
+ await clickLocator(pwPage, t);
139
+ },
140
+ async type(t, text) {
141
+ ensureOpen();
142
+ await resolveLocator(pwPage, t).fill(text);
143
+ },
144
+ },
145
+ });
146
+ /** The `eval` escape hatch: run a JS EXPRESSION in the page, return by value. */
147
+ export const evalHand = ({ pwPage, ensureOpen }) => ({
148
+ verbs: {
149
+ async eval(expression) {
150
+ ensureOpen();
151
+ // The `eval` escape hatch (PRD story 9): run the raw JS EXPRESSION in the
152
+ // page and return its serializable result. Playwright's `evaluate`
153
+ // already IS the seam's serialization contract (see {@link WebHandsPage.eval}):
154
+ // it passes a string as an expression, awaits a returned Promise, and
155
+ // structurally clones the result out of the page by VALUE. That clone is
156
+ // richer than JSON: it preserves NaN/Infinity/BigInt and circular
157
+ // structures (back-refs become a `[Circular]` marker), yields `undefined`
158
+ // for functions/symbols, and returns an opaque preview string for a live
159
+ // host object (a DOM node never crosses the process boundary). A page-side
160
+ // throw rejects. We pass it straight through rather than re-encode it:
161
+ // wrapping the value in a transport-specific envelope would invent a
162
+ // dialect the seam deliberately avoids. The thrown error is a plain
163
+ // `Error`, so no Playwright/CDP type leaks across the seam (ADR-0003).
164
+ return pwPage.evaluate(expression);
165
+ },
166
+ },
167
+ });
168
+ /** The `wait` verb: pace actions by a condition (timeout/locator/navigation). */
169
+ export const waitHand = ({ pwPage, ensureOpen }) => ({
170
+ verbs: {
171
+ async wait(condition) {
172
+ ensureOpen();
173
+ await waitFor(pwPage, condition);
174
+ },
175
+ },
176
+ });
177
+ /**
178
+ * The `cookies` + `setCookies` verbs. These prove the {@link HandContext} needs
179
+ * the `context`: cookies are a context-level, not page-level, concern, so this
180
+ * hand reaches `ctx.context`, not `ctx.pwPage`.
181
+ */
182
+ export const cookiesHand = ({ context, ensureOpen }) => ({
183
+ verbs: {
184
+ async cookies() {
185
+ ensureOpen();
186
+ const raw = await context.cookies();
187
+ return raw.map(toSeamCookie);
188
+ },
189
+ async setCookies(cookies) {
190
+ ensureOpen();
191
+ await context.addCookies(cookies.map(fromSeamCookie));
192
+ },
193
+ },
194
+ });
195
+ /**
196
+ * webhands' eight built-in verbs as built-in hands, in composition order. Both
197
+ * Playwright transports compose THIS exact set, so the verb surface is
198
+ * identical across launch and attach (the only legitimate difference is the
199
+ * per-transport SESSION LIFECYCLE, which is not a hand's concern).
200
+ */
201
+ export const BUILT_IN_HANDS = [
202
+ navigationHand,
203
+ snapshotHand,
204
+ interactionHand,
205
+ evalHand,
206
+ waitHand,
207
+ cookiesHand,
208
+ ];
209
+ /**
210
+ * Compose webhands' built-in hands over a live context into the seam's
211
+ * {@link WebHandsPage}. The convenience both transports call: `composePage(ctx,
212
+ * BUILT_IN_HANDS)`. The built-in hands set up no in-process resources, so the
213
+ * returned `dispose` is a no-op today; it exists so a transport can sequence
214
+ * hand-teardown before its own browser/context teardown once third-party hands
215
+ * (which may hold resources) are added in Phase 2.
216
+ */
217
+ export function composeBuiltInPage(ctx) {
218
+ return composePage(ctx, BUILT_IN_HANDS);
219
+ }
220
+ /**
221
+ * Compose webhands' built-in hands together with any explicitly-loaded
222
+ * third-party hands (Phase 2) over a live context. The third-party hands are
223
+ * composed AFTER the built-ins through the EXACT same {@link composePage} the
224
+ * built-ins use, so a loaded hand plugs into the same host: its verbs merge into
225
+ * the same seam {@link WebHandsPage} and its `dispose` is sequenced LIFO with the rest.
226
+ * A third-party hand may add NEW verbs (the common case) and, because later
227
+ * contributions win the merge, may also override a built-in verb — that is the
228
+ * operator's choice, made by the trust act of naming the hand (ADR-0007).
229
+ */
230
+ export function composeWithHands(ctx, extraHands) {
231
+ return composePage(ctx, [...BUILT_IN_HANDS, ...extraHands]);
232
+ }
233
+ // ---------------------------------------------------------------------------
234
+ // Shared verb building blocks (moved here with the verb bodies they back).
235
+ // Re-exported from the launch transport for its existing public-API consumers.
236
+ // ---------------------------------------------------------------------------
237
+ /**
238
+ * Run the `wait` verb's three forms (PRD story 10) against a Playwright page.
239
+ *
240
+ * - `timeout` — pace by a fixed delay (`waitForTimeout`), so an agent can act
241
+ * like a human and let XHR-rendered content land.
242
+ * - `locator` — block until the addressed element appears (`Locator.waitFor()`),
243
+ * the form for content rendered AFTER `goto` settled on `load`.
244
+ * - `navigation` — block until the NEXT navigation settles to `load`. We use
245
+ * `waitForNavigation()` even though Playwright marks it `@deprecated` ("racy,
246
+ * use waitForURL"): that deprecation targets in-process TEST code that can arm
247
+ * the wait BEFORE the action and pass a target URL. Neither holds here. Across
248
+ * this seam verbs are DISCRETE sequential calls (`click` then `wait`), so we
249
+ * CANNOT arm before the trigger; and the realistic trigger is an async,
250
+ * JS-driven transition (a redirect / SPA route change that fires AFTER the
251
+ * agent's action, the "let XHR-rendered content load" case of story 10), so
252
+ * "wait for the NEXT navigation" is exactly right — whereas `waitForLoadState`
253
+ * would see the already-loaded current page and return before the pending
254
+ * transition. `waitForURL` is unusable because the verb has no target URL by
255
+ * design (the agent waits for "a navigation", not a known address). (See the
256
+ * task's ## Decisions note.)
257
+ *
258
+ * Shared by both Playwright transports (via the `wait` built-in hand) so the
259
+ * verb behaviour stays identical (no parallel second implementation).
260
+ */
261
+ export async function waitFor(page, condition) {
262
+ switch (condition.kind) {
263
+ case 'timeout':
264
+ await page.waitForTimeout(condition.ms);
265
+ return;
266
+ case 'locator':
267
+ await resolveLocator(page, condition.target).waitFor();
268
+ return;
269
+ case 'navigation':
270
+ // eslint-disable-next-line @typescript-eslint/no-deprecated
271
+ await page.waitForNavigation();
272
+ return;
273
+ }
274
+ }
275
+ /**
276
+ * Resolve a raw Playwright locator EXPRESSION (ADR-0004) against the page. The
277
+ * verb surface passes locator expressions like `getByRole('button', …)`; we
278
+ * evaluate them in a small sandbox where `page`/`p` is the page, so the full
279
+ * Playwright locator grammar is available without leaking the type across the
280
+ * seam.
281
+ *
282
+ * One resolution path for both transports (via the built-in interaction/wait
283
+ * hands), so there is no parallel addressing scheme.
284
+ */
285
+ export function resolveLocator(page, expression) {
286
+ // eslint-disable-next-line no-new-func
287
+ const factory = new Function('page', 'p', `return (${expression});`);
288
+ return factory(page, page);
289
+ }
290
+ /**
291
+ * Run the `click` verb against a Playwright page (PRD story 8), shared by both
292
+ * Playwright transports (via the built-in interaction hand) so the verb behaves
293
+ * identically (mirrors {@link waitFor}; no parallel second implementation).
294
+ *
295
+ * First try a normal `Locator.click()`, which AUTO-WAITS for the element to be
296
+ * visible and actionable — the right behaviour for a real button. A hidden
297
+ * custom input (the case the prd calls out) NEVER becomes actionable, so that
298
+ * click times out; on a Playwright `TimeoutError` we fall back to
299
+ * `dispatchEvent('click')`, which fires a click WITHOUT the actionability
300
+ * checks. The fallback is deliberately the documented Playwright escape (a
301
+ * sibling to the `eval` hatch, ADR-0004), not a reimplemented click: we keep
302
+ * the locator a raw resolved expression and only change HOW the resolved
303
+ * locator is clicked.
304
+ *
305
+ * Only a timeout triggers the fallback. The fallback `dispatchEvent` is itself
306
+ * bounded by the same short timeout, so a locator that resolves NO element (a
307
+ * bad locator) surfaces its timeout quickly instead of hanging the dispatch on
308
+ * Playwright's 30s default — the dispatch escape is for elements that EXIST but
309
+ * are not actionable (hidden custom inputs), not for absent ones.
310
+ */
311
+ export async function clickLocator(page, expression) {
312
+ const target = resolveLocator(page, expression);
313
+ try {
314
+ await target.click({ timeout: NORMAL_CLICK_TIMEOUT_MS });
315
+ }
316
+ catch (cause) {
317
+ if (!(cause instanceof pwErrors.TimeoutError)) {
318
+ throw cause;
319
+ }
320
+ // The element never became actionable (e.g. a hidden custom input). Fire
321
+ // the click without actionability checks, the prd's explicit escape path.
322
+ await target.dispatchEvent('click', { timeout: NORMAL_CLICK_TIMEOUT_MS });
323
+ }
324
+ }
325
+ /** Map a Playwright cookie to the transport-neutral seam {@link Cookie}. */
326
+ function toSeamCookie(c) {
327
+ return {
328
+ name: c.name,
329
+ value: c.value,
330
+ domain: c.domain,
331
+ path: c.path,
332
+ expires: c.expires,
333
+ httpOnly: c.httpOnly,
334
+ secure: c.secure,
335
+ sameSite: c.sameSite,
336
+ };
337
+ }
338
+ /** Map a seam {@link Cookie} to a Playwright cookie shape. */
339
+ function fromSeamCookie(c) {
340
+ return {
341
+ name: c.name,
342
+ value: c.value,
343
+ domain: c.domain,
344
+ path: c.path,
345
+ expires: c.expires,
346
+ httpOnly: c.httpOnly,
347
+ secure: c.secure,
348
+ sameSite: c.sameSite,
349
+ };
350
+ }
351
+ //# sourceMappingURL=hand-host.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hand-host.js","sourceRoot":"","sources":["../src/hand-host.ts"],"names":[],"mappings":"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"}