agent-comms 1.27.2 → 1.28.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.
@@ -0,0 +1,90 @@
1
+ /**
2
+ * becomeCoordinator actual-port regression test (#42) — becomeCoordinator(host, 0) must report the OS-assigned port it actually bound, not the literal 0 it was called with, on every transport whose listener bookkeeping goes through listListeners().
3
+ *
4
+ * Run: node dist/test/become-coordinator-actual-port.integration.test.js [test-name] With no argument, every scenario runs in order.
5
+ */
6
+ import * as net from "node:net";
7
+ import * as tls from "node:tls";
8
+ import * as assert from "node:assert/strict";
9
+ import { TlsTransport } from "../core/tls-transport.js";
10
+ import { TcpTransport } from "../core/tcp-transport.js";
11
+ import { generateIdentity } from "../core/identity.js";
12
+ function noopEvents() {
13
+ return {
14
+ onMessage: () => undefined,
15
+ onPeerConnected: () => undefined,
16
+ onPeerDisconnected: () => undefined,
17
+ onIntroduction: () => undefined,
18
+ onConnectionRequest: () => undefined,
19
+ onPeerList: () => undefined,
20
+ onPeerJoined: () => undefined,
21
+ onBecomeCoordinator: () => undefined,
22
+ };
23
+ }
24
+ async function testTlsReportsActualPort() {
25
+ const identity = generateIdentity();
26
+ const transport = new TlsTransport(noopEvents(), identity);
27
+ await transport.becomeCoordinator("127.0.0.1", 0);
28
+ const [listener] = transport.listListeners();
29
+ assert.ok(listener);
30
+ assert.notStrictEqual(listener.port, 0);
31
+ await new Promise((resolve, reject) => {
32
+ const socket = tls.connect({ host: "127.0.0.1", port: listener.port, rejectUnauthorized: false }, () => {
33
+ socket.destroy();
34
+ resolve();
35
+ });
36
+ socket.once("error", reject);
37
+ });
38
+ console.log(` ✓ TlsTransport reported and bound the same port (${listener.port})`);
39
+ await transport.shutdown();
40
+ }
41
+ async function testTcpReportsActualPort() {
42
+ const transport = new TcpTransport(noopEvents());
43
+ await transport.becomeCoordinator("127.0.0.1", 0);
44
+ const [listener] = transport.listListeners();
45
+ assert.ok(listener);
46
+ assert.notStrictEqual(listener.port, 0);
47
+ await new Promise((resolve, reject) => {
48
+ const socket = net.connect({ host: "127.0.0.1", port: listener.port }, () => {
49
+ socket.destroy();
50
+ resolve();
51
+ });
52
+ socket.once("error", reject);
53
+ });
54
+ console.log(` ✓ TcpTransport reported and bound the same port (${listener.port})`);
55
+ await transport.shutdown();
56
+ }
57
+ // ---------------------------------------------------------------------------
58
+ // Runner
59
+ // ---------------------------------------------------------------------------
60
+ const testName = process.argv[2];
61
+ const tests = {
62
+ "tls-reports-actual-port": testTlsReportsActualPort,
63
+ "tcp-reports-actual-port": testTcpReportsActualPort,
64
+ };
65
+ const selected = testName === undefined
66
+ ? Object.entries(tests)
67
+ : Object.entries(tests).filter(([name]) => name === testName);
68
+ if (selected.length === 0) {
69
+ console.error(`Unknown test: ${testName}`);
70
+ console.error(`Available: ${Object.keys(tests).join(", ")}`);
71
+ process.exit(1);
72
+ }
73
+ async function run() {
74
+ for (const [name, fn] of selected) {
75
+ console.log(`Running ${name}:`);
76
+ await fn();
77
+ }
78
+ const maxWait = 2000;
79
+ const start = Date.now();
80
+ while ((process._getActiveHandles?.()?.length ?? 0) > 0 &&
81
+ Date.now() - start < maxWait) {
82
+ await new Promise((resolve) => setTimeout(resolve, 50));
83
+ }
84
+ process.exit(0);
85
+ }
86
+ run().catch((err) => {
87
+ console.error(`FAIL [${testName ?? "all"}]:`, err);
88
+ process.exit(1);
89
+ });
90
+ //# sourceMappingURL=become-coordinator-actual-port.integration.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"become-coordinator-actual-port.integration.test.js","sourceRoot":"","sources":["../../src/test/become-coordinator-actual-port.integration.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Unit tests for the protocol handshake (#31): the gate state machine, negotiation over wire-mesh-core, and the state-sync wire tolerance.
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=handshake.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handshake.test.d.ts","sourceRoot":"","sources":["../../src/test/handshake.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,196 @@
1
+ /**
2
+ * Unit tests for the protocol handshake (#31): the gate state machine, negotiation over wire-mesh-core, and the state-sync wire tolerance.
3
+ */
4
+ import * as assert from "node:assert/strict";
5
+ import * as net from "node:net";
6
+ import { describe, it } from "node:test";
7
+ import { encode as cborEncode, cdeEncodeOptions } from "cbor2";
8
+ import { AGENT_COMMS_DOMAIN, ConnectionHandshake, MESH_PROTOCOL_VERSION, attachSocketHandshake, encodeHandshakeFrame, negotiateMeshProtocol, } from "../core/handshake.js";
9
+ import { normaliseWireState, } from "../core/wire-protocol.js";
10
+ describe("negotiateMeshProtocol", () => {
11
+ it("negotiates down to the lower version with the shared domain", () => {
12
+ const result = negotiateMeshProtocol({
13
+ type: "handshake",
14
+ version: MESH_PROTOCOL_VERSION + 1,
15
+ domains: [AGENT_COMMS_DOMAIN],
16
+ });
17
+ assert.equal(result.ok, true);
18
+ assert.equal(result.version, MESH_PROTOCOL_VERSION);
19
+ assert.deepEqual(result.sharedDomains, [AGENT_COMMS_DOMAIN]);
20
+ });
21
+ it("refuses a peer with no shared domain", () => {
22
+ const result = negotiateMeshProtocol({
23
+ type: "handshake",
24
+ version: MESH_PROTOCOL_VERSION,
25
+ domains: ["example.com/something-else"],
26
+ });
27
+ assert.equal(result.ok, false);
28
+ });
29
+ });
30
+ describe("ConnectionHandshake", () => {
31
+ it("classifies a peer frame as negotiated and returns trailing JSON bytes", () => {
32
+ const gate = new ConnectionHandshake("server");
33
+ const frame = encodeHandshakeFrame();
34
+ const jsonTail = Buffer.from('{"method":"introduce"}\n', "utf8");
35
+ const outcome = gate.feed(Buffer.concat([frame, jsonTail]));
36
+ assert.equal(outcome.kind, "negotiated");
37
+ if (outcome.kind !== "negotiated")
38
+ return;
39
+ assert.equal(outcome.result.version, MESH_PROTOCOL_VERSION);
40
+ assert.equal(outcome.rest.toString(), jsonTail.toString());
41
+ // Subsequent feeds pass through unchanged.
42
+ const more = gate.feed(Buffer.from("{}", "utf8"));
43
+ assert.equal(more.kind, "negotiated");
44
+ if (more.kind !== "negotiated")
45
+ return;
46
+ assert.equal(more.rest.toString(), "{}");
47
+ });
48
+ it("reassembles a frame split across TCP-sized chunks", () => {
49
+ const gate = new ConnectionHandshake("server");
50
+ const frame = Buffer.from(encodeHandshakeFrame());
51
+ const split = Math.floor(frame.length / 2);
52
+ assert.equal(gate.feed(frame.subarray(0, split)).kind, "pending");
53
+ const outcome = gate.feed(frame.subarray(split));
54
+ assert.equal(outcome.kind, "negotiated");
55
+ });
56
+ it("classifies a JSON-first-byte connection as legacy and passes bytes through", () => {
57
+ const gate = new ConnectionHandshake("server");
58
+ const outcome = gate.feed(Buffer.from('{"method":"introduce"}\n', "utf8"));
59
+ assert.equal(outcome.kind, "legacy");
60
+ if (outcome.kind !== "legacy")
61
+ return;
62
+ assert.match(outcome.rest.toString(), /introduce/);
63
+ });
64
+ it("refuses a handshake whose negotiation fails (no shared domain)", () => {
65
+ const gate = new ConnectionHandshake("server");
66
+ const hostile = cborEncode({ type: "handshake", version: 1, domains: ["example.com/other"] }, cdeEncodeOptions);
67
+ const outcome = gate.feed(Buffer.from(hostile));
68
+ assert.equal(outcome.kind, "refused");
69
+ if (outcome.kind !== "refused")
70
+ return;
71
+ assert.match(outcome.reason, /no shared domain/);
72
+ });
73
+ it("refuses a CBOR item that is not a handshake frame", () => {
74
+ const gate = new ConnectionHandshake("server");
75
+ const notAHandshake = cborEncode({ hello: "world" }, cdeEncodeOptions);
76
+ const outcome = gate.feed(Buffer.from(notAHandshake));
77
+ assert.equal(outcome.kind, "refused");
78
+ });
79
+ it("refuses undecodable leading bytes that are neither CBOR maps nor JSON", () => {
80
+ const gate = new ConnectionHandshake("server");
81
+ const outcome = gate.feed(Buffer.from([0xff, 0x00, 0x01]));
82
+ assert.equal(outcome.kind, "refused");
83
+ });
84
+ it("refuses a binary blob far beyond any handshake frame size", () => {
85
+ const gate = new ConnectionHandshake("server");
86
+ const big = Buffer.alloc(2048, 0x61); // 'a' — neither CBOR map head nor '{'
87
+ assert.equal(gate.feed(big).kind, "refused");
88
+ });
89
+ });
90
+ describe("normaliseWireState (#31 direction 2)", () => {
91
+ it("defaults missing deliveryQueues and entity versions for old-build snapshots", () => {
92
+ const legacy = {
93
+ agents: {
94
+ a1: { id: "a1", name: "a", version: undefined },
95
+ },
96
+ rooms: {},
97
+ messages: {},
98
+ dms: {},
99
+ };
100
+ const normalised = normaliseWireState(legacy);
101
+ assert.deepEqual(normalised.deliveryQueues, {});
102
+ assert.equal(normalised.agents.a1.version, 1);
103
+ });
104
+ it("passes a complete modern state through unchanged", () => {
105
+ // Deliberately loose (matching the "legacy" fixture above): this test asserts only the four fields normaliseWireState touches, not a fully valid AgentIdentity/Room for every other field those domain types carry.
106
+ const modern = {
107
+ agents: { a1: { id: "a1", version: 3 } },
108
+ rooms: { r1: { id: "r1", version: 2 } },
109
+ messages: {},
110
+ dms: {},
111
+ deliveryQueues: { a1: [] },
112
+ };
113
+ assert.deepEqual(normaliseWireState(modern), modern);
114
+ });
115
+ });
116
+ // A live gate over a real socket pair: the client frame goes out first; the server classifies on receipt and replies; the client then sees the reply.
117
+ describe("ConnectionHandshake over a real socket pair", () => {
118
+ it("client sends frame first; both sides reach negotiated", async () => {
119
+ const server = net.createServer();
120
+ await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
121
+ const port = server.address().port;
122
+ const serverOutcome = new Promise((resolve) => {
123
+ server.on("connection", (socket) => {
124
+ const gate = new ConnectionHandshake("server");
125
+ socket.on("data", (data) => {
126
+ const outcome = gate.feed(data);
127
+ if (outcome.kind !== "pending") {
128
+ if (outcome.kind === "negotiated") {
129
+ socket.write(encodeHandshakeFrame());
130
+ }
131
+ resolve(outcome.kind);
132
+ }
133
+ });
134
+ });
135
+ });
136
+ const client = net.createConnection({ port, host: "127.0.0.1" });
137
+ const clientGate = new ConnectionHandshake("client");
138
+ const clientOutcome = new Promise((resolve) => {
139
+ client.on("data", (data) => {
140
+ const outcome = clientGate.feed(data);
141
+ if (outcome.kind !== "pending")
142
+ resolve(outcome.kind);
143
+ });
144
+ });
145
+ client.write(encodeHandshakeFrame());
146
+ assert.equal(await serverOutcome, "negotiated");
147
+ assert.equal(await clientOutcome, "negotiated");
148
+ client.destroy();
149
+ server.close();
150
+ });
151
+ it("a legacy peer (no handshake frame) is tolerated: JSON bytes pass straight through both sides", async () => {
152
+ const server = net.createServer();
153
+ await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
154
+ const port = server.address().port;
155
+ const serverReceived = new Promise((resolve, reject) => {
156
+ server.on("connection", (socket) => {
157
+ attachSocketHandshake(socket, "server", (data) => resolve(data.toString()), reject);
158
+ });
159
+ });
160
+ // A pre-#31 peer: writes its JSON line directly, sends no handshake frame at all.
161
+ const client = net.createConnection({ port, host: "127.0.0.1" });
162
+ await new Promise((resolve) => client.on("connect", resolve));
163
+ client.write('{"method":"introduce"}\n');
164
+ assert.match(await serverReceived, /introduce/);
165
+ client.destroy();
166
+ server.close();
167
+ });
168
+ it("an incompatible handshake (no shared domain) is refused loudly: the connection is destroyed rather than desynced", async () => {
169
+ const server = net.createServer();
170
+ await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
171
+ const port = server.address().port;
172
+ const serverError = new Promise((resolve) => {
173
+ server.on("connection", (socket) => {
174
+ attachSocketHandshake(socket, "server", () => {
175
+ throw new Error("payload should never be reached on a refused handshake");
176
+ }, resolve);
177
+ });
178
+ });
179
+ const client = net.createConnection({ port, host: "127.0.0.1" });
180
+ await new Promise((resolve) => client.on("connect", resolve));
181
+ const foreignFrame = cborEncode({
182
+ type: "handshake",
183
+ version: MESH_PROTOCOL_VERSION,
184
+ domains: ["example.com/unrelated-mesh"],
185
+ }, cdeEncodeOptions);
186
+ client.write(Buffer.from(foreignFrame));
187
+ const error = await serverError;
188
+ assert.match(error.message, /no shared domain/);
189
+ await new Promise((resolve) => {
190
+ client.on("close", resolve);
191
+ client.on("error", () => resolve());
192
+ });
193
+ server.close();
194
+ });
195
+ });
196
+ //# sourceMappingURL=handshake.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handshake.test.js","sourceRoot":"","sources":["../../src/test/handshake.test.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-comms",
3
- "version": "1.27.2",
3
+ "version": "1.28.0",
4
4
  "description": "Cross-harness communication mesh for LLM agents — rooms, DMs, presence, and real-time push delivery over TCP",
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@10.33.0",
@@ -52,7 +52,7 @@
52
52
  "generate:server-json": "tsx scripts/sync-release-metadata.ts",
