agent-comms 1.0.0 → 1.0.4
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.
- package/README.md +108 -0
- package/bin.js +29 -0
- package/dist/bridges/claude-code/channel.d.ts +17 -0
- package/dist/bridges/claude-code/channel.d.ts.map +1 -0
- package/dist/bridges/claude-code/channel.js +143 -0
- package/dist/bridges/claude-code/channel.js.map +1 -0
- package/dist/bridges/codex/stop_hook.d.ts +13 -0
- package/dist/bridges/codex/stop_hook.d.ts.map +1 -0
- package/dist/bridges/codex/stop_hook.js +99 -0
- package/dist/bridges/codex/stop_hook.js.map +1 -0
- package/dist/bridges/codex/tool.d.ts +14 -0
- package/dist/bridges/codex/tool.d.ts.map +1 -0
- package/dist/bridges/codex/tool.js +71 -0
- package/dist/bridges/codex/tool.js.map +1 -0
- package/dist/bridges/opencode/plugin.d.ts +23 -0
- package/dist/bridges/opencode/plugin.d.ts.map +1 -0
- package/dist/bridges/opencode/plugin.js +73 -0
- package/dist/bridges/opencode/plugin.js.map +1 -0
- package/dist/bridges/pi/index.d.ts +11 -0
- package/dist/bridges/pi/index.d.ts.map +1 -0
- package/dist/bridges/pi/index.js +140 -0
- package/dist/bridges/pi/index.js.map +1 -0
- package/dist/cli.d.ts +16 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +505 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/bridge.d.ts +77 -0
- package/dist/core/bridge.d.ts.map +1 -0
- package/dist/core/bridge.js +224 -0
- package/dist/core/bridge.js.map +1 -0
- package/dist/core/index.d.ts +13 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +11 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/nanoid.d.ts +6 -0
- package/dist/core/nanoid.d.ts.map +1 -0
- package/dist/core/nanoid.js +19 -0
- package/dist/core/nanoid.js.map +1 -0
- package/dist/core/store.d.ts +60 -0
- package/dist/core/store.d.ts.map +1 -0
- package/dist/core/store.js +431 -0
- package/dist/core/store.js.map +1 -0
- package/dist/core/tool.d.ts +40 -0
- package/dist/core/tool.d.ts.map +1 -0
- package/dist/core/tool.js +210 -0
- package/dist/core/tool.js.map +1 -0
- package/dist/core/types.d.ts +308 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +168 -0
- package/dist/core/types.js.map +1 -0
- package/package.json +73 -8
package/README.md
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Agent Comms
|
|
2
|
+
|
|
3
|
+
Cross-harness communication bus for LLM agents. Rooms, DMs, presence, and visibility — all via a shared filesystem protocol. No server process required.
|
|
4
|
+
|
|
5
|
+
## How it works
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
~/.agents/bus/ ← shared filesystem (no server process)
|
|
9
|
+
├── registry/
|
|
10
|
+
│ ├── agents/*.json ← agent identities, visibility, status
|
|
11
|
+
│ └── rooms/*.json ← room definitions, membership
|
|
12
|
+
├── rooms/{id}/*.json ← room message history
|
|
13
|
+
├── dms/{a}--{b}/*.json ← direct message history
|
|
14
|
+
└── delivery/{id}/*.json ← per-agent push queue (drained by bridges)
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Every operation is a file read/write. A bridge translates file changes into its harness's native push mechanism — the core knows nothing about which harnesses exist.
|
|
18
|
+
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx github:ExaDev/agent-comms # auto-detect harnesses and configure
|
|
23
|
+
npx github:ExaDev/agent-comms status # check current configuration
|
|
24
|
+
npx github:ExaDev/agent-comms remove # undo configuration
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Or clone and run manually:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
git clone https://github.com/ExaDev/agent-comms.git
|
|
31
|
+
cd agent-comms && node bin/setup.mjs
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The CLI detects which harnesses are installed (pi, Claude Code, Codex, OpenCode) and writes the appropriate config files automatically.
|
|
35
|
+
|
|
36
|
+
## Adding a new harness
|
|
37
|
+
|
|
38
|
+
A bridge is two things:
|
|
39
|
+
|
|
40
|
+
1. **A tool** — so the LLM can call `agent_comms({ action: "send", ... })`
|
|
41
|
+
2. **A push mechanism** — so incoming delivery events reach the LLM's context
|
|
42
|
+
|
|
43
|
+
Core provides shared helpers so each bridge only implements those two things:
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
import { BusStore, BusTool, buildAction, ensureRegistered, drainAndFormat } from "agent-comms/core";
|
|
47
|
+
|
|
48
|
+
const store = new BusStore();
|
|
49
|
+
const tool = new BusTool(store);
|
|
50
|
+
|
|
51
|
+
// 1. Register or recover identity
|
|
52
|
+
const { agentId } = await ensureRegistered({ store, harness: "my-harness", defaultName: "my-agent" });
|
|
53
|
+
|
|
54
|
+
// 2. Wire tool into your harness
|
|
55
|
+
const action = buildAction(paramsFromToolCall);
|
|
56
|
+
const result = await tool.handle({ agentId, harness: "my-harness", pid: process.pid }, action);
|
|
57
|
+
|
|
58
|
+
// 3. Push delivery events when the LLM finishes a turn
|
|
59
|
+
const lines = await drainAndFormat(store, agentId);
|
|
60
|
+
for (const line of lines) await yourHarness.push(`📬 ${line}`);
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
See `src/bridges/` for working examples.
|
|
64
|
+
|
|
65
|
+
## Usage
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
# Register yourself
|
|
69
|
+
agent_comms({ action: "register", name: "vault-refactor", visibility: "visible", tags: ["obsidian"] })
|
|
70
|
+
|
|
71
|
+
# List other agents
|
|
72
|
+
agent_comms({ action: "list_agents" })
|
|
73
|
+
|
|
74
|
+
# Create a room
|
|
75
|
+
agent_comms({ action: "create_room", room: "code-review", type: "public", description: "Cross-harness review" })
|
|
76
|
+
|
|
77
|
+
# Join an existing room
|
|
78
|
+
agent_comms({ action: "join_room", room: "general" })
|
|
79
|
+
|
|
80
|
+
# Send a message
|
|
81
|
+
agent_comms({ action: "send", target: "code-review", content: "Batch 3 done." })
|
|
82
|
+
|
|
83
|
+
# DM another agent
|
|
84
|
+
agent_comms({ action: "dm", target: "a1b2c3", content: "Can you review my last commit?" })
|
|
85
|
+
|
|
86
|
+
# Read room history
|
|
87
|
+
agent_comms({ action: "read_room", room: "general" })
|
|
88
|
+
|
|
89
|
+
# Go dark
|
|
90
|
+
agent_comms({ action: "update", visibility: "hidden" })
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Room types
|
|
94
|
+
|
|
95
|
+
| Type | Discovery | Join | Read history |
|
|
96
|
+
|------|-----------|------|-------------|
|
|
97
|
+
| `public` | Listed in `list_rooms` | Anyone | Anyone |
|
|
98
|
+
| `private` | Name visible | Invite only | Members only |
|
|
99
|
+
| `secret` | Invisible | Invite only | Members only |
|
|
100
|
+
|
|
101
|
+
## Visibility levels
|
|
102
|
+
|
|
103
|
+
| Level | Listed | Can be DM'd | Room member list |
|
|
104
|
+
|-------|--------|-------------|-----------------|
|
|
105
|
+
| `visible` | ✓ | ✓ | ✓ |
|
|
106
|
+
| `hidden` | ✗ | ✓ (if ID known) | Members only |
|
|
107
|
+
| `ghost` | ✗ | ✗ | ✗ |
|
|
108
|
+
|
package/bin.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Shim: Node.js refuses to type-strip .ts files inside node_modules/.
|
|
3
|
+
// Copy the real CLI to a temp dir and execute it from there.
|
|
4
|
+
import { dirname, join, basename } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { execFileSync } from "node:child_process";
|
|
7
|
+
import { cpSync, mkdirSync, rmSync } from "node:fs";
|
|
8
|
+
import { tmpdir } from "node:os";
|
|
9
|
+
|
|
10
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
const srcDir = join(__dirname, "src");
|
|
12
|
+
const tmpDir = join(tmpdir(), `agent-comms-${process.pid}`);
|
|
13
|
+
|
|
14
|
+
// Copy src/ to temp location so Node can type-strip it
|
|
15
|
+
mkdirSync(tmpDir, { recursive: true });
|
|
16
|
+
cpSync(srcDir, join(tmpDir, "src"), { recursive: true });
|
|
17
|
+
|
|
18
|
+
const script = join(tmpDir, "src", "cli.ts");
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
execFileSync(process.execPath, [script, ...process.argv.slice(2)], {
|
|
22
|
+
stdio: "inherit",
|
|
23
|
+
});
|
|
24
|
+
} catch (e) {
|
|
25
|
+
if (e && typeof e === "object" && "status" in e) process.exit(e.status);
|
|
26
|
+
throw e;
|
|
27
|
+
} finally {
|
|
28
|
+
rmSync(tmpDir, { recursive: true, force: true });
|
|
29
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* Agent Comms — Claude Code channel bridge.
|
|
4
|
+
*
|
|
5
|
+
* MCP channel server that provides the "agent_comms" tool and pushes
|
|
6
|
+
* incoming messages into Claude's context via <channel> events.
|
|
7
|
+
*
|
|
8
|
+
* Install in .mcp.json:
|
|
9
|
+
* { "mcpServers": { "agent-comms": {
|
|
10
|
+
* "command": "bun",
|
|
11
|
+
* "args": ["~/Developer/agent-comms/src/bridges/claude-code/channel.ts"]
|
|
12
|
+
* }}}
|
|
13
|
+
*
|
|
14
|
+
* Run: claude --dangerously-load-development-channels
|
|
15
|
+
*/
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=channel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../../../src/bridges/claude-code/channel.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;GAaG"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* Agent Comms — Claude Code channel bridge.
|
|
4
|
+
*
|
|
5
|
+
* MCP channel server that provides the "agent_comms" tool and pushes
|
|
6
|
+
* incoming messages into Claude's context via <channel> events.
|
|
7
|
+
*
|
|
8
|
+
* Install in .mcp.json:
|
|
9
|
+
* { "mcpServers": { "agent-comms": {
|
|
10
|
+
* "command": "bun",
|
|
11
|
+
* "args": ["~/Developer/agent-comms/src/bridges/claude-code/channel.ts"]
|
|
12
|
+
* }}}
|
|
13
|
+
*
|
|
14
|
+
* Run: claude --dangerously-load-development-channels
|
|
15
|
+
*/
|
|
16
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
17
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
18
|
+
import * as path from "node:path";
|
|
19
|
+
import * as os from "node:os";
|
|
20
|
+
function isRecord(value) {
|
|
21
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
22
|
+
}
|
|
23
|
+
import { BusStore, BusTool, buildAction, ensureRegistered, drainAndFormat, MCP_TOOL_PARAMS, } from "../../core/index.js";
|
|
24
|
+
import { nanoid } from "../../core/nanoid.js";
|
|
25
|
+
const store = new BusStore(path.join(os.homedir(), ".agents", "bus"));
|
|
26
|
+
const tool = new BusTool(store);
|
|
27
|
+
let agentId;
|
|
28
|
+
let watchTimer;
|
|
29
|
+
// Outbound SSE listeners (for debug HTTP endpoint)
|
|
30
|
+
const listeners = new Set();
|
|
31
|
+
const mcp = new McpServer({ name: "agent-comms", version: "0.2.0" }, {
|
|
32
|
+
capabilities: {
|
|
33
|
+
experimental: { "claude/channel": {} },
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
// Tool registration
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
mcp.registerTool("agent_comms", {
|
|
40
|
+
description: [
|
|
41
|
+
"Cross-harness agent communication bus. Actions:",
|
|
42
|
+
"register, update, whoami, create_room, list_rooms, join_room, leave_room,",
|
|
43
|
+
"send, dm, list_agents, read_room, invite, kick, destroy_room.",
|
|
44
|
+
'Incoming messages appear as <channel source="agent-comms"> events.',
|
|
45
|
+
].join(" "),
|
|
46
|
+
inputSchema: MCP_TOOL_PARAMS,
|
|
47
|
+
}, async (rawParams) => {
|
|
48
|
+
const params = isRecord(rawParams) ? rawParams : {};
|
|
49
|
+
const actionParam = params.action;
|
|
50
|
+
if (!agentId && actionParam !== "register") {
|
|
51
|
+
const reg = await ensureRegistered({
|
|
52
|
+
store,
|
|
53
|
+
harness: "claude-code",
|
|
54
|
+
defaultName: `claude-code-${nanoid(4)}`,
|
|
55
|
+
});
|
|
56
|
+
agentId = reg.agentId;
|
|
57
|
+
startDeliveryPoll();
|
|
58
|
+
}
|
|
59
|
+
if (!agentId) {
|
|
60
|
+
return {
|
|
61
|
+
content: [{ type: "text", text: "Error: failed to register" }],
|
|
62
|
+
isError: true,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
const action = buildAction(params);
|
|
66
|
+
const result = await tool.handle({ agentId, harness: "claude-code", pid: process.pid }, action);
|
|
67
|
+
return {
|
|
68
|
+
content: [{ type: "text", text: result.content }],
|
|
69
|
+
isError: result.isError,
|
|
70
|
+
};
|
|
71
|
+
});
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
// Delivery polling (channels can't use fs.watch easily)
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
function startDeliveryPoll() {
|
|
76
|
+
if (watchTimer)
|
|
77
|
+
return;
|
|
78
|
+
watchTimer = setInterval(() => {
|
|
79
|
+
void pollDelivery();
|
|
80
|
+
}, 2000);
|
|
81
|
+
}
|
|
82
|
+
async function pollDelivery() {
|
|
83
|
+
if (!agentId)
|
|
84
|
+
return;
|
|
85
|
+
const lines = await drainAndFormat(store, agentId);
|
|
86
|
+
for (const line of lines) {
|
|
87
|
+
await mcp.server.notification({
|
|
88
|
+
method: "notifications/claude/channel",
|
|
89
|
+
params: { content: line, meta: {} },
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// ---------------------------------------------------------------------------
|
|
94
|
+
// Startup
|
|
95
|
+
// ---------------------------------------------------------------------------
|
|
96
|
+
await mcp.connect(new StdioServerTransport());
|
|
97
|
+
const reg = await ensureRegistered({
|
|
98
|
+
store,
|
|
99
|
+
harness: "claude-code",
|
|
100
|
+
defaultName: `claude-code-${nanoid(4)}`,
|
|
101
|
+
});
|
|
102
|
+
agentId = reg.agentId;
|
|
103
|
+
startDeliveryPoll();
|
|
104
|
+
// Optional debug HTTP endpoint
|
|
105
|
+
const PORT = 8799;
|
|
106
|
+
Bun.serve({
|
|
107
|
+
port: PORT,
|
|
108
|
+
hostname: "127.0.0.1",
|
|
109
|
+
idleTimeout: 0,
|
|
110
|
+
async fetch(req) {
|
|
111
|
+
const url = new URL(req.url);
|
|
112
|
+
if (req.method === "GET" && url.pathname === "/events") {
|
|
113
|
+
const stream = new ReadableStream({
|
|
114
|
+
start(ctrl) {
|
|
115
|
+
ctrl.enqueue(": agent-comms connected\n\n");
|
|
116
|
+
const emit = (chunk) => {
|
|
117
|
+
ctrl.enqueue(chunk);
|
|
118
|
+
};
|
|
119
|
+
listeners.add(emit);
|
|
120
|
+
req.signal.addEventListener("abort", () => listeners.delete(emit));
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
return new Response(stream, {
|
|
124
|
+
headers: {
|
|
125
|
+
"Content-Type": "text/event-stream",
|
|
126
|
+
"Cache-Control": "no-cache",
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
if (req.method === "POST") {
|
|
131
|
+
const body = await req.text();
|
|
132
|
+
if (!agentId)
|
|
133
|
+
return new Response("not registered", { status: 500 });
|
|
134
|
+
await mcp.server.notification({
|
|
135
|
+
method: "notifications/claude/channel",
|
|
136
|
+
params: { content: body, meta: { source: "http" } },
|
|
137
|
+
});
|
|
138
|
+
return new Response("ok");
|
|
139
|
+
}
|
|
140
|
+
return new Response("agent-comms channel server", { status: 200 });
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
//# sourceMappingURL=channel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel.js","sourceRoot":"","sources":["../../../src/bridges/claude-code/channel.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Comms — Codex Stop hook.
|
|
3
|
+
*
|
|
4
|
+
* Drains the agent-comms delivery queue when Codex finishes a turn.
|
|
5
|
+
* If pending messages exist, returns decision=block with the messages
|
|
6
|
+
* as the reason, causing Codex to continue processing them immediately.
|
|
7
|
+
*
|
|
8
|
+
* Run via: npx agent-comms bridge codex-stop
|
|
9
|
+
*
|
|
10
|
+
* Requires [features] codex_hooks = true in config.toml.
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=stop_hook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stop_hook.d.ts","sourceRoot":"","sources":["../../../src/bridges/codex/stop_hook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Comms — Codex Stop hook.
|
|
3
|
+
*
|
|
4
|
+
* Drains the agent-comms delivery queue when Codex finishes a turn.
|
|
5
|
+
* If pending messages exist, returns decision=block with the messages
|
|
6
|
+
* as the reason, causing Codex to continue processing them immediately.
|
|
7
|
+
*
|
|
8
|
+
* Run via: npx agent-comms bridge codex-stop
|
|
9
|
+
*
|
|
10
|
+
* Requires [features] codex_hooks = true in config.toml.
|
|
11
|
+
*/
|
|
12
|
+
import * as fs from "node:fs";
|
|
13
|
+
import * as path from "node:path";
|
|
14
|
+
import * as os from "node:os";
|
|
15
|
+
import { DeliveryEventSchema } from "../../core/types.js";
|
|
16
|
+
const BUS_ROOT = path.join(os.homedir(), ".agents", "bus");
|
|
17
|
+
const IDENTITY_FILE = path.join(BUS_ROOT, "identity.json");
|
|
18
|
+
function isRecord(value) {
|
|
19
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
20
|
+
}
|
|
21
|
+
function readIdentity() {
|
|
22
|
+
try {
|
|
23
|
+
const parsed = JSON.parse(fs.readFileSync(IDENTITY_FILE, "utf-8"));
|
|
24
|
+
if (isRecord(parsed) && typeof parsed.id === "string") {
|
|
25
|
+
return parsed.id;
|
|
26
|
+
}
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function drainDelivery(agentId) {
|
|
34
|
+
const deliveryDir = path.join(BUS_ROOT, "delivery", agentId);
|
|
35
|
+
try {
|
|
36
|
+
const files = fs
|
|
37
|
+
.readdirSync(deliveryDir)
|
|
38
|
+
.filter((f) => f.endsWith(".json"))
|
|
39
|
+
.sort();
|
|
40
|
+
const events = [];
|
|
41
|
+
for (const file of files) {
|
|
42
|
+
const fp = path.join(deliveryDir, file);
|
|
43
|
+
try {
|
|
44
|
+
const parsed = JSON.parse(fs.readFileSync(fp, "utf-8"));
|
|
45
|
+
events.push(DeliveryEventSchema.parse(parsed));
|
|
46
|
+
fs.unlinkSync(fp);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
fs.unlinkSync(fp);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
events.sort((a, b) => {
|
|
53
|
+
const ta = a.type === "room_message" || a.type === "dm" ? a.message.timestamp : "";
|
|
54
|
+
const tb = b.type === "room_message" || b.type === "dm" ? b.message.timestamp : "";
|
|
55
|
+
return ta.localeCompare(tb);
|
|
56
|
+
});
|
|
57
|
+
return events;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return [];
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function formatEvent(event) {
|
|
64
|
+
switch (event.type) {
|
|
65
|
+
case "room_message":
|
|
66
|
+
return `[${event.message.room}] ${event.message.from}: ${event.message.content}`;
|
|
67
|
+
case "dm":
|
|
68
|
+
return `DM from ${event.message.from}: ${event.message.content}`;
|
|
69
|
+
case "room_invite":
|
|
70
|
+
return `Invited to room ${event.room} by ${event.from}`;
|
|
71
|
+
case "member_joined":
|
|
72
|
+
return `${event.agent} joined ${event.room}`;
|
|
73
|
+
case "member_left":
|
|
74
|
+
return `${event.agent} left ${event.room}`;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// Read Codex hook input from stdin, then drain and respond
|
|
78
|
+
const chunks = [];
|
|
79
|
+
process.stdin.setEncoding("utf-8");
|
|
80
|
+
process.stdin.on("data", (chunk) => chunks.push(chunk));
|
|
81
|
+
process.stdin.on("end", () => {
|
|
82
|
+
try {
|
|
83
|
+
JSON.parse(chunks.join(""));
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
/* no input, fine */
|
|
87
|
+
}
|
|
88
|
+
const agentId = readIdentity();
|
|
89
|
+
if (!agentId)
|
|
90
|
+
process.exit(0);
|
|
91
|
+
const events = drainDelivery(agentId);
|
|
92
|
+
if (events.length === 0)
|
|
93
|
+
process.exit(0);
|
|
94
|
+
const lines = events.map(formatEvent);
|
|
95
|
+
const message = "📬 Agent Comms pending messages:\n" +
|
|
96
|
+
lines.map((l) => `- ${l}`).join("\n");
|
|
97
|
+
process.stdout.write(JSON.stringify({ decision: "block", reason: message }, null, 2) + "\n");
|
|
98
|
+
});
|
|
99
|
+
//# sourceMappingURL=stop_hook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stop_hook.js","sourceRoot":"","sources":["../../../src/bridges/codex/stop_hook.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Agent Comms — Codex MCP tool server.
|
|
4
|
+
*
|
|
5
|
+
* Provides the "agent_comms" tool for Codex to call.
|
|
6
|
+
* Push delivery is handled by the Stop hook (stop_hook.ts).
|
|
7
|
+
*
|
|
8
|
+
* Install in ~/.codex/config.toml:
|
|
9
|
+
* [mcp_servers.agent-comms]
|
|
10
|
+
* command = "npx"
|
|
11
|
+
* args = ["agent-comms", "bridge", "codex"]
|
|
12
|
+
*/
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../../src/bridges/codex/tool.ts"],"names":[],"mappings":";AACA;;;;;;;;;;GAUG"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Agent Comms — Codex MCP tool server.
|
|
4
|
+
*
|
|
5
|
+
* Provides the "agent_comms" tool for Codex to call.
|
|
6
|
+
* Push delivery is handled by the Stop hook (stop_hook.ts).
|
|
7
|
+
*
|
|
8
|
+
* Install in ~/.codex/config.toml:
|
|
9
|
+
* [mcp_servers.agent-comms]
|
|
10
|
+
* command = "npx"
|
|
11
|
+
* args = ["agent-comms", "bridge", "codex"]
|
|
12
|
+
*/
|
|
13
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
14
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
15
|
+
import * as path from "node:path";
|
|
16
|
+
import * as os from "node:os";
|
|
17
|
+
function isRecord(value) {
|
|
18
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
19
|
+
}
|
|
20
|
+
import { BusStore, BusTool, buildAction, ensureRegistered, MCP_TOOL_PARAMS, } from "../../core/index.js";
|
|
21
|
+
import { nanoid } from "../../core/nanoid.js";
|
|
22
|
+
const store = new BusStore(path.join(os.homedir(), ".agents", "bus"));
|
|
23
|
+
const tool = new BusTool(store);
|
|
24
|
+
let agentId;
|
|
25
|
+
const mcp = new McpServer({ name: "agent-comms", version: "0.2.0" }, { capabilities: {} });
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
// Tool registration
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
mcp.registerTool("agent_comms", {
|
|
30
|
+
description: [
|
|
31
|
+
"Cross-harness agent communication bus. Actions:",
|
|
32
|
+
"register, update, whoami, create_room, list_rooms, join_room, leave_room,",
|
|
33
|
+
"send, dm, list_agents, read_room, invite, kick, destroy_room.",
|
|
34
|
+
"Incoming messages are delivered automatically via the Stop hook.",
|
|
35
|
+
].join(" "),
|
|
36
|
+
inputSchema: MCP_TOOL_PARAMS,
|
|
37
|
+
}, async (rawParams) => {
|
|
38
|
+
const params = isRecord(rawParams) ? rawParams : {};
|
|
39
|
+
const actionParam = params.action;
|
|
40
|
+
if (!agentId && actionParam !== "register") {
|
|
41
|
+
const reg = await ensureRegistered({
|
|
42
|
+
store,
|
|
43
|
+
harness: "codex",
|
|
44
|
+
defaultName: `codex-${nanoid(4)}`,
|
|
45
|
+
});
|
|
46
|
+
agentId = reg.agentId;
|
|
47
|
+
}
|
|
48
|
+
if (!agentId) {
|
|
49
|
+
return {
|
|
50
|
+
content: [{ type: "text", text: "Error: failed to register" }],
|
|
51
|
+
isError: true,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
const action = buildAction(params);
|
|
55
|
+
const result = await tool.handle({ agentId, harness: "codex", pid: process.pid }, action);
|
|
56
|
+
return {
|
|
57
|
+
content: [{ type: "text", text: result.content }],
|
|
58
|
+
isError: result.isError,
|
|
59
|
+
};
|
|
60
|
+
});
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
// Startup
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
await mcp.connect(new StdioServerTransport());
|
|
65
|
+
const reg = await ensureRegistered({
|
|
66
|
+
store,
|
|
67
|
+
harness: "codex",
|
|
68
|
+
defaultName: `codex-${nanoid(4)}`,
|
|
69
|
+
});
|
|
70
|
+
agentId = reg.agentId;
|
|
71
|
+
//# sourceMappingURL=tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool.js","sourceRoot":"","sources":["../../../src/bridges/codex/tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Comms — OpenCode plugin bridge.
|
|
3
|
+
*
|
|
4
|
+
* Drains delivery queue on session.idle and injects messages via
|
|
5
|
+
* tui.prompt.append + tui.submitPrompt.
|
|
6
|
+
*
|
|
7
|
+
* Install (project): ln -s ~/Developer/agent-comms/src/bridges/opencode/plugin.ts .opencode/plugins/agent-comms.ts
|
|
8
|
+
* Install (global): ln -s ~/Developer/agent-comms/src/bridges/opencode/plugin.ts ~/.config/opencode/plugins/agent-comms.ts
|
|
9
|
+
*/
|
|
10
|
+
export declare const AgentCommsPlugin: (opts: {
|
|
11
|
+
project: unknown;
|
|
12
|
+
client: unknown;
|
|
13
|
+
$: unknown;
|
|
14
|
+
directory: string;
|
|
15
|
+
worktree: string;
|
|
16
|
+
}) => Promise<{
|
|
17
|
+
event: ({ event }: {
|
|
18
|
+
event: {
|
|
19
|
+
type: string;
|
|
20
|
+
};
|
|
21
|
+
}) => Promise<void>;
|
|
22
|
+
}>;
|
|
23
|
+
//# sourceMappingURL=plugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/bridges/opencode/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAqCH,eAAO,MAAM,gBAAgB,GAAU,MAAM;IAC3C,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,CAAC,EAAE,OAAO,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;uBA4C4B;QAAE,KAAK,EAAE;YAAE,IAAI,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE;EAMvD,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Comms — OpenCode plugin bridge.
|
|
3
|
+
*
|
|
4
|
+
* Drains delivery queue on session.idle and injects messages via
|
|
5
|
+
* tui.prompt.append + tui.submitPrompt.
|
|
6
|
+
*
|
|
7
|
+
* Install (project): ln -s ~/Developer/agent-comms/src/bridges/opencode/plugin.ts .opencode/plugins/agent-comms.ts
|
|
8
|
+
* Install (global): ln -s ~/Developer/agent-comms/src/bridges/opencode/plugin.ts ~/.config/opencode/plugins/agent-comms.ts
|
|
9
|
+
*/
|
|
10
|
+
import * as fs from "node:fs";
|
|
11
|
+
import * as path from "node:path";
|
|
12
|
+
import * as os from "node:os";
|
|
13
|
+
import { BusStore, ensureRegistered, drainAndFormat, } from "../../core/index.js";
|
|
14
|
+
import { nanoid } from "../../core/nanoid.js";
|
|
15
|
+
const store = new BusStore(path.join(os.homedir(), ".agents", "bus"));
|
|
16
|
+
function isOpenCodeClient(value) {
|
|
17
|
+
if (typeof value !== "object" || value === null)
|
|
18
|
+
return false;
|
|
19
|
+
if (!("tui" in value))
|
|
20
|
+
return false;
|
|
21
|
+
if (!("session" in value))
|
|
22
|
+
return false;
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
export const AgentCommsPlugin = async (opts) => {
|
|
26
|
+
if (!isOpenCodeClient(opts.client)) {
|
|
27
|
+
throw new Error("Agent Comms plugin requires a valid OpenCode client");
|
|
28
|
+
}
|
|
29
|
+
const client = opts.client;
|
|
30
|
+
const reg = await ensureRegistered({
|
|
31
|
+
store,
|
|
32
|
+
harness: "opencode",
|
|
33
|
+
defaultName: `opencode-${nanoid(4)}`,
|
|
34
|
+
});
|
|
35
|
+
const agentId = reg.agentId;
|
|
36
|
+
// Watch delivery dir so we know when messages arrive
|
|
37
|
+
const deliveryDir = store.deliveryDir(agentId);
|
|
38
|
+
fs.mkdirSync(deliveryDir, { recursive: true });
|
|
39
|
+
fs.watch(deliveryDir, () => {
|
|
40
|
+
// Don't push immediately — session.idle will drain
|
|
41
|
+
});
|
|
42
|
+
async function drainAndInject() {
|
|
43
|
+
const lines = await drainAndFormat(store, agentId);
|
|
44
|
+
if (lines.length === 0)
|
|
45
|
+
return;
|
|
46
|
+
const message = "📬 Agent Comms:\n" + lines.map((l) => `- ${l}`).join("\n");
|
|
47
|
+
try {
|
|
48
|
+
await client.tui.appendPrompt({ text: message });
|
|
49
|
+
await client.tui.submitPrompt();
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
// Fallback: prompt the current session directly
|
|
53
|
+
const sessions = await client.session.list();
|
|
54
|
+
const current = sessions.data[0];
|
|
55
|
+
if (current) {
|
|
56
|
+
await client.session.prompt({
|
|
57
|
+
path: { id: current.id },
|
|
58
|
+
body: {
|
|
59
|
+
parts: [{ type: "text", text: message }],
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
event: async ({ event }) => {
|
|
67
|
+
if (event.type === "session.idle") {
|
|
68
|
+
await drainAndInject();
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../../src/bridges/opencode/plugin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Comms — pi bridge extension.
|
|
3
|
+
*
|
|
4
|
+
* Provides the `agent_comms` tool and watches the delivery queue,
|
|
5
|
+
* pushing incoming messages via sendUserMessage().
|
|
6
|
+
*
|
|
7
|
+
* Install: add bridge path to ~/.pi/agent/settings.json extensions array
|
|
8
|
+
*/
|
|
9
|
+
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
10
|
+
export default function (pi: ExtensionAPI): void;
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/bridges/pi/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAelE,MAAM,CAAC,OAAO,WAAW,EAAE,EAAE,YAAY,QAgKxC"}
|