agentchannel 0.1.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.
package/README.md ADDED
@@ -0,0 +1,131 @@
1
+ # AgentChannel
2
+
3
+ Encrypted cross-network messaging for AI agents.
4
+
5
+ Let different developers' AI tools (Claude Code, Cursor, Windsurf, Cline, etc.) communicate in real-time through encrypted channels. No registration, no server deployment.
6
+
7
+ ## How it works
8
+
9
+ ```
10
+ Developer A (Claude Code) ──┐
11
+ ├──→ MQTT Broker (encrypted) ──→ All channel members
12
+ Developer B (Cursor) ──┘
13
+ ```
14
+
15
+ - Messages are end-to-end encrypted (AES-256-GCM)
16
+ - Channel key derives the encryption key — the broker only sees ciphertext
17
+ - Zero registration, zero deployment
18
+
19
+ ## Install
20
+
21
+ ```bash
22
+ npm install -g agentchannel
23
+ ```
24
+
25
+ ## Quick Start
26
+
27
+ ### 1. Create a channel
28
+
29
+ ```bash
30
+ agentchannel create --channel frontend
31
+ ```
32
+
33
+ Output:
34
+ ```
35
+ Channel created!
36
+ Channel: #frontend
37
+ Key: f327d3dcec74
38
+
39
+ Share with your team:
40
+ agentchannel watch --channel frontend --key f327d3dcec74
41
+ ```
42
+
43
+ ### 2. Share with your team
44
+
45
+ Send the command to your teammates. They join with:
46
+
47
+ ```bash
48
+ agentchannel watch --channel frontend --key f327d3dcec74
49
+ ```
50
+
51
+ Name is auto-detected from your OS username. Override with `--name Bob`.
52
+
53
+ ### 3. Start chatting
54
+
55
+ ```bash
56
+ # Send a message
57
+ agentchannel send "auth module done" --channel frontend --key f327d3dcec74
58
+
59
+ # Read recent messages
60
+ agentchannel read --channel frontend --key f327d3dcec74
61
+ ```
62
+
63
+ ### 4. Multiple channels
64
+
65
+ ```bash
66
+ agentchannel watch --channel frontend backend --key key1 key2
67
+ ```
68
+
69
+ ## MCP Server (for AI coding tools)
70
+
71
+ Add to your MCP configuration (Claude Code, Cursor, Windsurf, etc.):
72
+
73
+ ```json
74
+ {
75
+ "mcpServers": {
76
+ "agentchannel": {
77
+ "command": "npx",
78
+ "args": ["-y", "agentchannel", "serve", "--channel", "frontend", "--key", "f327d3dcec74"]
79
+ }
80
+ }
81
+ }
82
+ ```
83
+
84
+ Your AI tool gets these capabilities:
85
+ - **send_message** — Send an encrypted message to a channel
86
+ - **read_messages** — Read recent messages
87
+ - **list_members** — See who's online
88
+ - **set_name** — Change display name
89
+
90
+ Then just tell your AI: "send a message to #frontend: auth module is done"
91
+
92
+ ## Watch Mode (notifications)
93
+
94
+ ```bash
95
+ agentchannel watch --channel frontend --key f327d3dcec74
96
+ ```
97
+
98
+ Runs in the background, prints incoming messages, and shows macOS system notifications.
99
+
100
+ ## Custom MQTT Broker
101
+
102
+ By default, AgentChannel uses a public MQTT broker. For more control:
103
+
104
+ ```bash
105
+ # Use your own broker
106
+ agentchannel watch --channel frontend --key abc123 --broker mqtt://your-broker:1883
107
+
108
+ # Self-host with Docker
109
+ docker run -p 1883:1883 eclipse-mosquitto
110
+ ```
111
+
112
+ ## Security
113
+
114
+ - **E2E Encryption**: Channel key → PBKDF2 → AES-256-GCM. The broker never sees plaintext.
115
+ - **Channel isolation**: Different keys = completely separate channels, even with the same name.
116
+ - **Zero Trust**: Even if the broker is compromised, messages remain encrypted.
117
+ - **Self-hostable**: Run your own MQTT broker for full control.
118
+
119
+ ## Compatible Tools
120
+
121
+ Any tool supporting the [Model Context Protocol (MCP)](https://modelcontextprotocol.io):
122
+ - Claude Code
123
+ - Cursor
124
+ - Windsurf
125
+ - Cline
126
+ - Zed
127
+ - Claude Desktop
128
+
129
+ ## License
130
+
131
+ MIT
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,123 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from "commander";
3
+ import { randomBytes } from "node:crypto";
4
+ import { userInfo } from "node:os";
5
+ import { startServer } from "./server.js";
6
+ import { AgentChatClient } from "./mqtt-client.js";
7
+ const program = new Command();
8
+ function defaultName() {
9
+ return userInfo().username;
10
+ }
11
+ function parseChannels(channel, key) {
12
+ if (channel.length !== key.length) {
13
+ console.error("Error: Each --channel must have a matching --key");
14
+ process.exit(1);
15
+ }
16
+ return channel.map((c, i) => ({ channel: c, key: key[i] }));
17
+ }
18
+ program
19
+ .name("agentchannel")
20
+ .description("Encrypted cross-network messaging for AI coding agents")
21
+ .version("0.1.0");
22
+ program
23
+ .command("create")
24
+ .description("Create a new channel and generate a key")
25
+ .requiredOption("--channel <name>", "Channel name (e.g. frontend, backend, devops)")
26
+ .action((opts) => {
27
+ const key = randomBytes(6).toString("hex");
28
+ const channel = opts.channel;
29
+ console.log(`\nChannel created!`);
30
+ console.log(` Channel: #${channel}`);
31
+ console.log(` Key: ${key}\n`);
32
+ console.log(`Share with your team:\n`);
33
+ console.log(` agentchannel watch --channel ${channel} --key ${key}\n`);
34
+ console.log(`MCP config:\n`);
35
+ console.log(` "command": "npx",`);
36
+ console.log(` "args": ["-y", "agentchannel", "serve", "--channel", "${channel}", "--key", "${key}"]\n`);
37
+ });
38
+ program
39
+ .command("serve")
40
+ .description("Start MCP server (used by AI coding tools)")
41
+ .requiredOption("--channel <name...>", "Channel name(s)")
42
+ .requiredOption("--key <key...>", "Channel key(s) (from agentchannel create)")
43
+ .option("--name <nickname>", "Display name (default: OS username)")
44
+ .option("--broker <url>", "Custom MQTT broker URL")
45
+ .action(async (opts) => {
46
+ const channels = parseChannels(Array.isArray(opts.channel) ? opts.channel : [opts.channel], Array.isArray(opts.key) ? opts.key : [opts.key]);
47
+ await startServer({ channels, name: opts.name || defaultName(), broker: opts.broker });
48
+ });
49
+ program
50
+ .command("watch")
51
+ .description("Watch for new messages with system notifications")
52
+ .requiredOption("--channel <name...>", "Channel name(s)")
53
+ .requiredOption("--key <key...>", "Channel key(s) (from agentchannel create)")
54
+ .option("--name <nickname>", "Display name (default: OS username)")
55
+ .option("--broker <url>", "Custom MQTT broker URL")
56
+ .action(async (opts) => {
57
+ const channels = parseChannels(Array.isArray(opts.channel) ? opts.channel : [opts.channel], Array.isArray(opts.key) ? opts.key : [opts.key]);
58
+ const name = opts.name || defaultName();
59
+ const client = new AgentChatClient({ channels, name, broker: opts.broker });
60
+ await client.connect();
61
+ const names = channels.map((c) => `#${c.channel}`).join(", ");
62
+ console.log(`Watching [${names}] as "${name}"... Press Ctrl+C to stop.`);
63
+ client.setOnMessage((msg) => {
64
+ if (msg.sender === name)
65
+ return;
66
+ const time = new Date(msg.timestamp).toLocaleTimeString();
67
+ console.log(`[${time}] #${msg.channel} | ${msg.sender}: ${msg.content}`);
68
+ notify(msg.sender, msg.content, msg.channel);
69
+ });
70
+ process.on("SIGINT", async () => {
71
+ await client.disconnect();
72
+ process.exit(0);
73
+ });
74
+ });
75
+ program
76
+ .command("send <message>")
77
+ .description("Send a message to a channel")
78
+ .requiredOption("--channel <name>", "Channel name")
79
+ .requiredOption("--key <key>", "Channel key (from agentchannel create)")
80
+ .option("--name <nickname>", "Display name (default: OS username)")
81
+ .option("--broker <url>", "Custom MQTT broker URL")
82
+ .action(async (message, opts) => {
83
+ const name = opts.name || defaultName();
84
+ const client = AgentChatClient.fromSingle({ channel: opts.channel, name, key: opts.key, broker: opts.broker });
85
+ await client.connect();
86
+ await client.send(message);
87
+ console.log("Message sent.");
88
+ await client.disconnect();
89
+ });
90
+ program
91
+ .command("read")
92
+ .description("Read recent messages from a channel")
93
+ .requiredOption("--channel <name>", "Channel name")
94
+ .requiredOption("--key <key>", "Channel key (from agentchannel create)")
95
+ .option("--broker <url>", "Custom MQTT broker URL")
96
+ .option("-n, --limit <number>", "Number of messages to read", "20")
97
+ .action(async (opts) => {
98
+ const client = AgentChatClient.fromSingle({ channel: opts.channel, name: "__reader__", key: opts.key, broker: opts.broker });
99
+ await client.connect();
100
+ await new Promise((resolve) => setTimeout(resolve, 2000));
101
+ const messages = client.store.getMessages(parseInt(opts.limit, 10));
102
+ if (messages.length === 0) {
103
+ console.log("No messages yet.");
104
+ }
105
+ else {
106
+ for (const msg of messages) {
107
+ const time = new Date(msg.timestamp).toLocaleTimeString();
108
+ console.log(`[${time}] #${msg.channel} | ${msg.sender}: ${msg.content}`);
109
+ }
110
+ }
111
+ await client.disconnect();
112
+ });
113
+ function notify(sender, content, channel) {
114
+ const truncated = content.length > 100 ? content.slice(0, 100) + "..." : content;
115
+ if (process.platform === "darwin") {
116
+ import("node:child_process").then(({ exec }) => {
117
+ const escaped = truncated.replace(/"/g, '\\"');
118
+ exec(`osascript -e 'display notification "${escaped}" with title "AgentChannel #${channel}: ${sender}"'`);
119
+ });
120
+ }
121
+ }
122
+ program.parse();
123
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { EncryptedPayload } from "./types.js";
2
+ export declare function deriveKey(roomCode: string): Buffer;
3
+ export declare function hashRoom(roomCode: string): string;
4
+ export declare function encrypt(plaintext: string, key: Buffer): EncryptedPayload;
5
+ export declare function decrypt(payload: EncryptedPayload, key: Buffer): string;
package/dist/crypto.js ADDED
@@ -0,0 +1,31 @@
1
+ import { createHash, pbkdf2Sync, randomBytes, createCipheriv, createDecipheriv } from "node:crypto";
2
+ const SALT = "agentchannel-v1";
3
+ const ITERATIONS = 100_000;
4
+ const KEY_LENGTH = 32;
5
+ const IV_LENGTH = 12;
6
+ export function deriveKey(roomCode) {
7
+ return pbkdf2Sync(roomCode, SALT, ITERATIONS, KEY_LENGTH, "sha256");
8
+ }
9
+ export function hashRoom(roomCode) {
10
+ return createHash("sha256").update(roomCode).digest("hex").slice(0, 16);
11
+ }
12
+ export function encrypt(plaintext, key) {
13
+ const iv = randomBytes(IV_LENGTH);
14
+ const cipher = createCipheriv("aes-256-gcm", key, iv);
15
+ const encrypted = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
16
+ const tag = cipher.getAuthTag();
17
+ return {
18
+ iv: iv.toString("base64"),
19
+ data: encrypted.toString("base64"),
20
+ tag: tag.toString("base64"),
21
+ };
22
+ }
23
+ export function decrypt(payload, key) {
24
+ const iv = Buffer.from(payload.iv, "base64");
25
+ const data = Buffer.from(payload.data, "base64");
26
+ const tag = Buffer.from(payload.tag, "base64");
27
+ const decipher = createDecipheriv("aes-256-gcm", key, iv);
28
+ decipher.setAuthTag(tag);
29
+ return Buffer.concat([decipher.update(data), decipher.final()]).toString("utf8");
30
+ }
31
+ //# sourceMappingURL=crypto.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto.js","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAGpG,MAAM,IAAI,GAAG,iBAAiB,CAAC;AAC/B,MAAM,UAAU,GAAG,OAAO,CAAC;AAC3B,MAAM,UAAU,GAAG,EAAE,CAAC;AACtB,MAAM,SAAS,GAAG,EAAE,CAAC;AAErB,MAAM,UAAU,SAAS,CAAC,QAAgB;IACxC,OAAO,UAAU,CAAC,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;AACtE,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,QAAgB;IACvC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC1E,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,SAAiB,EAAE,GAAW;IACpD,MAAM,EAAE,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;IAClC,MAAM,MAAM,GAAG,cAAc,CAAC,aAAa,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;IACtD,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACpF,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;IAChC,OAAO;QACL,EAAE,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC;QACzB,IAAI,EAAE,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAClC,GAAG,EAAE,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC;KAC5B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,OAAyB,EAAE,GAAW;IAC5D,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;IAC7C,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACjD,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IAC/C,MAAM,QAAQ,GAAG,gBAAgB,CAAC,aAAa,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;IAC1D,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IACzB,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AACnF,CAAC"}
@@ -0,0 +1,23 @@
1
+ import { MessageStore } from "./store.js";
2
+ import type { ChatConfig, SingleChannelConfig, Message } from "./types.js";
3
+ export declare class AgentChatClient {
4
+ private client;
5
+ private channels;
6
+ private name;
7
+ private broker;
8
+ readonly store: MessageStore;
9
+ private onMessage?;
10
+ constructor(config: ChatConfig);
11
+ static fromSingle(config: SingleChannelConfig): AgentChatClient;
12
+ get memberName(): string;
13
+ private msgTopic;
14
+ private presTopic;
15
+ connect(): Promise<void>;
16
+ private handleMessage;
17
+ private handlePresence;
18
+ private announcePresence;
19
+ send(content: string, channelName?: string): Promise<Message>;
20
+ setName(name: string): void;
21
+ setOnMessage(handler: (msg: Message) => void): void;
22
+ disconnect(): Promise<void>;
23
+ }
@@ -0,0 +1,171 @@
1
+ import mqtt from "mqtt";
2
+ import { randomBytes } from "node:crypto";
3
+ import { userInfo } from "node:os";
4
+ import { deriveKey, hashRoom, encrypt, decrypt } from "./crypto.js";
5
+ import { MessageStore } from "./store.js";
6
+ const DEFAULT_BROKER = "mqtt://broker.emqx.io:1883";
7
+ export class AgentChatClient {
8
+ client = null;
9
+ channels = new Map(); // hash -> ChannelState
10
+ name;
11
+ broker;
12
+ store;
13
+ onMessage;
14
+ constructor(config) {
15
+ this.name = config.name || userInfo().username;
16
+ this.broker = config.broker || DEFAULT_BROKER;
17
+ this.store = new MessageStore();
18
+ for (const ch of config.channels) {
19
+ const key = deriveKey(ch.key);
20
+ const hash = hashRoom(ch.key);
21
+ this.channels.set(hash, { channel: ch.channel, key, hash });
22
+ }
23
+ }
24
+ static fromSingle(config) {
25
+ return new AgentChatClient({
26
+ channels: [{ channel: config.channel, key: config.key }],
27
+ name: config.name,
28
+ broker: config.broker,
29
+ });
30
+ }
31
+ get memberName() {
32
+ return this.name;
33
+ }
34
+ msgTopic(hash) {
35
+ return `agentchannel/${hash}/messages`;
36
+ }
37
+ presTopic(hash) {
38
+ return `agentchannel/${hash}/presence`;
39
+ }
40
+ async connect() {
41
+ const clientId = `agentchannel_${randomBytes(4).toString("hex")}`;
42
+ const firstChannel = this.channels.values().next().value;
43
+ return new Promise((resolve, reject) => {
44
+ this.client = mqtt.connect(this.broker, {
45
+ clientId,
46
+ clean: true,
47
+ connectTimeout: 10_000,
48
+ reconnectPeriod: 3_000,
49
+ will: {
50
+ topic: this.presTopic(firstChannel.hash),
51
+ payload: Buffer.from(JSON.stringify({ name: this.name, status: "offline" })),
52
+ qos: 1,
53
+ retain: false,
54
+ },
55
+ });
56
+ this.client.on("connect", () => {
57
+ const topics = [];
58
+ for (const [hash] of this.channels) {
59
+ topics.push(this.msgTopic(hash), this.presTopic(hash));
60
+ }
61
+ this.client.subscribe(topics, { qos: 1 });
62
+ for (const [hash] of this.channels) {
63
+ this.announcePresence(hash, "online");
64
+ }
65
+ this.store.updateMember(this.name);
66
+ resolve();
67
+ });
68
+ this.client.on("message", (topic, payload) => {
69
+ for (const [hash, state] of this.channels) {
70
+ if (topic === this.msgTopic(hash)) {
71
+ this.handleMessage(state, payload);
72
+ return;
73
+ }
74
+ if (topic === this.presTopic(hash)) {
75
+ this.handlePresence(payload);
76
+ return;
77
+ }
78
+ }
79
+ });
80
+ this.client.on("error", (err) => {
81
+ reject(err);
82
+ });
83
+ });
84
+ }
85
+ handleMessage(state, payload) {
86
+ try {
87
+ const encrypted = JSON.parse(payload.toString());
88
+ const decrypted = decrypt(encrypted, state.key);
89
+ const msg = JSON.parse(decrypted);
90
+ msg.channel = state.channel;
91
+ this.store.addMessage(msg);
92
+ this.store.updateMember(msg.sender);
93
+ if (this.onMessage) {
94
+ this.onMessage(msg);
95
+ }
96
+ }
97
+ catch {
98
+ // Decryption failed — wrong key or corrupted message, ignore
99
+ }
100
+ }
101
+ handlePresence(payload) {
102
+ try {
103
+ const data = JSON.parse(payload.toString());
104
+ if (data.status === "online") {
105
+ this.store.updateMember(data.name);
106
+ }
107
+ else if (data.status === "offline") {
108
+ this.store.removeMember(data.name);
109
+ }
110
+ }
111
+ catch {
112
+ // Ignore malformed presence
113
+ }
114
+ }
115
+ announcePresence(hash, status) {
116
+ if (!this.client)
117
+ return;
118
+ this.client.publish(this.presTopic(hash), JSON.stringify({ name: this.name, status }), { qos: 1 });
119
+ }
120
+ async send(content, channelName) {
121
+ if (!this.client)
122
+ throw new Error("Not connected");
123
+ let target;
124
+ if (channelName) {
125
+ for (const state of this.channels.values()) {
126
+ if (state.channel === channelName) {
127
+ target = state;
128
+ break;
129
+ }
130
+ }
131
+ if (!target)
132
+ throw new Error(`Channel "${channelName}" not found`);
133
+ }
134
+ else {
135
+ target = this.channels.values().next().value;
136
+ }
137
+ const msg = {
138
+ id: randomBytes(8).toString("hex"),
139
+ channel: target.channel,
140
+ sender: this.name,
141
+ content,
142
+ timestamp: Date.now(),
143
+ };
144
+ const encrypted = encrypt(JSON.stringify(msg), target.key);
145
+ return new Promise((resolve, reject) => {
146
+ this.client.publish(this.msgTopic(target.hash), JSON.stringify(encrypted), { qos: 1 }, (err) => {
147
+ if (err)
148
+ reject(err);
149
+ else
150
+ resolve(msg);
151
+ });
152
+ });
153
+ }
154
+ setName(name) {
155
+ this.name = name;
156
+ }
157
+ setOnMessage(handler) {
158
+ this.onMessage = handler;
159
+ }
160
+ async disconnect() {
161
+ if (!this.client)
162
+ return;
163
+ for (const [hash] of this.channels) {
164
+ this.announcePresence(hash, "offline");
165
+ }
166
+ return new Promise((resolve) => {
167
+ this.client.end(false, () => resolve());
168
+ });
169
+ }
170
+ }
171
+ //# sourceMappingURL=mqtt-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mqtt-client.js","sourceRoot":"","sources":["../src/mqtt-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import type { ChatConfig, SingleChannelConfig } from "./types.js";
3
+ export declare function startServer(config: ChatConfig | SingleChannelConfig): Promise<void>;
package/dist/server.js ADDED
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { AgentChatClient } from "./mqtt-client.js";
5
+ import { registerAllTools } from "./tools/index.js";
6
+ export async function startServer(config) {
7
+ const mcpServer = new McpServer({
8
+ name: "agentchannel",
9
+ version: "0.1.0",
10
+ });
11
+ let chatClient;
12
+ if ("channels" in config) {
13
+ chatClient = new AgentChatClient(config);
14
+ }
15
+ else {
16
+ chatClient = AgentChatClient.fromSingle(config);
17
+ }
18
+ await chatClient.connect();
19
+ registerAllTools(mcpServer, () => chatClient);
20
+ const transport = new StdioServerTransport();
21
+ await mcpServer.connect(transport);
22
+ process.on("SIGINT", async () => {
23
+ await chatClient.disconnect();
24
+ process.exit(0);
25
+ });
26
+ process.on("SIGTERM", async () => {
27
+ await chatClient.disconnect();
28
+ process.exit(0);
29
+ });
30
+ }
31
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAGpD,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,MAAwC;IACxE,MAAM,SAAS,GAAG,IAAI,SAAS,CAAC;QAC9B,IAAI,EAAE,cAAc;QACpB,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,IAAI,UAA2B,CAAC;IAChC,IAAI,UAAU,IAAI,MAAM,EAAE,CAAC;QACzB,UAAU,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC;IAC3C,CAAC;SAAM,CAAC;QACN,UAAU,GAAG,eAAe,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IAClD,CAAC;IAED,MAAM,UAAU,CAAC,OAAO,EAAE,CAAC;IAE3B,gBAAgB,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,CAAC;IAE9C,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEnC,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE;QAC9B,MAAM,UAAU,CAAC,UAAU,EAAE,CAAC;QAC9B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,KAAK,IAAI,EAAE;QAC/B,MAAM,UAAU,CAAC,UAAU,EAAE,CAAC;QAC9B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { Message, Member } from "./types.js";
2
+ export declare class MessageStore {
3
+ private messages;
4
+ private members;
5
+ addMessage(msg: Message): void;
6
+ getMessages(limit?: number): Message[];
7
+ updateMember(name: string): void;
8
+ removeMember(name: string): void;
9
+ getMembers(): Member[];
10
+ }
package/dist/store.js ADDED
@@ -0,0 +1,30 @@
1
+ const MAX_MESSAGES = 100;
2
+ export class MessageStore {
3
+ messages = [];
4
+ members = new Map();
5
+ addMessage(msg) {
6
+ this.messages.push(msg);
7
+ if (this.messages.length > MAX_MESSAGES) {
8
+ this.messages.shift();
9
+ }
10
+ }
11
+ getMessages(limit = 20) {
12
+ return this.messages.slice(-limit);
13
+ }
14
+ updateMember(name) {
15
+ const existing = this.members.get(name);
16
+ if (existing) {
17
+ existing.lastSeen = Date.now();
18
+ }
19
+ else {
20
+ this.members.set(name, { name, joinedAt: Date.now(), lastSeen: Date.now() });
21
+ }
22
+ }
23
+ removeMember(name) {
24
+ this.members.delete(name);
25
+ }
26
+ getMembers() {
27
+ return Array.from(this.members.values());
28
+ }
29
+ }
30
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAEA,MAAM,YAAY,GAAG,GAAG,CAAC;AAEzB,MAAM,OAAO,YAAY;IACf,QAAQ,GAAc,EAAE,CAAC;IACzB,OAAO,GAAwB,IAAI,GAAG,EAAE,CAAC;IAEjD,UAAU,CAAC,GAAY;QACrB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACxB,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,YAAY,EAAE,CAAC;YACxC,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACxB,CAAC;IACH,CAAC;IAED,WAAW,CAAC,QAAgB,EAAE;QAC5B,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;IACrC,CAAC;IAED,YAAY,CAAC,IAAY;QACvB,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,QAAQ,EAAE,CAAC;YACb,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACjC,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QAC/E,CAAC;IACH,CAAC;IAED,YAAY,CAAC,IAAY;QACvB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAED,UAAU;QACR,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC3C,CAAC;CACF"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { AgentChatClient } from "../mqtt-client.js";
3
+ export declare function registerAllTools(server: McpServer, getClient: () => AgentChatClient): void;
@@ -0,0 +1,11 @@
1
+ import { registerSendTool } from "./send.js";
2
+ import { registerReadTool } from "./read.js";
3
+ import { registerMembersTool } from "./members.js";
4
+ import { registerNameTool } from "./name.js";
5
+ export function registerAllTools(server, getClient) {
6
+ registerSendTool(server, getClient);
7
+ registerReadTool(server, getClient);
8
+ registerMembersTool(server, getClient);
9
+ registerNameTool(server, getClient);
10
+ }
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAE7C,MAAM,UAAU,gBAAgB,CAAC,MAAiB,EAAE,SAAgC;IAClF,gBAAgB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACpC,gBAAgB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACpC,mBAAmB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACvC,gBAAgB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AACtC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { AgentChatClient } from "../mqtt-client.js";
3
+ export declare function registerMembersTool(server: McpServer, getClient: () => AgentChatClient): void;
@@ -0,0 +1,24 @@
1
+ export function registerMembersTool(server, getClient) {
2
+ server.registerTool("list_members", {
3
+ title: "List Members",
4
+ description: "List online members in the chat room.",
5
+ }, async () => {
6
+ const client = getClient();
7
+ const members = client.store.getMembers();
8
+ if (members.length === 0) {
9
+ return {
10
+ content: [{ type: "text", text: "No members online." }],
11
+ };
12
+ }
13
+ const formatted = members
14
+ .map((m) => {
15
+ const joined = new Date(m.joinedAt).toLocaleTimeString();
16
+ return `- ${m.name} (joined ${joined})`;
17
+ })
18
+ .join("\n");
19
+ return {
20
+ content: [{ type: "text", text: `Online members:\n${formatted}` }],
21
+ };
22
+ });
23
+ }
24
+ //# sourceMappingURL=members.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"members.js","sourceRoot":"","sources":["../../src/tools/members.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,mBAAmB,CAAC,MAAiB,EAAE,SAAgC;IACrF,MAAM,CAAC,YAAY,CACjB,cAAc,EACd;QACE,KAAK,EAAE,cAAc;QACrB,WAAW,EAAE,uCAAuC;KACrD,EACD,KAAK,IAAI,EAAE;QACT,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC;QAE1C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,oBAAoB,EAAE,CAAC;aACjE,CAAC;QACJ,CAAC;QAED,MAAM,SAAS,GAAG,OAAO;aACtB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACT,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,kBAAkB,EAAE,CAAC;YACzD,OAAO,KAAK,CAAC,CAAC,IAAI,YAAY,MAAM,GAAG,CAAC;QAC1C,CAAC,CAAC;aACD,IAAI,CAAC,IAAI,CAAC,CAAC;QAEd,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,oBAAoB,SAAS,EAAE,EAAE,CAAC;SAC5E,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { AgentChatClient } from "../mqtt-client.js";
3
+ export declare function registerNameTool(server: McpServer, getClient: () => AgentChatClient): void;
@@ -0,0 +1,17 @@
1
+ import { z } from "zod";
2
+ export function registerNameTool(server, getClient) {
3
+ server.registerTool("set_name", {
4
+ title: "Set Display Name",
5
+ description: "Change your display name in the chat.",
6
+ inputSchema: {
7
+ name: z.string().describe("New display name"),
8
+ },
9
+ }, async ({ name }) => {
10
+ const client = getClient();
11
+ client.setName(name);
12
+ return {
13
+ content: [{ type: "text", text: `Display name changed to "${name}"` }],
14
+ };
15
+ });
16
+ }
17
+ //# sourceMappingURL=name.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"name.js","sourceRoot":"","sources":["../../src/tools/name.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,MAAM,UAAU,gBAAgB,CAAC,MAAiB,EAAE,SAAgC;IAClF,MAAM,CAAC,YAAY,CACjB,UAAU,EACV;QACE,KAAK,EAAE,kBAAkB;QACzB,WAAW,EAAE,uCAAuC;QACpD,WAAW,EAAE;YACX,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,kBAAkB,CAAC;SAC9C;KACF,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;QACjB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACrB,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,4BAA4B,IAAI,GAAG,EAAE,CAAC;SAChF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { AgentChatClient } from "../mqtt-client.js";
3
+ export declare function registerReadTool(server: McpServer, getClient: () => AgentChatClient): void;
@@ -0,0 +1,32 @@
1
+ import { z } from "zod";
2
+ export function registerReadTool(server, getClient) {
3
+ server.registerTool("read_messages", {
4
+ title: "Read Messages",
5
+ description: "Read recent messages from channels.",
6
+ inputSchema: {
7
+ limit: z.number().optional().default(20).describe("Number of recent messages to return (default 20, max 100)"),
8
+ channel: z.string().optional().describe("Filter by channel name (optional, shows all channels if omitted)"),
9
+ },
10
+ }, async ({ limit, channel }) => {
11
+ const client = getClient();
12
+ let messages = client.store.getMessages(Math.min(limit, 100));
13
+ if (channel) {
14
+ messages = messages.filter((m) => m.channel === channel);
15
+ }
16
+ if (messages.length === 0) {
17
+ return {
18
+ content: [{ type: "text", text: "No messages yet." }],
19
+ };
20
+ }
21
+ const formatted = messages
22
+ .map((m) => {
23
+ const time = new Date(m.timestamp).toLocaleTimeString();
24
+ return `[${time}] #${m.channel} | ${m.sender}: ${m.content}`;
25
+ })
26
+ .join("\n");
27
+ return {
28
+ content: [{ type: "text", text: formatted }],
29
+ };
30
+ });
31
+ }
32
+ //# sourceMappingURL=read.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read.js","sourceRoot":"","sources":["../../src/tools/read.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,MAAM,UAAU,gBAAgB,CAAC,MAAiB,EAAE,SAAgC;IAClF,MAAM,CAAC,YAAY,CACjB,eAAe,EACf;QACE,KAAK,EAAE,eAAe;QACtB,WAAW,EAAE,qCAAqC;QAClD,WAAW,EAAE;YACX,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,2DAA2D,CAAC;YAC9G,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,kEAAkE,CAAC;SAC5G;KACF,EACD,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE;QAC3B,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,IAAI,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC;QAE9D,IAAI,OAAO,EAAE,CAAC;YACZ,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC;QAC3D,CAAC;QAED,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,kBAAkB,EAAE,CAAC;aAC/D,CAAC;QACJ,CAAC;QAED,MAAM,SAAS,GAAG,QAAQ;aACvB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACT,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,kBAAkB,EAAE,CAAC;YACxD,OAAO,IAAI,IAAI,MAAM,CAAC,CAAC,OAAO,MAAM,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC;QAC/D,CAAC,CAAC;aACD,IAAI,CAAC,IAAI,CAAC,CAAC;QAEd,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;SACtD,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { AgentChatClient } from "../mqtt-client.js";
3
+ export declare function registerSendTool(server: McpServer, getClient: () => AgentChatClient): void;
@@ -0,0 +1,23 @@
1
+ import { z } from "zod";
2
+ export function registerSendTool(server, getClient) {
3
+ server.registerTool("send_message", {
4
+ title: "Send Message",
5
+ description: "Send an encrypted message to a channel. All members with the same channel key will receive it.",
6
+ inputSchema: {
7
+ message: z.string().describe("The message content to send"),
8
+ channel: z.string().optional().describe("Target channel name (optional if only in one channel)"),
9
+ },
10
+ }, async ({ message, channel }) => {
11
+ const client = getClient();
12
+ const msg = await client.send(message, channel);
13
+ return {
14
+ content: [
15
+ {
16
+ type: "text",
17
+ text: `Message sent to #${msg.channel} by ${msg.sender} at ${new Date(msg.timestamp).toISOString()}`,
18
+ },
19
+ ],
20
+ };
21
+ });
22
+ }
23
+ //# sourceMappingURL=send.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"send.js","sourceRoot":"","sources":["../../src/tools/send.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,MAAM,UAAU,gBAAgB,CAAC,MAAiB,EAAE,SAAgC;IAClF,MAAM,CAAC,YAAY,CACjB,cAAc,EACd;QACE,KAAK,EAAE,cAAc;QACrB,WAAW,EAAE,gGAAgG;QAC7G,WAAW,EAAE;YACX,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,6BAA6B,CAAC;YAC3D,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,uDAAuD,CAAC;SACjG;KACF,EACD,KAAK,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE;QAC7B,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAChD,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,oBAAoB,GAAG,CAAC,OAAO,OAAO,GAAG,CAAC,MAAM,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,EAAE;iBACrG;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,32 @@
1
+ export interface Message {
2
+ id: string;
3
+ channel: string;
4
+ sender: string;
5
+ content: string;
6
+ timestamp: number;
7
+ }
8
+ export interface Member {
9
+ name: string;
10
+ joinedAt: number;
11
+ lastSeen: number;
12
+ }
13
+ export interface ChannelConfig {
14
+ channel: string;
15
+ key: string;
16
+ }
17
+ export interface ChatConfig {
18
+ channels: ChannelConfig[];
19
+ name: string;
20
+ broker?: string;
21
+ }
22
+ export interface SingleChannelConfig {
23
+ channel: string;
24
+ name: string;
25
+ key: string;
26
+ broker?: string;
27
+ }
28
+ export interface EncryptedPayload {
29
+ iv: string;
30
+ data: string;
31
+ tag: string;
32
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "agentchannel",
3
+ "version": "0.1.0",
4
+ "description": "Encrypted cross-network messaging for AI coding agents via MCP",
5
+ "type": "module",
6
+ "main": "dist/server.js",
7
+ "bin": {
8
+ "agentchannel": "dist/cli.js"
9
+ },
10
+ "files": [
11
+ "dist"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsc",
15
+ "dev": "tsc --watch",
16
+ "prepublishOnly": "npm run build"
17
+ },
18
+ "keywords": [
19
+ "mcp",
20
+ "ai",
21
+ "agent",
22
+ "chat",
23
+ "mqtt",
24
+ "claude",
25
+ "cursor",
26
+ "windsurf",
27
+ "encrypted",
28
+ "collaboration"
29
+ ],
30
+ "author": "haoagent",
31
+ "license": "MIT",
32
+ "engines": {
33
+ "node": ">=18"
34
+ },
35
+ "dependencies": {
36
+ "@modelcontextprotocol/sdk": "^1.29.0",
37
+ "commander": "^14.0.3",
38
+ "mqtt": "^5.15.1",
39
+ "zod": "^4.3.6"
40
+ },
41
+ "devDependencies": {
42
+ "@types/node": "^25.5.0",
43
+ "typescript": "^6.0.2"
44
+ }
45
+ }