@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
@@ -1,9 +1,9 @@
1
1
  import { type Cookie, type WaitCondition } from './seam.js';
2
- import type { Page } from './seam.js';
2
+ import type { WebHandsPage } from './seam.js';
3
3
  /**
4
4
  * The wire protocol for driving the long-lived session over HTTP (ADR-0005).
5
5
  *
6
- * The served process holds ONE live {@link Page} in memory; a thin client verb
6
+ * The served process holds ONE live {@link WebHandsPage} in memory; a thin client verb
7
7
  * cannot hold a JS reference to it across the process boundary, so each verb
8
8
  * call is sent as a small JSON request to the server, which runs it against its
9
9
  * live page and returns the result. This module is the SINGLE source of truth
@@ -11,16 +11,46 @@ import type { Page } from './seam.js';
11
11
  * client proxy so they cannot drift (mirrors how `serializeCookies` is shared
12
12
  * by the cookies verb and its test).
13
13
  *
14
- * It is a thin transport detail, NOT a second verb surface: every request maps
15
- * 1:1 to a {@link Page} method, and the seam's verb semantics (ADR-0003/0004)
16
- * are unchanged. The {@link LocatorString} brand and the structured
17
- * {@link WaitCondition} cross as plain JSON and are re-branded on the server
18
- * with {@link locator}; no Playwright/CDP type is ever named here.
14
+ * It is a thin transport detail, NOT a second verb surface: every built-in
15
+ * request maps 1:1 to a {@link WebHandsPage} method, and the seam's verb semantics
16
+ * (ADR-0003/0004) are unchanged. The {@link LocatorString} brand and the
17
+ * structured {@link WaitCondition} cross as plain JSON and are re-branded on the
18
+ * server with {@link locator}; no Playwright/CDP type is ever named here.
19
+ *
20
+ * THIRD-PARTY HAND VERBS (Phase 2, Model B of the "hands" prd; ADR-0007). The
21
+ * eight built-in verbs stay a CLOSED union (the 1:1 source of truth above). A
22
+ * dynamically-loaded hand contributes a verb whose name `core` does NOT know at
23
+ * compile time, so it cannot be a named member of that closed union without
24
+ * re-meaning "closed". Instead it crosses as a SINGLE generic
25
+ * {@link SessionRpcHandRequest} variant (`{verb: 'hand', name, args}`) that
26
+ * names the contributed verb at runtime and carries its arguments. This is the
27
+ * exact wire parallel of how a hand verb composes into the page object: by name,
28
+ * dynamically, alongside the typed built-ins. The agent thereby gains a new tool
29
+ * over the wire WITHOUT ever holding a live page handle.
30
+ *
31
+ * SERIALIZATION BOUNDARY (the load-bearing rule; prd's resolved Q3). A hand
32
+ * verb's result crosses this RPC, so it MUST be serializable under the same
33
+ * structured-clone contract `eval` documents (see {@link WebHandsPage.eval}): richer
34
+ * than JSON, but a value with no transferable form does not round-trip. This is
35
+ * enforced by CONVENTION + TYPES (a hand author returns serializable values),
36
+ * NOT a blanket runtime clone here — a blanket clone would corrupt legitimate
37
+ * in-process (Model A) returns, where a hand may pass/return live Playwright
38
+ * handles within a single in-process call chain. A host-side runtime clone of
39
+ * agent-verb results is available HARDENING for untrusted hands, not built here.
40
+ * A page/in-hand throw REJECTS faithfully on the client exactly as the `eval`
41
+ * path already does (the server maps it to an `ok: false` reply carrying the
42
+ * message; the client re-throws a faithful `Error`).
19
43
  */
20
44
  /** The path the session RPC is served under, below the server's base URL. */
21
45
  export declare const SESSION_RPC_PATH = "/session/call";
22
46
  /** A single verb call to run against the served live page. */
