agent-comms 9.1.3 → 10.0.1

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 (54) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.md +12 -0
  4. package/dist/bridges/user/web/bridge-port-range.d.ts +9 -3
  5. package/dist/bridges/user/web/bridge-port-range.d.ts.map +1 -1
  6. package/dist/bridges/user/web/bridge-port-range.js +17 -4
  7. package/dist/bridges/user/web/bridge-port-range.js.map +1 -1
  8. package/dist/bridges/user/web/dist/bundle.js +1 -1
  9. package/dist/bridges/user/web/dist/mesh-worker.js +4 -4
  10. package/dist/bridges/user/web/dist/sw.js +1 -1
  11. package/dist/bridges/user/web/pairing-handshake.d.ts +17 -0
  12. package/dist/bridges/user/web/pairing-handshake.d.ts.map +1 -0
  13. package/dist/bridges/user/web/pairing-handshake.js +121 -0
  14. package/dist/bridges/user/web/pairing-handshake.js.map +1 -0
  15. package/dist/bridges/user/web/pairing-protocol.d.ts +64 -0
  16. package/dist/bridges/user/web/pairing-protocol.d.ts.map +1 -0
  17. package/dist/bridges/user/web/pairing-protocol.js +65 -0
  18. package/dist/bridges/user/web/pairing-protocol.js.map +1 -0
  19. package/dist/bridges/user/web/server.d.ts +6 -0
  20. package/dist/bridges/user/web/server.d.ts.map +1 -1
  21. package/dist/bridges/user/web/server.js +91 -60
  22. package/dist/bridges/user/web/server.js.map +1 -1
  23. package/dist/bridges/user/web/web-access.d.ts +9 -1
  24. package/dist/bridges/user/web/web-access.d.ts.map +1 -1
  25. package/dist/bridges/user/web/web-access.js +32 -7
  26. package/dist/bridges/user/web/web-access.js.map +1 -1
  27. package/dist/bridges/user/web/web-listen.d.ts +11 -0
  28. package/dist/bridges/user/web/web-listen.d.ts.map +1 -0
  29. package/dist/bridges/user/web/web-listen.js +53 -0
  30. package/dist/bridges/user/web/web-listen.js.map +1 -0
  31. package/dist/bridges/user/web/web-pairing-exchange.d.ts +68 -0
  32. package/dist/bridges/user/web/web-pairing-exchange.d.ts.map +1 -0
  33. package/dist/bridges/user/web/web-pairing-exchange.js +201 -0
  34. package/dist/bridges/user/web/web-pairing-exchange.js.map +1 -0
  35. package/dist/bridges/user/web/web-pairing.d.ts +58 -0
  36. package/dist/bridges/user/web/web-pairing.d.ts.map +1 -0
  37. package/dist/bridges/user/web/web-pairing.js +215 -0
  38. package/dist/bridges/user/web/web-pairing.js.map +1 -0
  39. package/dist/cli-main.d.ts.map +1 -1
  40. package/dist/cli-main.js +12 -1
  41. package/dist/cli-main.js.map +1 -1
  42. package/package.json +2 -2
  43. package/src/bridges/user/web/bridge-port-range.ts +24 -4
  44. package/src/bridges/user/web/dist/bundle.js +1 -1
  45. package/src/bridges/user/web/dist/mesh-worker.js +4 -4
  46. package/src/bridges/user/web/dist/sw.js +1 -1
  47. package/src/bridges/user/web/pairing-handshake.ts +170 -0
  48. package/src/bridges/user/web/pairing-protocol.ts +122 -0
  49. package/src/bridges/user/web/server.ts +137 -69
  50. package/src/bridges/user/web/web-access.ts +40 -6
  51. package/src/bridges/user/web/web-listen.ts +68 -0
  52. package/src/bridges/user/web/web-pairing-exchange.ts +292 -0
  53. package/src/bridges/user/web/web-pairing.ts +273 -0
  54. package/src/cli-main.ts +14 -1
