agentchannel 0.6.0 → 0.7.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,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { AgentChatClient } from "../mqtt-client.js";
3
+ export declare function registerGetMessageTool(server: McpServer, getClient: () => AgentChatClient): void;
@@ -0,0 +1,27 @@
1
+ import { z } from "zod";
2
+ export function registerGetMessageTool(server, getClient) {
3
+ server.registerTool("get_message", {
4
+ title: "Get Message",
5
+ description: "Get the full content of a single message by ID. Use read_messages(preview=true) first to get message IDs.",
6
+ inputSchema: {
7
+ id: z.string().describe("Message ID from read_messages preview"),
8
+ },
9
+ }, async ({ id }) => {
10
+ const client = getClient();
11
+ const msg = client.store.getMessageById(id);
12
+ if (!msg) {
13
+ return {
14
+ content: [{ type: "text", text: `Message ${id} not found.` }],
15
+ };
16
+ }
17
+ const time = new Date(msg.timestamp).toLocaleTimeString();
18
+ const trust = msg.trustLevel ? ` [${msg.trustLevel.toUpperCase()}]` : "";
19
+ const fp = msg.senderKey ? `:${msg.senderKey.slice(0, 4)}` : "";
20
+ const label = msg.subchannel ? `#${msg.channel} ##${msg.subchannel}` : `#${msg.channel}`;
21
+ const text = `[${time}] ${label} | @${msg.sender}${fp}${trust}:\n\n${msg.content}`;
22
+ return {
23
+ content: [{ type: "text", text }],
24
+ };
25
+ });
26
+ }
27
+ //# sourceMappingURL=get-message.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-message.js","sourceRoot":"","sources":["../../src/tools/get-message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,MAAM,UAAU,sBAAsB,CAAC,MAAiB,EAAE,SAAgC;IACxF,MAAM,CAAC,YAAY,CACjB,aAAa,EACb;QACE,KAAK,EAAE,aAAa;QACpB,WAAW,EAAE,2GAA2G;QACxH,WAAW,EAAE;YACX,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,uCAAuC,CAAC;SACjE;KACF,EACD,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE;QACf,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;QAE5C,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,WAAW,EAAE,aAAa,EAAE,CAAC;aACvE,CAAC;QACJ,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,kBAAkB,EAAE,CAAC;QAC1D,MAAM,KAAK,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,UAAU,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACzE,MAAM,EAAE,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,MAAM,KAAK,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,OAAO,MAAM,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;QACzF,MAAM,IAAI,GAAG,IAAI,IAAI,KAAK,KAAK,OAAO,GAAG,CAAC,MAAM,GAAG,EAAE,GAAG,KAAK,QAAQ,GAAG,CAAC,OAAO,EAAE,CAAC;QAEnF,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,CAAC;SAC3C,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -5,9 +5,11 @@ import { registerNameTool } from "./name.js";
5
5
  import { registerChannelTools } from "./channel.js";
6
6
  import { registerUnreadTool } from "./unread.js";
7
7
  import { registerMuteTools } from "./mute.js";
