agent-comms 8.2.0 → 8.3.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 (66) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.md +15 -1
  4. package/dist/bridges/mcp/server.d.ts +13 -1
  5. package/dist/bridges/mcp/server.d.ts.map +1 -1
  6. package/dist/bridges/mcp/server.js +7 -4
  7. package/dist/bridges/mcp/server.js.map +1 -1
  8. package/dist/bridges/user/controller.d.ts +3 -0
  9. package/dist/bridges/user/controller.d.ts.map +1 -1
  10. package/dist/bridges/user/controller.js +4 -0
  11. package/dist/bridges/user/controller.js.map +1 -1
  12. package/dist/bridges/user/web/dist/bundle.js +1 -1
  13. package/dist/bridges/user/web/dist/sw.js +1 -1
  14. package/dist/bridges/user/web/frontend/boot-logic.d.ts +9 -8
  15. package/dist/bridges/user/web/frontend/boot-logic.d.ts.map +1 -1
  16. package/dist/bridges/user/web/frontend/boot-logic.js +9 -12
  17. package/dist/bridges/user/web/frontend/boot-logic.js.map +1 -1
  18. package/dist/bridges/user/web/frontend/main.js +3 -6
  19. package/dist/bridges/user/web/frontend/main.js.map +1 -1
  20. package/dist/bridges/user/web/frontend/mesh-client.d.ts.map +1 -1
  21. package/dist/bridges/user/web/frontend/mesh-client.js +3 -4
  22. package/dist/bridges/user/web/frontend/mesh-client.js.map +1 -1
  23. package/dist/bridges/user/web/frontend/served-by-bridge.d.ts +10 -0
  24. package/dist/bridges/user/web/frontend/served-by-bridge.d.ts.map +1 -0
  25. package/dist/bridges/user/web/frontend/served-by-bridge.js +10 -0
  26. package/dist/bridges/user/web/frontend/served-by-bridge.js.map +1 -0
  27. package/dist/bridges/user/web/server.d.ts +12 -0
  28. package/dist/bridges/user/web/server.d.ts.map +1 -1
  29. package/dist/bridges/user/web/server.js +90 -11
  30. package/dist/bridges/user/web/server.js.map +1 -1
  31. package/dist/bridges/user/web/test/lan-web-server.integration.test.d.ts +7 -0
  32. package/dist/bridges/user/web/test/lan-web-server.integration.test.d.ts.map +1 -0
  33. package/dist/bridges/user/web/test/lan-web-server.integration.test.js +245 -0
  34. package/dist/bridges/user/web/test/lan-web-server.integration.test.js.map +1 -0
  35. package/dist/bridges/user/web/test/web-access.unit.test.d.ts +5 -0
  36. package/dist/bridges/user/web/test/web-access.unit.test.d.ts.map +1 -0
  37. package/dist/bridges/user/web/test/web-access.unit.test.js +271 -0
  38. package/dist/bridges/user/web/test/web-access.unit.test.js.map +1 -0
  39. package/dist/bridges/user/web/test/web-beacon.unit.test.d.ts +5 -0
  40. package/dist/bridges/user/web/test/web-beacon.unit.test.d.ts.map +1 -0
  41. package/dist/bridges/user/web/test/web-beacon.unit.test.js +40 -0
  42. package/dist/bridges/user/web/test/web-beacon.unit.test.js.map +1 -0
  43. package/dist/bridges/user/web/web-access.d.ts +79 -0
  44. package/dist/bridges/user/web/web-access.d.ts.map +1 -0
  45. package/dist/bridges/user/web/web-access.js +262 -0
  46. package/dist/bridges/user/web/web-access.js.map +1 -0
  47. package/dist/bridges/user/web/web-beacon.d.ts +27 -0
  48. package/dist/bridges/user/web/web-beacon.d.ts.map +1 -0
  49. package/dist/bridges/user/web/web-beacon.js +45 -0
  50. package/dist/bridges/user/web/web-beacon.js.map +1 -0
  51. package/dist/core/first-contact.d.ts +2 -0
  52. package/dist/core/first-contact.d.ts.map +1 -1
  53. package/dist/core/first-contact.js +1 -1
  54. package/dist/core/first-contact.js.map +1 -1
  55. package/dist/core/index.d.ts +1 -1
  56. package/dist/core/index.d.ts.map +1 -1
  57. package/dist/core/index.js.map +1 -1
  58. package/dist/test/mcp-bridge.runner.d.ts +5 -0
  59. package/dist/test/mcp-bridge.runner.d.ts.map +1 -0
  60. package/dist/test/mcp-bridge.runner.js +25 -0
  61. package/dist/test/mcp-bridge.runner.js.map +1 -0
  62. package/dist/test/mcp-stdout-channel.integration.test.d.ts +5 -0
  63. package/dist/test/mcp-stdout-channel.integration.test.d.ts.map +1 -0
  64. package/dist/test/mcp-stdout-channel.integration.test.js +116 -0
  65. package/dist/test/mcp-stdout-channel.integration.test.js.map +1 -0
  66. package/package.json +1 -1