@@ -15,7 +15,7 @@
15
15
  "source": "url",
16
16
  "url": "https://github.com/ExaDev/agent-comms.git"
17
17
  },
18
- "version": "9.1.3"
18
+ "version": "10.0.1"
19
19
  }
20
20
  ]
21
21
  }
@@ -17,5 +17,5 @@
17
17
  },
18
18
  "name": "agent-comms",
19
19
  "repository": "https://github.com/ExaDev/agent-comms",
20
- "version": "9.1.3"
20
+ "version": "10.0.1"
21
21
  }
package/README.md CHANGED
@@ -334,6 +334,18 @@ Both legs are independently resumable: each side of the worker keeps its own buf
334
334
 
335
335
  Not every piece of dashboard data travels over that live event stream, though. Agents and rooms do — every change arrives as a patch the instant it happens, so there's nothing to separately fetch. Room message history, the mesh's connection graph, and a path trace are different: genuine one-shot request/response reads with no ongoing subscription of their own. Those three go through [TanStack Query](https://tanstack.com/query), wired up via [oRPC's own TanStack Query integration](https://orpc.unnoq.com/docs/integrations/tanstack-query) over the same tab-to-worker oRPC client described above — caching, request de-duplication, and cache invalidation on the same events that already drive the live side of the dashboard.
336
336
 
337
+ ## Pairing the hosted dashboard
338
+
339
+ The dashboard that GitHub Pages serves reaches a bridge on the same machine. The origin it is served from is shared by every page published under the same account, so the origin alone does not say which page is calling, and a port in the bridge range does not say which listener is the bridge. A per-install pairing secret, which this bridge issued and never sends, settles both: the dashboard and the bridge each prove they hold it before the dashboard sends anything or the bridge admits anything. A dashboard served by the bridge itself, and any other client on this machine, needs no secret.
340
+
341
+ To pair a browser, open `http://127.0.0.1:<port>/pair` (the bridge prints the address when it starts; the first bridge is on port 19877) in that browser on the machine running the bridge, and press Pair this browser. That opens the hosted dashboard with the secret in the address fragment, which no server receives. The dashboard keeps it in its own storage and removes it from the address. A browser without a secret is shown how to pair instead of being offered a connection.
342
+
343
+ The secret is only ever the key of a proof. For each port of the range the dashboard opens `/ws/hello` and sends a fresh random nonce, and nothing else. A bridge answers with its own nonce and an HMAC-SHA-256 over its role, both nonces and the port, keyed with the secret. The dashboard checks that proof in constant time and, only if it is right, answers with its own over the same nonces under the other role; a listener that is not the bridge learns one nonce and is not spoken to again, and a proof is bound to the port it was made for, so a listener cannot pass the real bridge's answer off as its own. The bridge checks the dashboard's proof and answers with a single-use ticket that lives a few seconds. The dashboard offers the ticket on the mesh socket as a second subprotocol (`agent-comms-ticket.<ticket>`), since a browser cannot set headers on a WebSocket and a query string would put the ticket in logs, and the server always selects the fixed `agent-comms` subprotocol, so the ticket is never echoed. A page of the hosted origin reaches nothing else of the bridge: every HTTP route and every other path answer `403`.
344
+
345
+ The secret is 256 random bits from the platform's cryptographic random source, kept as `web-pairing-secret` in the data directory with owner-only permissions (a file that is open to anyone else, or that belongs to someone else, is replaced), and never placed in a URL query string, a header or a log. `agent-comms pairing rotate` replaces it: the running bridge reads the file again when it changes, so every ticket and proof under the old secret is refused at once, without a restart, and every socket the hosted dashboard holds open is closed as soon as the operating system reports the secret file replaced (a periodic check once a second ends it otherwise, where the file system reports nothing); each browser pairs again. The pairing page is served only to a client on this machine, never to a page of the hosted origin and never to a request another site started, and it cannot be framed.
346
+
347
+ The dashboard keeps the secret in the storage of its own origin, which every page of that origin can read, so pairing separates a browser profile that was never paired from one that was, not pages that share the dashboard's storage; separating those needs the dashboard on an origin of its own. The exchange is a change to both sides: a dashboard that has it cannot connect to a bridge from before it, and a bridge that has it refuses a dashboard from before it. Update the bridge, and reload the dashboard, to the latest release of each.
348
+
337
349
  ## Reaching the web UI from the LAN
338
350
 
339
351
  A bridge's web server listens on loopback only unless told otherwise, and a browser on the same machine needs no credentials. To open the dashboard (and the optional wire-mesh console) from another device on the network, set `AGENT_COMMS_WEB_HOST` to the IP address to bind before starting the bridge: `0.0.0.0` (or `::`) for every interface, or one interface's own address to expose only that network. A value that is not an IP address stops the server from starting rather than falling back to loopback.
@@ -7,6 +7,8 @@
7
7
  */
8
8
  /** First port of the range a bridge's web server binds and the dashboard probes. */
9
9
  export declare const BRIDGE_PORT_BASE = 19877;
10
+ /** Where the pairing page of a bridge on `port` is. */
11
+ export declare function bridgePairingPageUrl(port: number): string;
10
12
  /** How many consecutive ports, from the base, belong to the range. */
11
13
  export declare const BRIDGE_PORT_COUNT = 10;
12
14
  /** How long the probe waits for one port to accept the mesh socket before it counts as not a bridge: a listener that accepts and never answers must not stall the walk over the rest of the range. A bridge answers on loopback well inside this. */
@@ -31,9 +33,12 @@ export declare function bridgeMeshUrl(port: number): string;
31
33
  /**
32
34
  * Whether a bridge's mesh socket (the dashboard's own endpoint, `/ws/mesh`) accepts a connection on the port within the timeout. Another kind of server, a refused port and a listener that never answers all give false: a WebSocket handshake needs a bridge to complete, and unlike a plain fetch it is readable from a hosted page without CORS headers.
33
35
  * @param port - The loopback port to try.
34
- * @param timeoutMs - How long to wait for the handshake; defaults to {@link BRIDGE_PROBE_TIMEOUT_MS}.
36
+ * @param options - `timeoutMs` is how long to wait for the handshake (default {@link BRIDGE_PROBE_TIMEOUT_MS}); `pairingSecret` is the secret this browser was paired with. With one, the listener must first prove it holds it (frontend/pairing-handshake.ts), and a listener that cannot, a bridge that was paired with another secret and a port nothing answers on are all not a bridge; the secret is never sent, and a listener that is not the bridge is sent one random nonce and nothing else. Without one the port is a bridge when its mesh socket accepts a connection.
35
37
  */
36
- export declare function isBridgeAt(port: number, timeoutMs?: number): Promise<boolean>;
38
+ export declare function isBridgeAt(port: number, options?: Readonly<{
39
+ timeoutMs?: number | undefined;
40
+ pairingSecret?: string | undefined;
41
+ }>): Promise<boolean>;
37
42
  /**
38
43
  * The first port of the range that `isBridge` accepts, tried in range order, or undefined when none does.
39
44
  * @param isBridge - Decides whether a bridge answers on a port.
@@ -43,10 +48,11 @@ export declare function findBridgePort(isBridge: (port: number) => Promise<boole
43
48
  /**
44
49
  * Looks for a bridge in the range and, when one answers, passes its mesh socket address to `onFound`; calls nothing when none does. Resolves once the walk is over.
45
50
  * @param onFound - Receives the mesh socket address of the first bridge found.
46
- * @param options - `base` is the first port of the range (default {@link BRIDGE_PORT_BASE}); `timeoutMs` is the wait for each port (default {@link BRIDGE_PROBE_TIMEOUT_MS}).
51
+ * @param options - `base` is the first port of the range (default {@link BRIDGE_PORT_BASE}); `timeoutMs` is the wait for each port (default {@link BRIDGE_PROBE_TIMEOUT_MS}); `pairingSecret` is offered to every port tried.
47
52
  */
48
53
  export declare function probeForBridge(onFound: (meshUrl: string) => void, options?: Readonly<{
49
54
  base?: number | undefined;
50
55
  timeoutMs?: number | undefined;
56
+ pairingSecret?: string | undefined;
51
57
  }>): Promise<void>;
52
58
  //# sourceMappingURL=bridge-port-range.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"bridge-port-range.d.ts","sourceRoot":"","sources":["../../../../src/bridges/user/web/bridge-port-range.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,oFAAoF;AACpF,eAAO,MAAM,gBAAgB,QAAQ,CAAC;AAEtC,sEAAsE;AACtE,eAAO,MAAM,iBAAiB,KAAK,CAAC;AAEpC,qPAAqP;AACrP,eAAO,MAAM,uBAAuB,OAAO,CAAC;AAE5C,qEAAqE;AACrE,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAE7C,4BAA4B;AAC5B,eAAO,MAAM,YAAY,QAAS,CAAC;AAEnC,2GAA2G;AAC3G,qBAAa,0BAA2B,SAAQ,KAAK;IACnD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,IAAI,EAAE,MAAM;CAOzB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,GAAE,MAAyB,GAAG,MAAM,EAAE,CASzE;AAED,uDAAuD;AACvD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAC9B,IAAI,EAAE,MAAM,EACZ,SAAS,GAAE,MAAgC,GAC1C,OAAO,CAAC,OAAO,CAAC,CA6BlB;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,EAC5C,IAAI,GAAE,MAAyB,GAC9B,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAK7B;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,EAClC,OAAO,CAAC,EAAE,QAAQ,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC,CAAC,GACD,OAAO,CAAC,IAAI,CAAC,CAOf"}
1
+ {"version":3,"file":"bridge-port-range.d.ts","sourceRoot":"","sources":["../../../../src/bridges/user/web/bridge-port-range.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,oFAAoF;AACpF,eAAO,MAAM,gBAAgB,QAAQ,CAAC;AAEtC,uDAAuD;AACvD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,sEAAsE;AACtE,eAAO,MAAM,iBAAiB,KAAK,CAAC;AAEpC,qPAAqP;AACrP,eAAO,MAAM,uBAAuB,OAAO,CAAC;AAE5C,qEAAqE;AACrE,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAE7C,4BAA4B;AAC5B,eAAO,MAAM,YAAY,QAAS,CAAC;AAEnC,2GAA2G;AAC3G,qBAAa,0BAA2B,SAAQ,KAAK;IACnD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,IAAI,EAAE,MAAM;CAOzB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,GAAE,MAAyB,GAAG,MAAM,EAAE,CASzE;AAED,uDAAuD;AACvD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAC9B,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,QAAQ,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACpC,CAAC,GACD,OAAO,CAAC,OAAO,CAAC,CAkClB;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,EAC5C,IAAI,GAAE,MAAyB,GAC9B,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAK7B;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,EAClC,OAAO,CAAC,EAAE,QAAQ,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACpC,CAAC,GACD,OAAO,CAAC,IAAI,CAAC,CAWf"}
@@ -5,8 +5,13 @@
5
5
  *
6
6
  * Shared by the Node server and the browser frontend, so it imports nothing from either.
7
7
  */
8
+ import { acquireTicket } from "./pairing-handshake.js";
8
9
  /** First port of the range a bridge's web server binds and the dashboard probes. */
9
10
  export const BRIDGE_PORT_BASE = 19877;
11
+ /** Where the pairing page of a bridge on `port` is. */
12
+ export function bridgePairingPageUrl(port) {
13
+ return `http://127.0.0.1:${String(port)}/pair`;
14
+ }
10
15
  /** How many consecutive ports, from the base, belong to the range. */
11
16
  export const BRIDGE_PORT_COUNT = 10;
12
17
  /** How long the probe waits for one port to accept the mesh socket before it counts as not a bridge: a listener that accepts and never answers must not stall the walk over the rest of the range. A bridge answers on loopback well inside this. */
@@ -44,9 +49,14 @@ export function bridgeMeshUrl(port) {
44
49
  /**
45
50
  * Whether a bridge's mesh socket (the dashboard's own endpoint, `/ws/mesh`) accepts a connection on the port within the timeout. Another kind of server, a refused port and a listener that never answers all give false: a WebSocket handshake needs a bridge to complete, and unlike a plain fetch it is readable from a hosted page without CORS headers.
46
51
  * @param port - The loopback port to try.
47
- * @param timeoutMs - How long to wait for the handshake; defaults to {@link BRIDGE_PROBE_TIMEOUT_MS}.
52
+ * @param options - `timeoutMs` is how long to wait for the handshake (default {@link BRIDGE_PROBE_TIMEOUT_MS}); `pairingSecret` is the secret this browser was paired with. With one, the listener must first prove it holds it (frontend/pairing-handshake.ts), and a listener that cannot, a bridge that was paired with another secret and a port nothing answers on are all not a bridge; the secret is never sent, and a listener that is not the bridge is sent one random nonce and nothing else. Without one the port is a bridge when its mesh socket accepts a connection.
48
53
  */
49
- export async function isBridgeAt(port, timeoutMs = BRIDGE_PROBE_TIMEOUT_MS) {
54
+ export async function isBridgeAt(port, options) {
55
+ const timeoutMs = options?.timeoutMs ?? BRIDGE_PROBE_TIMEOUT_MS;
56
+ const pairingSecret = options?.pairingSecret;
57
+ if (pairingSecret !== undefined) {
58
+ return (await acquireTicket(port, pairingSecret, timeoutMs)) !== undefined;
59
+ }
50
60
  return new Promise((resolve) => {
51
61
  const socket = new WebSocket(bridgeMeshUrl(port));
52
62
  const settle = (isBridge) => {
@@ -79,11 +89,14 @@ export async function findBridgePort(isBridge, base = BRIDGE_PORT_BASE) {
79
89
  /**
80
90
  * Looks for a bridge in the range and, when one answers, passes its mesh socket address to `onFound`; calls nothing when none does. Resolves once the walk is over.
81
91
  * @param onFound - Receives the mesh socket address of the first bridge found.
82
- * @param options - `base` is the first port of the range (default {@link BRIDGE_PORT_BASE}); `timeoutMs` is the wait for each port (default {@link BRIDGE_PROBE_TIMEOUT_MS}).
92
+ * @param options - `base` is the first port of the range (default {@link BRIDGE_PORT_BASE}); `timeoutMs` is the wait for each port (default {@link BRIDGE_PROBE_TIMEOUT_MS}); `pairingSecret` is offered to every port tried.
83
93
  */
84
94
  export async function probeForBridge(onFound, options) {
85
95
  const timeoutMs = options?.timeoutMs ?? BRIDGE_PROBE_TIMEOUT_MS;
86
- const port = await findBridgePort(async (candidate) => isBridgeAt(candidate, timeoutMs), options?.base);
96
+ const port = await findBridgePort(async (candidate) => isBridgeAt(candidate, {
97
+ timeoutMs,
98
+ pairingSecret: options?.pairingSecret,
99
+ }), options?.base);
87
100
  if (port !== undefined)
88
101
  onFound(bridgeMeshUrl(port));
89
102
  }
@@ -1 +1 @@
1
- {"version":3,"file":"bridge-port-range.js","sourceRoot":"","sources":["../../../../src/bridges/user/web/bridge-port-range.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bridge-port-range.js","sourceRoot":"","sources":["../../../../src/bridges/user/web/bridge-port-range.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvD,oFAAoF;AACpF,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,CAAC;AAEtC,uDAAuD;AACvD,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC/C,OAAO,oBAAoB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC;AACjD,CAAC;AAED,sEAAsE;AACtE,MAAM,CAAC,MAAM,iBAAiB,GAAG,EAAE,CAAC;AAEpC,qPAAqP;AACrP,MAAM,CAAC,MAAM,uBAAuB,GAAG,IAAI,CAAC;AAE5C,qEAAqE;AACrE,MAAM,CAAC,MAAM,wBAAwB,GAAG,IAAI,CAAC;AAE7C,4BAA4B;AAC5B,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC;AAEnC,2GAA2G;AAC3G,MAAM,OAAO,0BAA2B,SAAQ,KAAK;IAC1C,IAAI,CAAS;IAEtB,YAAY,IAAY;QACtB,KAAK,CACH,oBAAoB,MAAM,CAAC,IAAI,CAAC,4BAA4B,MAAM,CAAC,iBAAiB,CAAC,qBAAqB,MAAM,CAAC,wBAAwB,CAAC,OAAO,MAAM,CAAC,YAAY,CAAC,EAAE,CACxK,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,4BAA4B,CAAC;QACzC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,OAAe,gBAAgB;IAC7D,IACE,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC;QACvB,IAAI,GAAG,wBAAwB;QAC/B,IAAI,GAAG,iBAAiB,GAAG,CAAC,GAAG,YAAY,EAC3C,CAAC;QACD,MAAM,IAAI,0BAA0B,CAAC,IAAI,CAAC,CAAC;IAC7C,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,iBAAiB,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC;AAC/E,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,kBAAkB,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC;AAClD,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,IAAY,EACZ,OAGE;IAEF,MAAM,SAAS,GAAG,OAAO,EAAE,SAAS,IAAI,uBAAuB,CAAC;IAChE,MAAM,aAAa,GAAG,OAAO,EAAE,aAAa,CAAC;IAC7C,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;QAChC,OAAO,CAAC,MAAM,aAAa,CAAC,IAAI,EAAE,aAAa,EAAE,SAAS,CAAC,CAAC,KAAK,SAAS,CAAC;IAC7E,CAAC;IACD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;QAClD,MAAM,MAAM,GAAG,CAAC,QAAiB,EAAQ,EAAE;YACzC,MAAM,CAAC,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,QAAQ,CAAC,CAAC;QACpB,CAAC,CAAC;QACF,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,gBAAgB,CAC7C,OAAO,EACP,GAAG,EAAE;YACH,MAAM,CAAC,KAAK,CAAC,CAAC;QAChB,CAAC,EACD,EAAE,IAAI,EAAE,IAAI,EAAE,CACf,CAAC;QACF,MAAM,CAAC,gBAAgB,CACrB,MAAM,EACN,GAAG,EAAE;YACH,MAAM,CAAC,IAAI,CAAC,CAAC;QACf,CAAC,EACD,EAAE,IAAI,EAAE,IAAI,EAAE,CACf,CAAC;QACF,MAAM,CAAC,gBAAgB,CACrB,OAAO,EACP,GAAG,EAAE;YACH,MAAM,CAAC,KAAK,CAAC,CAAC;QAChB,CAAC,EACD,EAAE,IAAI,EAAE,IAAI,EAAE,CACf,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,QAA4C,EAC5C,OAAe,gBAAgB;IAE/B,KAAK,MAAM,IAAI,IAAI,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;QACzC,IAAI,MAAM,QAAQ,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;IACxC,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,OAAkC,EAClC,OAIE;IAEF,MAAM,SAAS,GAAG,OAAO,EAAE,SAAS,IAAI,uBAAuB,CAAC;IAChE,MAAM,IAAI,GAAG,MAAM,cAAc,CAC/B,KAAK,EAAE,SAAS,EAAE,EAAE,CAClB,UAAU,CAAC,SAAS,EAAE;QACpB,SAAS;QACT,aAAa,EAAE,OAAO,EAAE,aAAa;KACtC,CAAC,EACJ,OAAO,EAAE,IAAI,CACd,CAAC;IACF,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;AACvD,CAAC"}