8
+ import { registerGetMessageTool } from "./get-message.js";
8
9
  export function registerAllTools(server, getClient) {
9
10
  registerSendTool(server, getClient);
10
11
  registerReadTool(server, getClient);
12
+ registerGetMessageTool(server, getClient);
11
13
  registerMembersTool(server, getClient);
12
14
  registerNameTool(server, getClient);
13
15
  registerChannelTools(server, getClient);
@@ -1 +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;AAC7C,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAE9C,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;IACpC,oBAAoB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACxC,kBAAkB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACtC,iBAAiB,CAAC,MAAM,CAAC,CAAC;AAC5B,CAAC"}
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;AAC7C,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAE1D,MAAM,UAAU,gBAAgB,CAAC,MAAiB,EAAE,SAAgC;IAClF,gBAAgB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACpC,gBAAgB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACpC,sBAAsB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAC1C,mBAAmB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACvC,gBAAgB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACpC,oBAAoB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACxC,kBAAkB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACtC,iBAAiB,CAAC,MAAM,CAAC,CAAC;AAC5B,CAAC"}
@@ -2,22 +2,27 @@ import { z } from "zod";
2
2
  export function registerMembersTool(server, getClient) {
3
3
  server.registerTool("list_members", {
4
4
  title: "List Members",
5
- description: "List members in a channel with last active time.",
5
+ description: "List members in a #channel or ##subchannel with last active time and fingerprint.",
6
6
  inputSchema: {
7
7
  channel: z.string().optional().describe("Channel name (optional, shows all if omitted)"),
8
+ subchannel: z.string().optional().describe("Subchannel name"),
8
9
  },
9
- }, async ({ channel }) => {
10
+ }, async ({ channel, subchannel }) => {
10
11
  const client = getClient();
11
- const members = client.store.getMembers(channel);
12
+ const key = subchannel && channel ? `${channel}/${subchannel}` : channel;
13
+ const members = client.store.getMembers(key);
12
14
  if (members.length === 0) {
15
+ const label = subchannel ? `#${channel} ##${subchannel}` : channel ? `#${channel}` : "any channel";
13
16
  return {
14
- content: [{ type: "text", text: channel ? `No members in #${channel}.` : "No members." }],
17
+ content: [{ type: "text", text: `No members in ${label}.` }],
15
18
  };
16
19
  }
17
20
  const formatted = members
18
21
  .map((m) => {
19
22
  const active = client.store.formatLastActive(m.lastActive);
20
- return `- @${m.name} in #${m.channel} (active ${active})`;
23
+ const label = m.subchannel ? `#${m.channel} ##${m.subchannel}` : `#${m.channel}`;
24
+ const fp = m.fingerprint ? `:${m.fingerprint.slice(0, 4)}` : "";
25
+ return `- @${m.name}${fp} in ${label} (active ${active})`;
21
26
  })
22
27
  .join("\n");
23
28
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"members.js","sourceRoot":"","sources":["../../src/tools/members.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,MAAM,UAAU,mBAAmB,CAAC,MAAiB,EAAE,SAAgC;IACrF,MAAM,CAAC,YAAY,CACjB,cAAc,EACd;QACE,KAAK,EAAE,cAAc;QACrB,WAAW,EAAE,kDAAkD;QAC/D,WAAW,EAAE;YACX,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,+CAA+C,CAAC;SACzF;KACF,EACD,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;QACpB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAEjD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,kBAAkB,OAAO,GAAG,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;aACnG,CAAC;QACJ,CAAC;QAED,MAAM,SAAS,GAAG,OAAO;aACtB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACT,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;YAC3D,OAAO,MAAM,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC,OAAO,YAAY,MAAM,GAAG,CAAC;QAC5D,CAAC,CAAC;aACD,IAAI,CAAC,IAAI,CAAC,CAAC;QAEd,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,aAAa,SAAS,EAAE,EAAE,CAAC;SACrE,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"members.js","sourceRoot":"","sources":["../../src/tools/members.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,MAAM,UAAU,mBAAmB,CAAC,MAAiB,EAAE,SAAgC;IACrF,MAAM,CAAC,YAAY,CACjB,cAAc,EACd;QACE,KAAK,EAAE,cAAc;QACrB,WAAW,EAAE,mFAAmF;QAChG,WAAW,EAAE;YACX,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,+CAA+C,CAAC;YACxF,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,iBAAiB,CAAC;SAC9D;KACF,EACD,KAAK,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,EAAE;QAChC,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,GAAG,GAAG,UAAU,IAAI,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,IAAI,UAAU,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;QACzE,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QAE7C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,MAAM,KAAK,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,OAAO,MAAM,UAAU,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,OAAO,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC;YACnG,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,iBAAiB,KAAK,GAAG,EAAE,CAAC;aACtE,CAAC;QACJ,CAAC;QAED,MAAM,SAAS,GAAG,OAAO;aACtB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACT,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;YAC3D,MAAM,KAAK,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,MAAM,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;YACjF,MAAM,EAAE,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAChE,OAAO,MAAM,CAAC,CAAC,IAAI,GAAG,EAAE,OAAO,KAAK,YAAY,MAAM,GAAG,CAAC;QAC5D,CAAC,CAAC;aACD,IAAI,CAAC,IAAI,CAAC,CAAC;QAEd,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,aAAa,SAAS,EAAE,EAAE,CAAC;SACrE,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -2,17 +2,22 @@ import { z } from "zod";
2
2
  export function registerReadTool(server, getClient) {
3
3
  server.registerTool("read_messages", {
4
4
  title: "Read Messages",
5
- description: "Read recent messages from channels.",
5
+ description: "Read recent messages from #channels or ##subchannels. Use preview=true to get a compact list (saves tokens), then get_message to read full content.",
6
6
  inputSchema: {
7
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)"),
8
+ channel: z.string().optional().describe("Filter by channel name"),
9
+ subchannel: z.string().optional().describe("Filter by subchannel name"),
10
+ preview: z.boolean().optional().default(false).describe("If true, return compact preview (id + sender + first line only). Use get_message(id) to read full content."),
9
11
  },
10
- }, async ({ limit, channel }) => {
12
+ }, async ({ limit, channel, subchannel, preview }) => {
11
13
  const client = getClient();
12
14
  let messages = client.store.getMessages(Math.min(limit, 100));
13
15
  if (channel) {
14
16
  messages = messages.filter((m) => m.channel === channel);
15
17
  }
18
+ if (subchannel) {
19
+ messages = messages.filter((m) => m.subchannel === subchannel);
20
+ }
16
21
  if (messages.length === 0) {
17
22
  return {
18
23
  content: [{ type: "text", text: "No messages yet." }],
@@ -25,7 +30,15 @@ export function registerReadTool(server, getClient) {
25
30
  const mention = m.content.includes(`@${myName}`) ? " [MENTION]" : "";
26
31
  if (m.type === "system")
27
32
  return `[${time}] ${m.content}`;
28
- return `[${time}] #${m.channel} | @${m.sender}: ${m.content}${mention}`;
33
+ const label = m.subchannel ? `#${m.channel} ##${m.subchannel}` : `#${m.channel}`;
34
+ const fp = m.senderKey ? `:${m.senderKey.slice(0, 4)}` : "";
35
+ if (preview) {
36
+ const firstLine = m.content.split("\n").find((l) => l.trim()) || m.content;
37
+ const short = firstLine.length > 80 ? firstLine.slice(0, 80) + "..." : firstLine;
38
+ return `[${m.id}] [${time}] ${label} | @${m.sender}${fp}: ${short}${mention}`;
39
+ }
40
+ const trust = m.trustLevel ? ` [${m.trustLevel.toUpperCase()}]` : "";
41
+ return `[${time}] ${label} | @${m.sender}${fp}${trust}: ${m.content}${mention}`;
29
42
  })
30
43
  .join("\n");
31
44
  client.store.markAsRead();
@@ -1 +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,MAAM,GAAG,MAAM,CAAC,UAAU,CAAC;QACjC,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,MAAM,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;YACrE,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ;gBAAE,OAAO,IAAI,IAAI,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC;YACzD,OAAO,IAAI,IAAI,MAAM,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,OAAO,GAAG,OAAO,EAAE,CAAC;QAC1E,CAAC,CAAC;aACD,IAAI,CAAC,IAAI,CAAC,CAAC;QAEd,MAAM,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC;QAE1B,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;SACtD,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"read.js","sourceRoot":"","sources":["../../src/tools/read.ts"],"names":[],"mappings":"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"}
@@ -2,19 +2,22 @@ import { z } from "zod";
2
2
  export function registerSendTool(server, getClient) {
3
3
  server.registerTool("send_message", {
4
4
  title: "Send Message",
5
- description: "Send an encrypted message to a channel. All members with the same channel key will receive it.",
5
+ description: "Send an encrypted message to a #channel or ##subchannel.",
6
6
  inputSchema: {
7
7
  message: z.string().describe("The message content to send"),
8
- channel: z.string().describe("Target channel name (required)"),
8
+ channel: z.string().describe("Target channel name (e.g. 'agentchannel')"),
9
+ subchannel: z.string().optional().describe("Target subchannel name (e.g. 'product'). Omit to send to the main channel."),
9
10
  },
10
- }, async ({ message, channel }) => {
11
+ }, async ({ message, channel, subchannel }) => {
11
12
  const client = getClient();
12
- const msg = await client.send(message, channel);
13
+ const target = subchannel ? `${channel}/${subchannel}` : channel;
14
+ const msg = await client.send(message, target);
15
+ const label = msg.subchannel ? `#${msg.channel} ##${msg.subchannel}` : `#${msg.channel}`;
13
16
  return {
14
17
  content: [
15
18
  {
16
19
  type: "text",
17
- text: `Message sent to #${msg.channel} by ${msg.sender} at ${new Date(msg.timestamp).toISOString()}`,
20
+ text: `Message sent to ${label} by @${msg.sender} at ${new Date(msg.timestamp).toISOString()}`,
18
21
  },
19
22
  ],
20
23
  };
@@ -1 +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,CAAC,gCAAgC,CAAC;SAC/D;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"}
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,0DAA0D;QACvE,WAAW,EAAE;YACX,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,6BAA6B,CAAC;YAC3D,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2CAA2C,CAAC;YACzE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,4EAA4E,CAAC;SACzH;KACF,EACD,KAAK,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,EAAE;QACzC,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,GAAG,OAAO,IAAI,UAAU,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;QACjE,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC/C,MAAM,KAAK,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,OAAO,MAAM,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;QACzF,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,mBAAmB,KAAK,QAAQ,GAAG,CAAC,MAAM,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,EAAE;iBAC/F;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,14 @@
1
+ export type TrustLevel = "tofu" | "verified" | "revoked" | "new";
2
+ export interface KnownKey {
3
+ publicKeyPem: string;
4
+ fingerprint: string;
5
+ displayName: string;
6
+ firstSeen: number;
7
+ lastSeen: number;
8
+ trustLevel: TrustLevel;
9
+ }
10
+ export declare function checkTrust(fingerprint: string, publicKeyPem: string, displayName: string): {
11
+ level: TrustLevel;
12
+ warning?: string;
13
+ };
14
+ export declare function getTrustLevel(fingerprint: string): TrustLevel;
@@ -0,0 +1,56 @@
1
+ import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { homedir } from "node:os";
4
+ const TRUST_FILE = join(homedir(), ".agentchannel", "known_keys.json");
5
+ let cache = null;
6
+ function load() {
7
+ if (cache)
8
+ return cache;
9
+ try {
10
+ cache = JSON.parse(readFileSync(TRUST_FILE, "utf-8"));
11
+ return cache;
12
+ }
13
+ catch {
14
+ cache = {};
15
+ return cache;
16
+ }
17
+ }
18
+ function save() {
19
+ mkdirSync(join(homedir(), ".agentchannel"), { recursive: true });
20
+ writeFileSync(TRUST_FILE, JSON.stringify(cache, null, 2));
21
+ }
22
+ export function checkTrust(fingerprint, publicKeyPem, displayName) {
23
+ const store = load();
24
+ const existing = store[fingerprint];
25
+ if (!existing) {
26
+ // First time seeing this key — TOFU
27
+ store[fingerprint] = {
28
+ publicKeyPem,
29
+ fingerprint,
30
+ displayName,
31
+ firstSeen: Date.now(),
32
+ lastSeen: Date.now(),
33
+ trustLevel: "tofu",
34
+ };
35
+ save();
36
+ return { level: "tofu" };
37
+ }
38
+ if (existing.trustLevel === "revoked") {
39
+ return { level: "revoked", warning: `Key ${fingerprint} has been revoked` };
40
+ }
41
+ // Update last seen
42
+ existing.lastSeen = Date.now();
43
+ // Check if display name changed
44
+ let warning;
45
+ if (existing.displayName !== displayName) {
46
+ warning = `Display name changed: "${existing.displayName}" → "${displayName}"`;
47
+ existing.displayName = displayName;
48
+ }
49
+ save();
50
+ return { level: existing.trustLevel, warning };
51
+ }
52
+ export function getTrustLevel(fingerprint) {
53
+ const store = load();
54
+ return store[fingerprint]?.trustLevel ?? "new";
55
+ }
56
+ //# sourceMappingURL=trust-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trust-store.js","sourceRoot":"","sources":["../src/trust-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACjE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,eAAe,EAAE,iBAAiB,CAAC,CAAC;AAavE,IAAI,KAAK,GAAoC,IAAI,CAAC;AAElD,SAAS,IAAI;IACX,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC;IACxB,IAAI,CAAC;QACH,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;QACtD,OAAO,KAAM,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,KAAK,GAAG,EAAE,CAAC;QACX,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,IAAI;IACX,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,eAAe,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACjE,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAC5D,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,WAAmB,EAAE,YAAoB,EAAE,WAAmB;IACvF,MAAM,KAAK,GAAG,IAAI,EAAE,CAAC;IACrB,MAAM,QAAQ,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC;IAEpC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,oCAAoC;QACpC,KAAK,CAAC,WAAW,CAAC,GAAG;YACnB,YAAY;YACZ,WAAW;YACX,WAAW;YACX,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;YACrB,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE;YACpB,UAAU,EAAE,MAAM;SACnB,CAAC;QACF,IAAI,EAAE,CAAC;QACP,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAC3B,CAAC;IAED,IAAI,QAAQ,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QACtC,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,WAAW,mBAAmB,EAAE,CAAC;IAC9E,CAAC;IAED,mBAAmB;IACnB,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAE/B,gCAAgC;IAChC,IAAI,OAA2B,CAAC;IAChC,IAAI,QAAQ,CAAC,WAAW,KAAK,WAAW,EAAE,CAAC;QACzC,OAAO,GAAG,0BAA0B,QAAQ,CAAC,WAAW,QAAQ,WAAW,GAAG,CAAC;QAC/E,QAAQ,CAAC,WAAW,GAAG,WAAW,CAAC;IACrC,CAAC;IAED,IAAI,EAAE,CAAC;IACP,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAC,UAAU,EAAE,OAAO,EAAE,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,WAAmB;IAC/C,MAAM,KAAK,GAAG,IAAI,EAAE,CAAC;IACrB,OAAO,KAAK,CAAC,WAAW,CAAC,EAAE,UAAU,IAAI,KAAK,CAAC;AACjD,CAAC"}
package/dist/types.d.ts CHANGED
@@ -1,31 +1,47 @@
1
1
  export interface Message {
2
2
  id: string;
3
3
  channel: string;
4
+ subchannel?: string;
4
5
  sender: string;
5
6
  content: string;
6
7
  timestamp: number;
7
- type?: "chat" | "system" | "action_request";
8
+ type?: "chat" | "system" | "action_request" | "channel_meta";
9
+ senderKey?: string;
10
+ signature?: string;
11
+ trustLevel?: string;
8
12
  }
9
13
  export interface Member {
10
14
  name: string;
11
15
  channel: string;
16
+ subchannel?: string;
12
17
  joinedAt: number;
13
18
  lastActive: number;
19
+ fingerprint?: string;
14
20
  }
15
21
  export interface ChannelConfig {
16
22
  channel: string;
23
+ subchannel?: string;
17
24
  key: string;
18
25
  }
19
26
  export interface ChatConfig {
20
27
  channels: ChannelConfig[];
21
28
  name: string;
22
29
  broker?: string;
30
+ silent?: boolean;
23
31
  }
24
32
  export interface SingleChannelConfig {
25
33
  channel: string;
34
+ subchannel?: string;
26
35
  name: string;
27
36
  key: string;
28
37
  broker?: string;
38
+ silent?: boolean;
39
+ }
40
+ export interface ChannelMeta {
41
+ name: string;
42
+ subchannels: string[];
43
+ owners: string[];
44
+ created: number;
29
45
  }
30
46
  export interface EncryptedPayload {
31
47
  iv: string;