53
53
  "publish:mcp-registry": "tsx scripts/publish-mcp-registry.ts",
54
54
  "lint": "eslint .",
55
- "test": "node --test --test-concurrency=1 dist/test/coordinator-socket-error.integration.test.js dist/test/identity-store.test.js dist/test/identity-cert.test.js dist/test/broadcast-window.integration.test.js dist/test/identity-restart.integration.test.js dist/test/mesh-e2e.integration.test.js dist/test/ws-broadcast-window.integration.test.js dist/test/tls-transport.integration.test.js dist/test/peer-id-verification.integration.test.js dist/test/state-sync-convergence.test.js dist/test/downtime-replay.test.js dist/test/downtime-replay.integration.test.js dist/test/filestore.test.js",
55
+ "test": "node --test --test-concurrency=1 dist/test/coordinator-socket-error.integration.test.js dist/test/identity-store.test.js dist/test/identity-cert.test.js dist/test/broadcast-window.integration.test.js dist/test/identity-restart.integration.test.js dist/test/mesh-e2e.integration.test.js dist/test/ws-broadcast-window.integration.test.js dist/test/tls-transport.integration.test.js dist/test/peer-id-verification.integration.test.js dist/test/become-coordinator-actual-port.integration.test.js dist/test/state-sync-convergence.test.js dist/test/downtime-replay.test.js dist/test/downtime-replay.integration.test.js dist/test/filestore.test.js dist/test/handshake.test.js",
56
56
  "test:visibility": "node --test dist/test/visibility.integration.test.js",
57
57
  "test:delivery": "node dist/test/delivery-receipt.runner.js",
58
58
  "test:federation": "node dist/test/federation.integration.test.js",
@@ -94,7 +94,9 @@
94
94
  "typescript-eslint": "8.69.0"
95
95
  },
96
96
  "dependencies": {
97
+ "@exadev/wire-mesh-core": "github:ExaDev/wire-mesh#path:ts/packages/core",
97
98
  "@modelcontextprotocol/sdk": "1.30.0",
99
+ "cbor2": "2.3.0",
98
100
  "preact": "10.29.7",
99
101
  "typebox": "1.3.6",
100
102
  "ws": "8.21.1",