@@ -0,0 +1,116 @@
1
+ /**
2
+ * stdout is the MCP channel (agent-comms#348): with stdin piped, the bridge must write nothing to it that is not a JSON-RPC message, or a strictly framed client rejects the stream. Diagnostics, including the web UI banner, belong on stderr.
3
+ */
4
+ import { afterEach, expect, it } from "vitest";
5
+ import * as child_process from "node:child_process";
6
+ import * as fs from "node:fs";
7
+ import { tmpdir } from "node:os";
8
+ import * as path from "node:path";
9
+ import * as readline from "node:readline";
10
+ import { fileURLToPath } from "node:url";
11
+ import { freeLocalPort, TeardownStack, unreachableHubUrl, } from "./hub-helpers.js";
12
+ const cleanups = new TeardownStack();
13
+ afterEach(async () => {
14
+ await cleanups.run();
15
+ });
16
+ const RUNNER = path.join(path.dirname(fileURLToPath(import.meta.url)), "mcp-bridge.runner.ts");
17
+ const INITIALIZE_ID = 1;
18
+ const TOOLS_LIST_ID = 2;
19
+ const MCP_PROTOCOL_VERSION = "2025-06-18";
20
+ /** Startup includes a real store init and web server start in a fresh process, so the wait is generous; the test's own timeout is the backstop. */
21
+ const RESPONSE_TIMEOUT_MS = 25_000;
22
+ function jsonRpcLine(message) {
23
+ return `${JSON.stringify({ jsonrpc: "2.0", ...message })}\n`;
24
+ }
25
+ function isJsonRpcMessage(value) {
26
+ return (typeof value === "object" &&
27
+ value !== null &&
28
+ "jsonrpc" in value &&
29
+ value.jsonrpc === "2.0");
30
+ }
31
+ it("writes only JSON-RPC messages to stdout and puts the web UI banner on stderr", async () => {
32
+ const slotDir = fs.mkdtempSync(path.join(tmpdir(), "agent-comms-mcp-test-"));
33
+ cleanups.push(async () => {
34
+ fs.rmSync(slotDir, { recursive: true, force: true });
35
+ });
36
+ const child = child_process.spawn(process.execPath, [
37
+ "--import",
38
+ "tsx",
39
+ RUNNER,
40
+ JSON.stringify({
41
+ coordinatorPort: await freeLocalPort(),
42
+ firstContactPort: await freeLocalPort(),
43
+ hubUrl: await unreachableHubUrl(),
44
+ slotDir,
45
+ }),
46
+ ], { stdio: ["pipe", "pipe", "pipe"] });
47
+ const exited = new Promise((resolve) => {
48
+ child.once("exit", () => {
49
+ resolve();
50
+ });
51
+ });
52
+ cleanups.push(async () => {
53
+ child.kill("SIGTERM");
54
+ await exited;
55
+ });
56
+ const stdoutLines = [];
57
+ let stderr = "";
58
+ child.stderr.on("data", (chunk) => {
59
+ stderr += chunk.toString();
60
+ });
61
+ const answered = new Set();
62
+ const BANNER = "Agent Comms web UI: http://127.0.0.1:";
63
+ let notifyStderr = () => undefined;
64
+ child.stderr.on("data", () => {
65
+ notifyStderr();
66
+ });
67
+ const bothAnsweredWithBanner = new Promise((resolve, reject) => {
68
+ const timer = setTimeout(() => {
69
+ reject(new Error(`no JSON-RPC responses and stderr banner within the timeout; stdout=${JSON.stringify(stdoutLines)} stderr=${stderr}`));
70
+ }, RESPONSE_TIMEOUT_MS);
71
+ // stdout and stderr are separate pipes, so the parent can see the responses before the banner written earlier: completion needs both.
72
+ const settleIfComplete = () => {
73
+ if (answered.has(INITIALIZE_ID) &&
74
+ answered.has(TOOLS_LIST_ID) &&
75
+ stderr.includes(BANNER)) {
76
+ clearTimeout(timer);
77
+ resolve();
78
+ }
79
+ };
80
+ notifyStderr = settleIfComplete;
81
+ readline.createInterface({ input: child.stdout }).on("line", (line) => {
82
+ stdoutLines.push(line);
83
+ try {
84
+ const parsed = JSON.parse(line);
85
+ if (typeof parsed === "object" &&
86
+ parsed !== null &&
87
+ "id" in parsed &&
88
+ typeof parsed.id === "number") {
89
+ answered.add(parsed.id);
90
+ }
91
+ }
92
+ catch {
93
+ // A non-JSON line is recorded above and fails the assertion below; the wait then ends at the timeout or the next response.
94
+ }
95
+ settleIfComplete();
96
+ });
97
+ });
98
+ child.stdin.write(jsonRpcLine({
99
+ id: INITIALIZE_ID,
100
+ method: "initialize",
101
+ params: {
102
+ protocolVersion: MCP_PROTOCOL_VERSION,
103
+ capabilities: {},
104
+ clientInfo: { name: "stdout-channel-test", version: "0.0.0" },
105
+ },
106
+ }));
107
+ child.stdin.write(jsonRpcLine({ method: "notifications/initialized" }));
108
+ child.stdin.write(jsonRpcLine({ id: TOOLS_LIST_ID, method: "tools/list" }));
109
+ await bothAnsweredWithBanner;
110
+ expect(stdoutLines.length).toBeGreaterThanOrEqual(2);
111
+ for (const line of stdoutLines) {
112
+ expect(isJsonRpcMessage(JSON.parse(line))).toBe(true);
113
+ }
114
+ expect(stderr).toContain(BANNER);
115
+ });
116
+ //# sourceMappingURL=mcp-stdout-channel.integration.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-stdout-channel.integration.test.js","sourceRoot":"","sources":["../../src/test/mcp-stdout-channel.integration.test.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC/C,OAAO,KAAK,aAAa,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EACL,aAAa,EACb,aAAa,EACb,iBAAiB,GAClB,MAAM,kBAAkB,CAAC;AAE1B,MAAM,QAAQ,GAAG,IAAI,aAAa,EAAE,CAAC;AAErC,SAAS,CAAC,KAAK,IAAI,EAAE;IACnB,MAAM,QAAQ,CAAC,GAAG,EAAE,CAAC;AACvB,CAAC,CAAC,CAAC;AAEH,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CACtB,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAC5C,sBAAsB,CACvB,CAAC;AAEF,MAAM,aAAa,GAAG,CAAC,CAAC;AACxB,MAAM,aAAa,GAAG,CAAC,CAAC;AACxB,MAAM,oBAAoB,GAAG,YAAY,CAAC;AAE1C,mJAAmJ;AACnJ,MAAM,mBAAmB,GAAG,MAAM,CAAC;AAEnC,SAAS,WAAW,CAAC,OAAgC;IACnD,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,OAAO,EAAE,CAAC,IAAI,CAAC;AAC/D,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAc;IACtC,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,SAAS,IAAI,KAAK;QAClB,KAAK,CAAC,OAAO,KAAK,KAAK,CACxB,CAAC;AACJ,CAAC;AAED,EAAE,CAAC,8EAA8E,EAAE,KAAK,IAAI,EAAE;IAC5F,MAAM,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,uBAAuB,CAAC,CAAC,CAAC;IAC7E,QAAQ,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE;QACvB,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IACH,MAAM,KAAK,GAAG,aAAa,CAAC,KAAK,CAC/B,OAAO,CAAC,QAAQ,EAChB;QACE,UAAU;QACV,KAAK;QACL,MAAM;QACN,IAAI,CAAC,SAAS,CAAC;YACb,eAAe,EAAE,MAAM,aAAa,EAAE;YACtC,gBAAgB,EAAE,MAAM,aAAa,EAAE;YACvC,MAAM,EAAE,MAAM,iBAAiB,EAAE;YACjC,OAAO;SACR,CAAC;KACH,EACD,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CACpC,CAAC;IACF,MAAM,MAAM,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QAC3C,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE;YACtB,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,QAAQ,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE;QACvB,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACtB,MAAM,MAAM,CAAC;IACf,CAAC,CAAC,CAAC;IAEH,MAAM,WAAW,GAAa,EAAE,CAAC;IACjC,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;QACxC,MAAM,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;IAC7B,CAAC,CAAC,CAAC;IACH,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IACnC,MAAM,MAAM,GAAG,uCAAuC,CAAC;IACvD,IAAI,YAAY,GAAe,GAAG,EAAE,CAAC,SAAS,CAAC;IAC/C,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE;QAC3B,YAAY,EAAE,CAAC;IACjB,CAAC,CAAC,CAAC;IACH,MAAM,sBAAsB,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACnE,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,MAAM,CACJ,IAAI,KAAK,CACP,sEAAsE,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,WAAW,MAAM,EAAE,CACrH,CACF,CAAC;QACJ,CAAC,EAAE,mBAAmB,CAAC,CAAC;QACxB,sIAAsI;QACtI,MAAM,gBAAgB,GAAG,GAAS,EAAE;YAClC,IACE,QAAQ,CAAC,GAAG,CAAC,aAAa,CAAC;gBAC3B,QAAQ,CAAC,GAAG,CAAC,aAAa,CAAC;gBAC3B,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EACvB,CAAC;gBACD,YAAY,CAAC,KAAK,CAAC,CAAC;gBACpB,OAAO,EAAE,CAAC;YACZ,CAAC;QACH,CAAC,CAAC;QACF,YAAY,GAAG,gBAAgB,CAAC;QAChC,QAAQ,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;YACpE,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACvB,IAAI,CAAC;gBACH,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBACzC,IACE,OAAO,MAAM,KAAK,QAAQ;oBAC1B,MAAM,KAAK,IAAI;oBACf,IAAI,IAAI,MAAM;oBACd,OAAO,MAAM,CAAC,EAAE,KAAK,QAAQ,EAC7B,CAAC;oBACD,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gBAC1B,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,2HAA2H;YAC7H,CAAC;YACD,gBAAgB,EAAE,CAAC;QACrB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,KAAK,CAAC,KAAK,CAAC,KAAK,CACf,WAAW,CAAC;QACV,EAAE,EAAE,aAAa;QACjB,MAAM,EAAE,YAAY;QACpB,MAAM,EAAE;YACN,eAAe,EAAE,oBAAoB;YACrC,YAAY,EAAE,EAAE;YAChB,UAAU,EAAE,EAAE,IAAI,EAAE,qBAAqB,EAAE,OAAO,EAAE,OAAO,EAAE;SAC9D;KACF,CAAC,CACH,CAAC;IACF,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,2BAA2B,EAAE,CAAC,CAAC,CAAC;IACxE,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,aAAa,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC;IAC5E,MAAM,sBAAsB,CAAC;IAE7B,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;IACrD,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxD,CAAC;IACD,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;AACnC,CAAC,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "agent-comms",
3
3
  "description": "Cross-harness communication mesh for LLM agents — rooms, DMs, presence, and real-time push delivery over TCP",
4
- "version": "8.2.0",
4
+ "version": "8.3.0",
5
5
  "bin": {
6
6
  "agent-comms": "dist/cli.js"
7
7
  },