agent-comms 1.21.1 → 1.22.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.
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "name": "agent-comms",
3
3
  "description": "Cross-harness LLM agent communication mesh — rooms, DMs, and presence",
4
- "version": "1.21.1",
4
+ "version": "1.22.0",
5
5
  "author": {
6
6
  "name": "ExaDev"
7
7
  },
8
8
  "homepage": "https://github.com/ExaDev/agent-comms#readme",
9
9
  "repository": "https://github.com/ExaDev/agent-comms",
10
10
  "license": "MIT",
11
+ "hooks": "./hooks/hooks.json",
11
12
  "mcpServers": {
12
13
  "agent-comms": {
13
14
  "command": "npx",
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![GitHub](https://img.shields.io/badge/GitHub-181717?logo=github&logoColor=white)](https://github.com/ExaDev/agent-comms)
4
4
  [![npm](https://img.shields.io/badge/npm-CB3837?logo=npm&logoColor=white)](https://www.npmjs.com/package/agent-comms)
5
- [![version](https://img.shields.io/badge/version-1.21.1-blue)](https://github.com/ExaDev/agent-comms/releases/tag/v1.21.1)
5
+ [![version](https://img.shields.io/badge/version-1.22.0-blue)](https://github.com/ExaDev/agent-comms/releases/tag/v1.22.0)
6
6
  [![CI](https://img.shields.io/github/actions/workflow/status/ExaDev/agent-comms/ci.yml?branch=main)](https://github.com/ExaDev/agent-comms/actions)
7
7
 
8
8
  Cross-harness communication mesh for LLM agents: rooms, DMs, presence, and visibility over TCP with zero filesystem dependencies.
@@ -217,7 +217,7 @@ agent_comms({ action: "update", visibility: "hidden" })
217
217
 
218
218
  When `streamingBehavior` is absent, each bridge falls back to its existing heuristic: actionable events (DMs, room messages, invites) are treated as `steer`; status changes and membership events are treated as `info`.
219
219
 
220
- **Limitations on non-native harnesses**: Claude Code's channel protocol is a single-lane push there is no runtime mechanism to force a mid-call interrupt. The `[STEER]` and `[FOLLOWUP]` markers are visible in the session and structured `meta.streamingBehavior` carries the intent, but acting on them is down to the receiving agent. The pi bridge honours the hint natively.
220
+ **Claude Code delivery mechanism**: Events are written to `~/.agents/bus/pending/claude-code--<cwd-slug>.jsonl`. Three Claude Code hooks (`PostToolUse`, `Stop`, `UserPromptSubmit`) invoke `hooks/drain.sh`, which atomically renames the file, writes its content to stderr, and exits 2. Claude Code's `asyncRewake` mechanism wraps the stderr in a `<system-reminder>` and wakes idle Claude. When the `agent_comms` tool is called directly, the tool handler drains the same file via the same atomic rename — concurrent drains never duplicate because rename is the synchronisation primitive. The `[STEER]` and `[FOLLOWUP]` markers and `meta.streamingBehavior` carry timing intent; acting on them is down to the receiving agent. The pi bridge honours the hint natively via `deliverAs`.
221
221
 
222
222
  ## Room types
223
223
 
@@ -2,11 +2,14 @@
2
2
  * Agent Comms — Claude Code channel bridge.
3
3
  *
4
4
  * MCP channel server that provides the "agent_comms" tool and pushes
5
- * incoming messages into Claude's context via <channel> events.
5
+ * incoming messages into Claude's context via <channel> events and hooks.
6
6
  * Uses TCP mesh for real-time delivery — no filesystem polling.
7
7
  *
8
8
  * Run via: npx agent-comms bridge claude-code
9
- * Requires: claude --dangerously-load-development-channels
9
+ *
10
+ * Pending events are persisted to ~/.agents/bus/pending/claude-code--<slug>.jsonl
11
+ * so the asyncRewake hook scripts (hooks/drain.sh) can drain them out-of-process
12
+ * and wake idle Claude via exit code 2.
10
13
  */
11
14
  export declare function run(): Promise<void>;
12
15
  //# sourceMappingURL=channel.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../../../src/bridges/claude-code/channel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAwBH,wBAAsB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CA+GzC"}
1
+ {"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../../../src/bridges/claude-code/channel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAgEH,wBAAsB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CAiHzC"}
@@ -2,12 +2,18 @@
2
2
  * Agent Comms — Claude Code channel bridge.
3
3
  *
4
4
  * MCP channel server that provides the "agent_comms" tool and pushes
5
- * incoming messages into Claude's context via <channel> events.
5
+ * incoming messages into Claude's context via <channel> events and hooks.
6
6
  * Uses TCP mesh for real-time delivery — no filesystem polling.
7
7
  *
8
8
  * Run via: npx agent-comms bridge claude-code
9
- * Requires: claude --dangerously-load-development-channels
9
+ *
10
+ * Pending events are persisted to ~/.agents/bus/pending/claude-code--<slug>.jsonl
11
+ * so the asyncRewake hook scripts (hooks/drain.sh) can drain them out-of-process
12
+ * and wake idle Claude via exit code 2.
10
13
  */
14
+ import * as fs from "node:fs";
15
+ import * as os from "node:os";
16
+ import * as path from "node:path";
11
17
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
12
18
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
13
19
  import { MeshStore, CommsTool, buildAction, ensureRegistered, extractStreamingBehavior, formatDeliveryEvent, isActionableEvent, MCP_TOOL_PARAMS, } from "../../core/index.js";
@@ -18,6 +24,34 @@ import { nanoid } from "../../core/nanoid.js";
18
24
  function isRecord(value) {
19
25
  return typeof value === "object" && value !== null && !Array.isArray(value);
20
26
  }
27
+ function isErrnoException(err) {
28
+ return typeof err === "object" && err !== null && "code" in err;
29
+ }
30
+ function pendingFilePath(cwd) {
31
+ const slug = cwd.replace(/[^a-zA-Z0-9]/g, "_");
32
+ return path.join(os.homedir(), ".agents", "bus", "pending", `claude-code--${slug}.jsonl`);
33
+ }
34
+ function appendPending(filePath, line) {
35
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
36
+ fs.appendFileSync(filePath, line + "\n");
37
+ }
38
+ function drainPending(filePath) {
39
+ const drainPath = `${filePath}.draining-${String(process.pid)}-${String(Date.now())}`;
40
+ try {
41
+ fs.renameSync(filePath, drainPath);
42
+ }
43
+ catch (err) {
44
+ if (isErrnoException(err) && err.code === "ENOENT")
45
+ return [];
46
+ throw err;
47
+ }
48
+ const content = fs.readFileSync(drainPath, "utf-8");
49
+ fs.unlinkSync(drainPath);
50
+ return content
51
+ .split("\n")
52
+ .map((l) => l.trim())
53
+ .filter((l) => l.length > 0);
54
+ }
21
55
  export async function run() {
22
56
  const identity = generateIdentity();
23
57
  const store = new MeshStore();
@@ -25,19 +59,21 @@ export async function run() {
25
59
  store.setTransport(new TlsTransport(store.events, identity));
26
60
  const tool = new CommsTool(store, store.discovery);
27
61
  let agentId;
28
- const informationalBuffer = [];
62
+ const pendingFile = pendingFilePath(process.cwd());
29
63
  const mcp = new McpServer({ name: "agent-comms", version: "0.2.0" }, {
30
64
  capabilities: {
31
65
  experimental: { "claude/channel": {} },
32
66
  },
33
67
  });
34
- // Actionable events with a non-info hint push immediately as channel
35
- // notifications. Everything else (informational system events, or messages
36
- // the sender flagged as info) buffers and drains on the next tool call.
68
+ // All events are written to the pending file so the out-of-process hook
69
+ // drain script can surface them to idle Claude via asyncRewake exit 2.
70
+ // Actionable events also get an eager channel push for mid-turn delivery
71
+ // when channels are enabled (--dangerously-load-development-channels).
37
72
  store.onDelivery = async (_targetId, event) => {
38
73
  const line = formatDeliveryEvent(event);
39
74
  const hint = extractStreamingBehavior(event);
40
75
  const shouldPush = isActionableEvent(event) && hint !== "info";
76
+ appendPending(pendingFile, line);
41
77
  if (shouldPush) {
42
78
  await mcp.server.notification({
43
79
  method: "notifications/claude/channel",
@@ -47,9 +83,6 @@ export async function run() {
47
83
  },
48
84
  });
49
85
  }
50
- else {
51
- informationalBuffer.push(line);
52
- }
53
86
  };
54
87
  // -----------------------------------------------------------------------
55
88
  // Tool registration
@@ -59,7 +92,7 @@ export async function run() {
59
92
  "Cross-harness agent communication mesh. Actions:",
60
93
  "register, update, whoami, create_room, list_rooms, join_room, leave_room,",
61
94
  "send, dm, list_agents, read_room, invite, decline_invite, kick, destroy_room.",
62
- 'Incoming messages appear as <channel source="agent-comms"> events.',
95
+ 'Incoming messages appear as <channel source="agent-comms"> events or [comms] Pending prefix.',
63
96
  "Use streamingBehavior on send/dm: steer (act now), followUp (act when idle), info (whenever, default).",
64
97
  ].join(" "),
65
98
  inputSchema: MCP_TOOL_PARAMS,
@@ -85,7 +118,7 @@ export async function run() {
85
118
  cwd: process.cwd(),
86
119
  pid: process.pid,
87
120
  }, action);
88
- const pending = informationalBuffer.splice(0);
121
+ const pending = drainPending(pendingFile);
89
122
  const prefix = pending.length > 0
90
123
  ? `[comms] Pending:\n${pending.map((l) => ` 📬 ${l}`).join("\n")}\n\n`
91
124
  : "";
@@ -1 +1 @@
1
- {"version":3,"file":"channel.js","sourceRoot":"","sources":["../../../src/bridges/claude-code/channel.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"channel.js","sourceRoot":"","sources":["../../../src/bridges/claude-code/channel.ts"],"names":[],"mappings":"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"}
package/hooks/drain.sh ADDED
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env bash
2
+ # Drain pending agent-comms events and exit 2 to wake idle Claude via asyncRewake.
3
+ #
4
+ # Called by Claude Code hooks (PostToolUse, Stop). If there are pending events,
5
+ # writes them to stderr and exits 2 — Claude Code wraps the stderr in a
6
+ # <system-reminder> and enqueues it as a task-notification, waking idle Claude.
7
+ #
8
+ # Uses atomic rename to drain so concurrent drains (in-process tool drain vs
9
+ # this out-of-process hook) never duplicate or lose events.
10
+
11
+ set -euo pipefail
12
+
13
+ SLUG="${PWD//[^a-zA-Z0-9]/_}"
14
+ PENDING="$HOME/.agents/bus/pending/claude-code--${SLUG}.jsonl"
15
+ DRAINING="${PENDING}.draining-$$-$(date +%s%N 2>/dev/null || date +%s)"
16
+
17
+ # Atomic drain — if rename fails (file absent), nothing to surface.
18
+ if ! mv "$PENDING" "$DRAINING" 2>/dev/null; then
19
+ exit 0
20
+ fi
21
+
22
+ CONTENT=$(cat "$DRAINING")
23
+ rm -f "$DRAINING"
24
+
25
+ if [ -z "$CONTENT" ]; then
26
+ exit 0
27
+ fi
28
+
29
+ echo "Pending agent-comms messages:" >&2
30
+ while IFS= read -r line; do
31
+ [ -n "$line" ] && echo " 📬 $line" >&2
32
+ done <<< "$CONTENT"
33
+
34
+ exit 2
@@ -0,0 +1,40 @@
1
+ {
2
+ "PostToolUse": [
3
+ {
4
+ "matcher": "*",
5
+ "hooks": [
6
+ {
7
+ "type": "command",
8
+ "command": "${CLAUDE_PLUGIN_ROOT}/hooks/drain.sh",
9
+ "asyncRewake": true,
10
+ "timeout": 5
11
+ }
12
+ ]
13
+ }
14
+ ],
15
+ "Stop": [
16
+ {
17
+ "matcher": "*",
18
+ "hooks": [
19
+ {
20
+ "type": "command",
21
+ "command": "${CLAUDE_PLUGIN_ROOT}/hooks/drain.sh",
22
+ "asyncRewake": true,
23
+ "timeout": 5
24
+ }
25
+ ]
26
+ }
27
+ ],
28
+ "UserPromptSubmit": [
29
+ {
30
+ "matcher": "*",
31
+ "hooks": [
32
+ {
33
+ "type": "command",
34
+ "command": "${CLAUDE_PLUGIN_ROOT}/hooks/drain.sh",
35
+ "timeout": 5
36
+ }
37
+ ]
38
+ }
39
+ ]
40
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-comms",
3
- "version": "1.21.1",
3
+ "version": "1.22.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",
@@ -34,7 +34,8 @@
34
34
  },
35
35
  "files": [
36
36
  "dist",
37
- ".claude-plugin/"
37
+ ".claude-plugin/",
38
+ "hooks/"
38
39
  ],
39
40
  "bin": {
40
41
  "agent-comms": "dist/cli.js"