23
- export type SessionRpcRequest = {
47
+ export type SessionRpcRequest = SessionRpcBuiltInRequest | SessionRpcHandRequest;
48
+ /**
49
+ * The CLOSED union of webhands' eight built-in verbs. Each variant maps 1:1 to a
50
+ * {@link WebHandsPage} method in {@link applySessionRpc}; this is the single source of
51
+ * truth for the built-in verb surface, shared verbatim by server and client.
52
+ */
53
+ export type SessionRpcBuiltInRequest = {
24
54
  readonly verb: 'navigate';
25
55
  readonly url: string;
26
56
  } | {
@@ -45,6 +75,24 @@ export type SessionRpcRequest = {
45
75
  readonly verb: 'setCookies';
46
76
  readonly cookies: readonly Cookie[];
47
77
  };
78
+ /**
79
+ * The OPEN escape for a dynamically-loaded third-party hand verb (Phase 2,
80
+ * Model B; ADR-0007). Unlike the closed built-in union, `core` does not know the
81
+ * verb's name at compile time, so it is carried at runtime: `name` is the
82
+ * contributed verb's plain name (exactly as it composed into the page object,
83
+ * not namespaced — a hand may even deliberately override a built-in, the
84
+ * operator's choice per ADR-0007) and `args` are its JSON arguments.
85
+ *
86
+ * The returned value and any thrown error obey the same serialization +
87
+ * rejection contract as `eval` (see this module's overview and {@link WebHandsPage.eval}).
88
+ */
89
+ export interface SessionRpcHandRequest {
90
+ readonly verb: 'hand';
91
+ /** The hand-contributed verb's name (as it composed into the page object). */
92
+ readonly name: string;
93
+ /** The verb's arguments, carried as plain JSON (must be serializable). */
94
+ readonly args: readonly unknown[];
95
+ }
48
96
  /**
49
97
  * The server's reply to a {@link SessionRpcRequest}. `ok: true` carries the
50
98
  * verb's return value (for verbs that return data); `ok: false` carries the
@@ -59,7 +107,7 @@ export type SessionRpcResponse = {
59
107
  readonly error: string;
60
108
  };
61
109
  /**
62
- * Run one {@link SessionRpcRequest} against a live {@link Page}, returning the
110
+ * Run one {@link SessionRpcRequest} against a live {@link WebHandsPage}, returning the
63
111
  * value the wire should carry back. The server's HTTP handler is just this plus
64
112
  * JSON framing; keeping the dispatch here (not inline in the handler) means the
65
113
  * verb-to-page mapping is in one place and unit-testable without HTTP.
@@ -68,9 +116,9 @@ export type SessionRpcResponse = {
68
116
  * locator with {@link locator} before handing it to the page so the seam's
69
117
  * branded-string contract holds.
70
118
  */
71
- export declare function applySessionRpc(page: Page, request: SessionRpcRequest): Promise<unknown>;
119
+ export declare function applySessionRpc(page: WebHandsPage, request: SessionRpcRequest): Promise<unknown>;
72
120
  /**
73
- * A {@link Page} whose verbs forward to a server via the supplied transport.
121
+ * A {@link WebHandsPage} whose verbs forward to a server via the supplied transport.
74
122
  *
75
123
  * Used by the client-side proxy (see `remote-session.ts`): each verb builds a
76
124
  * {@link SessionRpcRequest}, hands it to `send`, and shapes the reply back into
@@ -78,5 +126,21 @@ export declare function applySessionRpc(page: Page, request: SessionRpcRequest):
78
126
  * the verb-to-request mapping (the other half of {@link applySessionRpc}) in
79
127
  * one place so request and response shapes cannot drift between the two sides.
80
128
  */
81
- export declare function makeRpcPage(send: (request: SessionRpcRequest) => Promise<unknown>): Page;
129
+ export declare function makeRpcPage(send: (request: SessionRpcRequest) => Promise<unknown>): WebHandsPage;
130
+ /**
131
+ * Invoke a dynamically-loaded hand verb over the session RPC by name (Phase 2,
132
+ * Model B; ADR-0007). The client-side mirror of {@link applyHandVerb}: it builds
133
+ * the single generic {@link SessionRpcHandRequest} and hands it to the SAME
134
+ * `send` the built-in verbs use, so request/response shapes cannot drift.
135
+ *
136
+ * This is how the agent gains a new tool over the wire WITHOUT holding a live
137
+ * page handle: it names the contributed verb and passes serializable args; the
138
+ * server runs the hand against its own live page and returns a serializable
139
+ * result. A page/in-hand throw rejects faithfully (the `send` re-throws the
140
+ * server's error message), exactly as the `eval` path does.
141
+ *
142
+ * The result type is `unknown` because the hand decides the shape; callers
143
+ * narrow it (mirrors {@link WebHandsPage.eval}).
144
+ */
145
+ export declare function callHandVerb(send: (request: SessionRpcRequest) => Promise<unknown>, name: string, ...args: readonly unknown[]): Promise<unknown>;
82
146
  //# sourceMappingURL=session-rpc.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"session-rpc.d.ts","sourceRoot":"","sources":["../src/session-rpc.ts"],"names":[],"mappings":"AAAA,OAAO,EAEN,KAAK,MAAM,EAEX,KAAK,aAAa,EAClB,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,WAAW,CAAC;AAEpC;;;;;;;;;;;;;;;;GAgBG;AAEH,6EAA6E;AAC7E,eAAO,MAAM,gBAAgB,kBAAkB,CAAC;AAEhD,8DAA8D;AAC9D,MAAM,MAAM,iBAAiB,GAC1B;IAAC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAAC,GACjD;IAAC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAC,GACpD;IAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAC,GAClD;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAC,GACxE;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAAC,GACpD;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAA;CAAC,GAC1D;IAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;CAAC,GAC1B;IAAC,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;CAAC,CAAC;AAEtE;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,GAC3B;IAAC,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAC,GAC7C;IAAC,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAC,CAAC;AAEhD;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CACpC,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,iBAAiB,GACxB,OAAO,CAAC,OAAO,CAAC,CAwBlB;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAC1B,IAAI,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,OAAO,CAAC,OAAO,CAAC,GACpD,IAAI,CA8BN"}
1
+ {"version":3,"file":"session-rpc.d.ts","sourceRoot":"","sources":["../src/session-rpc.ts"],"names":[],"mappings":"AAAA,OAAO,EAEN,KAAK,MAAM,EAEX,KAAK,aAAa,EAClB,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,WAAW,CAAC;AAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH,6EAA6E;AAC7E,eAAO,MAAM,gBAAgB,kBAAkB,CAAC;AAEhD,8DAA8D;AAC9D,MAAM,MAAM,iBAAiB,GAC1B,wBAAwB,GACxB,qBAAqB,CAAC;AAEzB;;;;GAIG;AACH,MAAM,MAAM,wBAAwB,GACjC;IAAC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAAC,GACjD;IAAC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAC,GACpD;IAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAC,GAClD;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAC,GACxE;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAAC,GACpD;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAA;CAAC,GAC1D;IAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;CAAC,GAC1B;IAAC,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;CAAC,CAAC;AAEtE;;;;;;;;;;GAUG;AACH,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,8EAA8E;IAC9E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,0EAA0E;IAC1E,QAAQ,CAAC,IAAI,EAAE,SAAS,OAAO,EAAE,CAAC;CAClC;AAED;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,GAC3B;IAAC,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAC,GAC7C;IAAC,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAC,CAAC;AAEhD;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CACpC,IAAI,EAAE,YAAY,EAClB,OAAO,EAAE,iBAAiB,GACxB,OAAO,CAAC,OAAO,CAAC,CA0BlB;AAmCD;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAC1B,IAAI,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,OAAO,CAAC,OAAO,CAAC,GACpD,YAAY,CA8Bd;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,YAAY,CACjC,IAAI,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,OAAO,CAAC,OAAO,CAAC,EACtD,IAAI,EAAE,MAAM,EACZ,GAAG,IAAI,EAAE,SAAS,OAAO,EAAE,GACzB,OAAO,CAAC,OAAO,CAAC,CAElB"}
@@ -2,7 +2,7 @@ import { locator, } from './seam.js';
2
2
  /**
3
3
  * The wire protocol for driving the long-lived session over HTTP (ADR-0005).
4
4
  *
5
- * The served process holds ONE live {@link Page} in memory; a thin client verb
5
+ * The served process holds ONE live {@link WebHandsPage} in memory; a thin client verb
6
6
  * cannot hold a JS reference to it across the process boundary, so each verb
7
7
  * call is sent as a small JSON request to the server, which runs it against its
8
8
  * live page and returns the result. This module is the SINGLE source of truth
@@ -10,16 +10,40 @@ import { locator, } from './seam.js';
10
10
  * client proxy so they cannot drift (mirrors how `serializeCookies` is shared
11
11
  * by the cookies verb and its test).
12
12
  *
13
- * It is a thin transport detail, NOT a second verb surface: every request maps
14
- * 1:1 to a {@link Page} method, and the seam's verb semantics (ADR-0003/0004)
15
- * are unchanged. The {@link LocatorString} brand and the structured
16
- * {@link WaitCondition} cross as plain JSON and are re-branded on the server
17
- * with {@link locator}; no Playwright/CDP type is ever named here.
13
+ * It is a thin transport detail, NOT a second verb surface: every built-in
14
+ * request maps 1:1 to a {@link WebHandsPage} method, and the seam's verb semantics
15
+ * (ADR-0003/0004) are unchanged. The {@link LocatorString} brand and the
16
+ * structured {@link WaitCondition} cross as plain JSON and are re-branded on the
17
+ * server with {@link locator}; no Playwright/CDP type is ever named here.
18
+ *
19
+ * THIRD-PARTY HAND VERBS (Phase 2, Model B of the "hands" prd; ADR-0007). The
20
+ * eight built-in verbs stay a CLOSED union (the 1:1 source of truth above). A
21
+ * dynamically-loaded hand contributes a verb whose name `core` does NOT know at
22
+ * compile time, so it cannot be a named member of that closed union without
23
+ * re-meaning "closed". Instead it crosses as a SINGLE generic
24
+ * {@link SessionRpcHandRequest} variant (`{verb: 'hand', name, args}`) that
25
+ * names the contributed verb at runtime and carries its arguments. This is the
26
+ * exact wire parallel of how a hand verb composes into the page object: by name,
27
+ * dynamically, alongside the typed built-ins. The agent thereby gains a new tool
28
+ * over the wire WITHOUT ever holding a live page handle.
29
+ *
30
+ * SERIALIZATION BOUNDARY (the load-bearing rule; prd's resolved Q3). A hand
31
+ * verb's result crosses this RPC, so it MUST be serializable under the same
32
+ * structured-clone contract `eval` documents (see {@link WebHandsPage.eval}): richer
33
+ * than JSON, but a value with no transferable form does not round-trip. This is
34
+ * enforced by CONVENTION + TYPES (a hand author returns serializable values),
35
+ * NOT a blanket runtime clone here — a blanket clone would corrupt legitimate
36
+ * in-process (Model A) returns, where a hand may pass/return live Playwright
37
+ * handles within a single in-process call chain. A host-side runtime clone of
38
+ * agent-verb results is available HARDENING for untrusted hands, not built here.
39
+ * A page/in-hand throw REJECTS faithfully on the client exactly as the `eval`
40
+ * path already does (the server maps it to an `ok: false` reply carrying the
41
+ * message; the client re-throws a faithful `Error`).
18
42
  */
19
43
  /** The path the session RPC is served under, below the server's base URL. */
20
44
  export const SESSION_RPC_PATH = '/session/call';
21
45
  /**
22
- * Run one {@link SessionRpcRequest} against a live {@link Page}, returning the
46
+ * Run one {@link SessionRpcRequest} against a live {@link WebHandsPage}, returning the
23
47
  * value the wire should carry back. The server's HTTP handler is just this plus
24
48
  * JSON framing; keeping the dispatch here (not inline in the handler) means the
25
49
  * verb-to-page mapping is in one place and unit-testable without HTTP.
@@ -51,10 +75,36 @@ export async function applySessionRpc(page, request) {
51
75
  case 'setCookies':
52
76
  await page.setCookies(request.cookies);
53
77
  return undefined;
78
+ case 'hand':
79
+ return applyHandVerb(page, request);
54
80
  }
55
81
  }
56
82
  /**
57
- * A {@link Page} whose verbs forward to a server via the supplied transport.
83
+ * Invoke a dynamically-loaded hand verb by name against the live composed page.
84
+ *
85
+ * The composed {@link WebHandsPage} carries the hand's verbs at runtime (the host merged
86
+ * them in by name alongside the built-ins, see `composePage`), even though the
87
+ * seam `WebHandsPage` TYPE only names the eight built-ins. We therefore look the verb up
88
+ * on the page object as a runtime method and invoke it with the request's args.
89
+ * An unknown name is a faithful error (the hand was not loaded / named that
90
+ * verb), surfaced the same way a page-side throw is so the client rejects.
91
+ *
92
+ * The result is returned as-is: the serializable-only boundary is enforced by
93
+ * convention + types on the hand author, NOT a runtime clone here (a blanket
94
+ * clone would corrupt legitimate in-process Model A returns; see this module's
95
+ * overview). What the hand returns is what the wire carries back; the JSON
96
+ * framing in the server handler is the only encoding applied.
97
+ */
98
+ async function applyHandVerb(page, request) {
99
+ const verb = page[request.name];
100
+ if (typeof verb !== 'function') {
101
+ throw new Error(`no such hand verb '${request.name}' on the live page ` +
102
+ `(is the hand loaded and named in config?)`);
103
+ }
104
+ return verb.call(page, ...request.args);
105
+ }
106
+ /**
107
+ * A {@link WebHandsPage} whose verbs forward to a server via the supplied transport.
58
108
  *
59
109
  * Used by the client-side proxy (see `remote-session.ts`): each verb builds a
60
110
  * {@link SessionRpcRequest}, hands it to `send`, and shapes the reply back into
@@ -93,6 +143,24 @@ export function makeRpcPage(send) {
93
143
  },
94
144
  };
95
145
  }
146
+ /**
147
+ * Invoke a dynamically-loaded hand verb over the session RPC by name (Phase 2,
148
+ * Model B; ADR-0007). The client-side mirror of {@link applyHandVerb}: it builds
149
+ * the single generic {@link SessionRpcHandRequest} and hands it to the SAME
150
+ * `send` the built-in verbs use, so request/response shapes cannot drift.
151
+ *
152
+ * This is how the agent gains a new tool over the wire WITHOUT holding a live
153
+ * page handle: it names the contributed verb and passes serializable args; the
154
+ * server runs the hand against its own live page and returns a serializable
155
+ * result. A page/in-hand throw rejects faithfully (the `send` re-throws the
156
+ * server's error message), exactly as the `eval` path does.
157
+ *
158
+ * The result type is `unknown` because the hand decides the shape; callers
159
+ * narrow it (mirrors {@link WebHandsPage.eval}).
160
+ */
161
+ export async function callHandVerb(send, name, ...args) {
162
+ return send({ verb: 'hand', name, args });
163
+ }
96
164
  /**
97
165
  * Re-brand a {@link WaitCondition} that arrived as plain JSON: only the
98
166
  * `locator` form carries a branded string, which JSON flattens to a plain
@@ -1 +1 @@
1
- {"version":3,"file":"session-rpc.js","sourceRoot":"","sources":["../src/session-rpc.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session-rpc.js","sourceRoot":"","sources":["../src/session-rpc.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,9 @@
1
- import type { OpenTarget, Page, Session, Transport } from './seam.js';
1
+ import type { OpenTarget, WebHandsPage, Session, Transport } from './seam.js';
2
2
  /**
3
3
  * A record of one verb call against the stub, for assertions in seam tests.
4
4
  */
5
5
  export interface StubCall {
6
- readonly verb: keyof Page;
6
+ readonly verb: keyof WebHandsPage;
7
7
  readonly args: readonly unknown[];
8
8
  }
9
9
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"stub-transport.d.ts","sourceRoot":"","sources":["../src/stub-transport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEX,UAAU,EACV,IAAI,EACJ,OAAO,EAGP,SAAS,EAET,MAAM,WAAW,CAAC;AAEnB;;GAEG;AACH,MAAM,WAAW,QAAQ;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,IAAI,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,SAAS,OAAO,EAAE,CAAC;CAClC;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,aAAc,YAAW,SAAS;IAC9C,4EAA4E;IAC5E,QAAQ,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAM;IAE1B,IAAI,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC;CAgEhD"}
1
+ {"version":3,"file":"stub-transport.d.ts","sourceRoot":"","sources":["../src/stub-transport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEX,UAAU,EACV,YAAY,EACZ,OAAO,EAGP,SAAS,EAET,MAAM,WAAW,CAAC;AAEnB;;GAEG;AACH,MAAM,WAAW,QAAQ;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,YAAY,CAAC;IAClC,QAAQ,CAAC,IAAI,EAAE,SAAS,OAAO,EAAE,CAAC;CAClC;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,aAAc,YAAW,SAAS;IAC9C,4EAA4E;IAC5E,QAAQ,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAM;IAE1B,IAAI,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC;CA4EhD"}
@@ -16,6 +16,10 @@ export class StubTransport {
16
16
  async open(target) {
17
17
  const calls = this.calls;
18
18
  let closed = false;
19
+ let resolveClosed;
20
+ const closedSignal = new Promise((resolve) => {
21
+ resolveClosed = resolve;
22
+ });
19
23
  const ensureOpen = () => {
20
24
  if (closed) {
21
25
  throw new Error('session is closed');
@@ -68,7 +72,14 @@ export class StubTransport {
68
72
  return {
69
73
  page,
70
74
  async close() {
75
+ if (closed) {
76
+ return;
77
+ }
71
78
  closed = true;
79
+ resolveClosed();
80
+ },
81
+ waitForClose() {
82
+ return closedSignal;
72
83
  },
73
84
  };
74
85
  }
@@ -1 +1 @@
1
- {"version":3,"file":"stub-transport.js","sourceRoot":"","sources":["../src/stub-transport.ts"],"names":[],"mappings":"AAmBA;;;;;;;;;;;GAWG;AACH,MAAM,OAAO,aAAa;IACzB,4EAA4E;IACnE,KAAK,GAAe,EAAE,CAAC;IAEhC,KAAK,CAAC,IAAI,CAAC,MAAkB;QAC5B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACzB,IAAI,MAAM,GAAG,KAAK,CAAC;QAEnB,MAAM,UAAU,GAAG,GAAG,EAAE;YACvB,IAAI,MAAM,EAAE,CAAC;gBACZ,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;YACtC,CAAC;QACF,CAAC,CAAC;QAEF,MAAM,GAAG,GACR,MAAM,CAAC,IAAI,KAAK,QAAQ;YACvB,CAAC,CAAC,iBAAiB,MAAM,CAAC,OAAO,EAAE;YACnC,CAAC,CAAC,iBAAiB,MAAM,CAAC,QAAQ,EAAE,CAAC;QAEvC,MAAM,IAAI,GAAS;YAClB,KAAK,CAAC,QAAQ,CAAC,EAAU;gBACxB,UAAU,EAAE,CAAC;gBACb,KAAK,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,EAAC,CAAC,CAAC;YAC5C,CAAC;YACD,KAAK,CAAC,QAAQ,CAAC,OAAyB;gBACvC,UAAU,EAAE,CAAC;gBACb,KAAK,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,OAAO,CAAC,EAAC,CAAC,CAAC;gBAChD,OAAO;oBACN,GAAG;oBACH,IAAI,EAAE,OAAO,EAAE,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,eAAe;oBACvD,OAAO,EAAE,EAAE;iBACX,CAAC;YACH,CAAC;YACD,KAAK,CAAC,KAAK,CAAC,CAAC;gBACZ,UAAU,EAAE,CAAC;gBACb,KAAK,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC;YACxC,CAAC;YACD,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI;gBACjB,UAAU,EAAE,CAAC;gBACb,KAAK,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,EAAC,CAAC,CAAC;YAC7C,CAAC;YACD,KAAK,CAAC,IAAI,CAAC,UAAkB;gBAC5B,UAAU,EAAE,CAAC;gBACb,KAAK,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,UAAU,CAAC,EAAC,CAAC,CAAC;gBAC/C,OAAO,SAAS,CAAC;YAClB,CAAC;YACD,KAAK,CAAC,IAAI,CAAC,SAAwB;gBAClC,UAAU,EAAE,CAAC;gBACb,KAAK,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,SAAS,CAAC,EAAC,CAAC,CAAC;YAC/C,CAAC;YACD,KAAK,CAAC,OAAO;gBACZ,UAAU,EAAE,CAAC;gBACb,KAAK,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,EAAC,CAAC,CAAC;gBACxC,OAAO,EAAE,CAAC;YACX,CAAC;YACD,KAAK,CAAC,UAAU,CAAC,OAAO;gBACvB,UAAU,EAAE,CAAC;gBACb,KAAK,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,OAAO,CAAC,EAAC,CAAC,CAAC;YACnD,CAAC;SACD,CAAC;QAEF,OAAO;YACN,IAAI;YACJ,KAAK,CAAC,KAAK;gBACV,MAAM,GAAG,IAAI,CAAC;YACf,CAAC;SACD,CAAC;IACH,CAAC;CACD"}
1
+ {"version":3,"file":"stub-transport.js","sourceRoot":"","sources":["../src/stub-transport.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,23 @@
1
1
  {
2
2
  "name": "@webhands/core",
3
- "version": "0.1.0",
3
+ "version": "1.0.0",
4
+ "description": "Core library for webhands: drives a real, persistent browser via Playwright.",
5
+ "keywords": [
6
+ "browser",
7
+ "playwright",
8
+ "automation"
9
+ ],
10
+ "license": "AGPL-3.0-or-later",
11
+ "author": "wighawag",
12
+ "homepage": "https://github.com/wighawag/webhands#readme",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/wighawag/webhands.git",
16
+ "directory": "packages/core"
17
+ },
18
+ "bugs": {
19
+ "url": "https://github.com/wighawag/webhands/issues"
20
+ },
4
21
  "publishConfig": {
5
22
  "access": "public"
6
23
  },
@@ -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
@@ -34,12 +34,12 @@ export const COOKIES_EXPORT_VERSION = 1 as const;
34
34
  export interface CookiesExport {
35
35
  /** Format version (see {@link COOKIES_EXPORT_VERSION}). */
36
36
  readonly version: typeof COOKIES_EXPORT_VERSION;
37
- /** The exported cookies, exactly as the seam's {@link Page.cookies} returns them. */
37
+ /** The exported cookies, exactly as the seam's {@link WebHandsPage.cookies} returns them. */
38
38
  readonly cookies: readonly Cookie[];
39
39
  }
40
40
 
41
41
  /**
42
- * Serialize the cookies read from the seam ({@link Page.cookies}) into the
42
+ * Serialize the cookies read from the seam ({@link WebHandsPage.cookies}) into the
43
43
  * export file's text. Pretty-printed JSON so a human can read/diff a backed-up
44
44
  * session. This is pure: it does NO disk I/O, so the caller (the CLI verb, a
45
45
  * test) owns WHERE the file lands — which is what lets a test keep its export
@@ -55,7 +55,7 @@ export function serializeCookies(cookies: readonly Cookie[]): string {
55
55
 
56
56
  /**
57
57
  * Parse an export file's text back into the cookies to hand to the seam's
58
- * {@link Page.setCookies} ({@link parse} is pure; the caller does the disk read
58
+ * {@link WebHandsPage.setCookies} ({@link parse} is pure; the caller does the disk read
59
59
  * and the `setCookies` call). Rejects anything that is not a recognised export
60
60
  * envelope so a corrupt or wrong-version file surfaces as a clear error rather
61
61
  * than silently importing nothing or a half-parsed list.