agent-comms 9.1.3 → 10.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 (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 +1 -1
  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
@@ -6,9 +6,16 @@
6
6
  * Shared by the Node server and the browser frontend, so it imports nothing from either.
7
7
  */
8
8
 
9
+ import { acquireTicket } from "./pairing-handshake.js";
10
+
9
11
  /** First port of the range a bridge's web server binds and the dashboard probes. */
10
12
  export const BRIDGE_PORT_BASE = 19877;
11
13
 
14
+ /** Where the pairing page of a bridge on `port` is. */
15
+ export function bridgePairingPageUrl(port: number): string {
16
+ return `http://127.0.0.1:${String(port)}/pair`;
17
+ }
18
+
12
19
  /** How many consecutive ports, from the base, belong to the range. */
13
20
  export const BRIDGE_PORT_COUNT = 10;
14
21
 
@@ -58,12 +65,20 @@ export function bridgeMeshUrl(port: number): string {
58
65
  /**
59
66
  * 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.
60
67
  * @param port - The loopback port to try.
61
- * @param timeoutMs - How long to wait for the handshake; defaults to {@link BRIDGE_PROBE_TIMEOUT_MS}.
68
+ * @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.
62
69
  */
63
70
  export async function isBridgeAt(
64
71
  port: number,
65
- timeoutMs: number = BRIDGE_PROBE_TIMEOUT_MS,
72
+ options?: Readonly<{
73
+ timeoutMs?: number | undefined;
74
+ pairingSecret?: string | undefined;
75
+ }>,
66
76
  ): Promise<boolean> {
77
+ const timeoutMs = options?.timeoutMs ?? BRIDGE_PROBE_TIMEOUT_MS;
78
+ const pairingSecret = options?.pairingSecret;
79
+ if (pairingSecret !== undefined) {
80
+ return (await acquireTicket(port, pairingSecret, timeoutMs)) !== undefined;
81
+ }
67
82
  return new Promise((resolve) => {
68
83
  const socket = new WebSocket(bridgeMeshUrl(port));
69
84
  const settle = (isBridge: boolean): void => {
@@ -112,18 +127,23 @@ export async function findBridgePort(
112
127
  /**
113
128
  * 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.
114
129
  * @param onFound - Receives the mesh socket address of the first bridge found.
115
- * @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}).
130
+ * @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.
116
131
  */
117
132
  export async function probeForBridge(
118
133
  onFound: (meshUrl: string) => void,
119
134
  options?: Readonly<{
120
135
  base?: number | undefined;
121
136
  timeoutMs?: number | undefined;
137
+ pairingSecret?: string | undefined;
122
138
  }>,
123
139
  ): Promise<void> {
124
140
  const timeoutMs = options?.timeoutMs ?? BRIDGE_PROBE_TIMEOUT_MS;
125
141
  const port = await findBridgePort(
126
- async (candidate) => isBridgeAt(candidate, timeoutMs),
142
+ async (candidate) =>
143
+ isBridgeAt(candidate, {
144
+ timeoutMs,
145
+ pairingSecret: options?.pairingSecret,
146
+ }),
127
147
  options?.base,
128
148
  );
129
149
  if (port !== undefined) onFound(bridgeMeshUrl(port));