@suzuke/agend 0.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/README.md +78 -0
  2. package/README.zh-TW.md +79 -0
  3. package/dist/access-path.d.ts +7 -0
  4. package/dist/access-path.js +12 -0
  5. package/dist/access-path.js.map +1 -0
  6. package/dist/backend/claude-code.d.ts +13 -0
  7. package/dist/backend/claude-code.js +114 -0
  8. package/dist/backend/claude-code.js.map +1 -0
  9. package/dist/backend/codex.d.ts +10 -0
  10. package/dist/backend/codex.js +58 -0
  11. package/dist/backend/codex.js.map +1 -0
  12. package/dist/backend/factory.d.ts +2 -0
  13. package/dist/backend/factory.js +19 -0
  14. package/dist/backend/factory.js.map +1 -0
  15. package/dist/backend/gemini-cli.d.ts +10 -0
  16. package/dist/backend/gemini-cli.js +68 -0
  17. package/dist/backend/gemini-cli.js.map +1 -0
  18. package/dist/backend/index.d.ts +6 -0
  19. package/dist/backend/index.js +6 -0
  20. package/dist/backend/index.js.map +1 -0
  21. package/dist/backend/opencode.d.ts +10 -0
  22. package/dist/backend/opencode.js +63 -0
  23. package/dist/backend/opencode.js.map +1 -0
  24. package/dist/backend/types.d.ts +26 -0
  25. package/dist/backend/types.js +2 -0
  26. package/dist/backend/types.js.map +1 -0
  27. package/dist/channel/access-manager.d.ts +18 -0
  28. package/dist/channel/access-manager.js +149 -0
  29. package/dist/channel/access-manager.js.map +1 -0
  30. package/dist/channel/adapters/discord.d.ts +45 -0
  31. package/dist/channel/adapters/discord.js +366 -0
  32. package/dist/channel/adapters/discord.js.map +1 -0
  33. package/dist/channel/adapters/telegram.d.ts +58 -0
  34. package/dist/channel/adapters/telegram.js +569 -0
  35. package/dist/channel/adapters/telegram.js.map +1 -0
  36. package/dist/channel/attachment-handler.d.ts +15 -0
  37. package/dist/channel/attachment-handler.js +55 -0
  38. package/dist/channel/attachment-handler.js.map +1 -0
  39. package/dist/channel/factory.d.ts +12 -0
  40. package/dist/channel/factory.js +38 -0
  41. package/dist/channel/factory.js.map +1 -0
  42. package/dist/channel/ipc-bridge.d.ts +26 -0
  43. package/dist/channel/ipc-bridge.js +170 -0
  44. package/dist/channel/ipc-bridge.js.map +1 -0
  45. package/dist/channel/mcp-server.d.ts +10 -0
  46. package/dist/channel/mcp-server.js +196 -0
  47. package/dist/channel/mcp-server.js.map +1 -0
  48. package/dist/channel/mcp-tools.d.ts +909 -0
  49. package/dist/channel/mcp-tools.js +346 -0
  50. package/dist/channel/mcp-tools.js.map +1 -0
  51. package/dist/channel/message-bus.d.ts +17 -0
  52. package/dist/channel/message-bus.js +86 -0
  53. package/dist/channel/message-bus.js.map +1 -0
  54. package/dist/channel/message-queue.d.ts +39 -0
  55. package/dist/channel/message-queue.js +248 -0
  56. package/dist/channel/message-queue.js.map +1 -0
  57. package/dist/channel/tool-router.d.ts +6 -0
  58. package/dist/channel/tool-router.js +69 -0
  59. package/dist/channel/tool-router.js.map +1 -0
  60. package/dist/channel/tool-tracker.d.ts +13 -0
  61. package/dist/channel/tool-tracker.js +58 -0
  62. package/dist/channel/tool-tracker.js.map +1 -0
  63. package/dist/channel/types.d.ts +116 -0
  64. package/dist/channel/types.js +2 -0
  65. package/dist/channel/types.js.map +1 -0
  66. package/dist/cli.d.ts +2 -0
  67. package/dist/cli.js +782 -0
  68. package/dist/cli.js.map +1 -0
  69. package/dist/config.d.ts +8 -0
  70. package/dist/config.js +85 -0
  71. package/dist/config.js.map +1 -0
  72. package/dist/context-guardian.d.ts +29 -0
  73. package/dist/context-guardian.js +123 -0
  74. package/dist/context-guardian.js.map +1 -0
  75. package/dist/cost-guard.d.ts +21 -0
  76. package/dist/cost-guard.js +113 -0
  77. package/dist/cost-guard.js.map +1 -0
  78. package/dist/daemon-entry.d.ts +1 -0
  79. package/dist/daemon-entry.js +29 -0
  80. package/dist/daemon-entry.js.map +1 -0
  81. package/dist/daemon.d.ts +88 -0
  82. package/dist/daemon.js +821 -0
  83. package/dist/daemon.js.map +1 -0
  84. package/dist/daily-summary.d.ts +13 -0
  85. package/dist/daily-summary.js +55 -0
  86. package/dist/daily-summary.js.map +1 -0
  87. package/dist/event-log.d.ts +22 -0
  88. package/dist/event-log.js +66 -0
  89. package/dist/event-log.js.map +1 -0
  90. package/dist/export-import.d.ts +2 -0
  91. package/dist/export-import.js +110 -0
  92. package/dist/export-import.js.map +1 -0
  93. package/dist/fleet-context.d.ts +36 -0
  94. package/dist/fleet-context.js +4 -0
  95. package/dist/fleet-context.js.map +1 -0
  96. package/dist/fleet-manager.d.ts +115 -0
  97. package/dist/fleet-manager.js +1739 -0
  98. package/dist/fleet-manager.js.map +1 -0
  99. package/dist/fleet-system-prompt.d.ts +11 -0
  100. package/dist/fleet-system-prompt.js +60 -0
  101. package/dist/fleet-system-prompt.js.map +1 -0
  102. package/dist/hang-detector.d.ts +16 -0
  103. package/dist/hang-detector.js +53 -0
  104. package/dist/hang-detector.js.map +1 -0
  105. package/dist/index.d.ts +8 -0
  106. package/dist/index.js +6 -0
  107. package/dist/index.js.map +1 -0
  108. package/dist/logger.d.ts +3 -0
  109. package/dist/logger.js +63 -0
  110. package/dist/logger.js.map +1 -0
  111. package/dist/plugin/agend/.claude-plugin/plugin.json +5 -0
  112. package/dist/scheduler/db.d.ts +16 -0
  113. package/dist/scheduler/db.js +132 -0
  114. package/dist/scheduler/db.js.map +1 -0
  115. package/dist/scheduler/db.test.d.ts +1 -0
  116. package/dist/scheduler/db.test.js +92 -0
  117. package/dist/scheduler/db.test.js.map +1 -0
  118. package/dist/scheduler/index.d.ts +4 -0
  119. package/dist/scheduler/index.js +4 -0
  120. package/dist/scheduler/index.js.map +1 -0
  121. package/dist/scheduler/scheduler.d.ts +25 -0
  122. package/dist/scheduler/scheduler.js +119 -0
  123. package/dist/scheduler/scheduler.js.map +1 -0
  124. package/dist/scheduler/scheduler.test.d.ts +1 -0
  125. package/dist/scheduler/scheduler.test.js +119 -0
  126. package/dist/scheduler/scheduler.test.js.map +1 -0
  127. package/dist/scheduler/types.d.ts +47 -0
  128. package/dist/scheduler/types.js +7 -0
  129. package/dist/scheduler/types.js.map +1 -0
  130. package/dist/service-installer.d.ts +14 -0
  131. package/dist/service-installer.js +91 -0
  132. package/dist/service-installer.js.map +1 -0
  133. package/dist/setup-wizard.d.ts +14 -0
  134. package/dist/setup-wizard.js +517 -0
  135. package/dist/setup-wizard.js.map +1 -0
  136. package/dist/stt.d.ts +10 -0
  137. package/dist/stt.js +33 -0
  138. package/dist/stt.js.map +1 -0
  139. package/dist/tmux-manager.d.ts +22 -0
  140. package/dist/tmux-manager.js +132 -0
  141. package/dist/tmux-manager.js.map +1 -0
  142. package/dist/topic-commands.d.ts +22 -0
  143. package/dist/topic-commands.js +176 -0
  144. package/dist/topic-commands.js.map +1 -0
  145. package/dist/transcript-monitor.d.ts +21 -0
  146. package/dist/transcript-monitor.js +149 -0
  147. package/dist/transcript-monitor.js.map +1 -0
  148. package/dist/types.d.ts +153 -0
  149. package/dist/types.js +2 -0
  150. package/dist/types.js.map +1 -0
  151. package/dist/webhook-emitter.d.ts +15 -0
  152. package/dist/webhook-emitter.js +41 -0
  153. package/dist/webhook-emitter.js.map +1 -0
  154. package/package.json +58 -4
  155. package/templates/launchd.plist.ejs +29 -0
  156. package/templates/systemd.service.ejs +15 -0
  157. package/index.js +0 -1
@@ -0,0 +1,15 @@
1
+ import type { InboundMessage, ChannelAdapter } from "./types.js";
2
+ export interface AttachmentResult {
3
+ text: string;
4
+ extraMeta: Record<string, string>;
5
+ }
6
+ /**
7
+ * Process attachments on an inbound message:
8
+ * - Auto-download photos → extraMeta.image_path
9
+ * - Transcribe voice/audio via Groq Whisper → prepend to text
10
+ * - Pass other attachment types as file_id for manual download
11
+ */
12
+ export declare function processAttachments(msg: InboundMessage, adapter: ChannelAdapter, logger: {
13
+ info(obj: unknown, msg?: string): void;
14
+ warn(obj: unknown, msg?: string): void;
15
+ }, logPrefix?: string): Promise<AttachmentResult>;
@@ -0,0 +1,55 @@
1
+ import { unlinkSync } from "node:fs";
2
+ import { transcribe } from "../stt.js";
3
+ /**
4
+ * Process attachments on an inbound message:
5
+ * - Auto-download photos → extraMeta.image_path
6
+ * - Transcribe voice/audio via Groq Whisper → prepend to text
7
+ * - Pass other attachment types as file_id for manual download
8
+ */
9
+ export async function processAttachments(msg, adapter, logger, logPrefix) {
10
+ let text = msg.text;
11
+ const extraMeta = {};
12
+ // Auto-download photos so Claude can Read them directly
13
+ const photoAttachment = msg.attachments?.find(a => a.kind === "photo");
14
+ if (photoAttachment) {
15
+ try {
16
+ const localPath = await adapter.downloadAttachment(photoAttachment.fileId);
17
+ extraMeta.image_path = localPath;
18
+ }
19
+ catch (err) {
20
+ logger.warn({ err: err.message }, "Photo download failed");
21
+ }
22
+ }
23
+ // Transcribe voice/audio
24
+ const voiceAttachment = msg.attachments?.find(a => a.kind === "voice" || a.kind === "audio");
25
+ if (voiceAttachment) {
26
+ const groqKey = process.env.GROQ_API_KEY;
27
+ if (groqKey) {
28
+ try {
29
+ const localPath = await adapter.downloadAttachment(voiceAttachment.fileId);
30
+ const result = await transcribe(localPath, groqKey);
31
+ try {
32
+ unlinkSync(localPath);
33
+ }
34
+ catch { /* ignore */ }
35
+ text = text ? `${text}\n\n[語音訊息] ${result.text}` : `[語音訊息] ${result.text}`;
36
+ logger.info({ ...(logPrefix ? { context: logPrefix } : {}), transcription: result.text.slice(0, 80) }, "Voice transcribed");
37
+ }
38
+ catch (err) {
39
+ logger.warn({ err: err.message }, "Voice transcription failed");
40
+ text = text || "[語音訊息 — 轉錄失敗]";
41
+ }
42
+ }
43
+ else {
44
+ text = text || "[語音訊息 — 未設定 STT API key]";
45
+ }
46
+ extraMeta.attachment_file_id = voiceAttachment.fileId;
47
+ }
48
+ // Pass other attachment types as file_id for manual download
49
+ const otherAttachment = msg.attachments?.find(a => a.kind !== "photo" && a.kind !== "voice" && a.kind !== "audio");
50
+ if (otherAttachment) {
51
+ extraMeta.attachment_file_id = otherAttachment.fileId;
52
+ }
53
+ return { text, extraMeta };
54
+ }
55
+ //# sourceMappingURL=attachment-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attachment-handler.js","sourceRoot":"","sources":["../../src/channel/attachment-handler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { ChannelAdapter } from "./types.js";
2
+ import type { ChannelConfig } from "../types.js";
3
+ import type { AccessManager } from "./access-manager.js";
4
+ export interface AdapterOpts {
5
+ id: string;
6
+ botToken: string;
7
+ accessManager: AccessManager;
8
+ inboxDir: string;
9
+ }
10
+ /** Factory function that external adapter packages must default-export. */
11
+ export type AdapterFactory = (config: ChannelConfig, opts: AdapterOpts) => ChannelAdapter;
12
+ export declare function createAdapter(config: ChannelConfig, opts: AdapterOpts): Promise<ChannelAdapter>;
@@ -0,0 +1,38 @@
1
+ export async function createAdapter(config, opts) {
2
+ switch (config.type) {
3
+ case "telegram": {
4
+ const { TelegramAdapter } = await import("./adapters/telegram.js");
5
+ return new TelegramAdapter(opts);
6
+ }
7
+ case "discord": {
8
+ const { DiscordAdapter } = await import("./adapters/discord.js");
9
+ return new DiscordAdapter({
10
+ ...opts,
11
+ guildId: config.group_id != null ? String(config.group_id) : "",
12
+ categoryName: config.options?.category_name ?? undefined,
13
+ generalChannelId: config.options?.general_channel_id ?? undefined,
14
+ });
15
+ }
16
+ default: {
17
+ // External adapter — try canonical name, then bare name
18
+ const candidates = [`agend-adapter-${config.type}`, config.type];
19
+ let factory;
20
+ for (const pkg of candidates) {
21
+ try {
22
+ const mod = await import(pkg);
23
+ factory = mod.default;
24
+ break;
25
+ }
26
+ catch {
27
+ continue;
28
+ }
29
+ }
30
+ if (!factory) {
31
+ throw new Error(`Channel adapter "${config.type}" not found. ` +
32
+ `Install it: npm install agend-adapter-${config.type}`);
33
+ }
34
+ return factory(config, opts);
35
+ }
36
+ }
37
+ }
38
+ //# sourceMappingURL=factory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory.js","sourceRoot":"","sources":["../../src/channel/factory.ts"],"names":[],"mappings":"AAcA,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,MAAqB,EAAE,IAAiB;IAC1E,QAAQ,MAAM,CAAC,IAAI,EAAE,CAAC;QACpB,KAAK,UAAU,CAAC,CAAC,CAAC;YAChB,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,MAAM,CAAC,wBAAwB,CAAC,CAAC;YACnE,OAAO,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC;QACnC,CAAC;QACD,KAAK,SAAS,CAAC,CAAC,CAAC;YACf,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,MAAM,CAAC,uBAAuB,CAAC,CAAC;YACjE,OAAO,IAAI,cAAc,CAAC;gBACxB,GAAG,IAAI;gBACP,OAAO,EAAE,MAAM,CAAC,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;gBAC/D,YAAY,EAAG,MAAM,CAAC,OAAO,EAAE,aAAwB,IAAI,SAAS;gBACpE,gBAAgB,EAAG,MAAM,CAAC,OAAO,EAAE,kBAA6B,IAAI,SAAS;aAC9E,CAAC,CAAC;QACL,CAAC;QACD,OAAO,CAAC,CAAC,CAAC;YACR,wDAAwD;YACxD,MAAM,UAAU,GAAG,CAAC,iBAAiB,MAAM,CAAC,IAAI,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;YACjE,IAAI,OAAmC,CAAC;YAExC,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;gBAC7B,IAAI,CAAC;oBACH,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,CAAC;oBAC9B,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC;oBACtB,MAAM;gBACR,CAAC;gBAAC,MAAM,CAAC;oBACP,SAAS;gBACX,CAAC;YACH,CAAC;YAED,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,MAAM,IAAI,KAAK,CACb,oBAAoB,MAAM,CAAC,IAAI,eAAe;oBAC9C,yCAAyC,MAAM,CAAC,IAAI,EAAE,CACvD,CAAC;YACJ,CAAC;YAED,OAAO,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,26 @@
1
+ import { EventEmitter } from "node:events";
2
+ import { Socket } from "node:net";
3
+ export declare class IpcServer extends EventEmitter {
4
+ private sockPath;
5
+ private server;
6
+ private clients;
7
+ private logger?;
8
+ constructor(sockPath: string, logger?: {
9
+ warn(obj: unknown, msg?: string): void;
10
+ debug(obj: unknown, msg?: string): void;
11
+ });
12
+ listen(): Promise<void>;
13
+ private acceptClient;
14
+ broadcast(msg: unknown): void;
15
+ send(socket: Socket, msg: unknown): void;
16
+ close(): Promise<void>;
17
+ }
18
+ export declare class IpcClient extends EventEmitter {
19
+ private sockPath;
20
+ private socket;
21
+ constructor(sockPath: string);
22
+ connect(): Promise<void>;
23
+ get connected(): boolean;
24
+ send(msg: unknown): void;
25
+ close(): Promise<void>;
26
+ }
@@ -0,0 +1,170 @@
1
+ import { EventEmitter } from "node:events";
2
+ import { createServer, createConnection, } from "node:net";
3
+ import { unlinkSync, existsSync, chmodSync } from "node:fs";
4
+ function encode(msg) {
5
+ return JSON.stringify(msg) + "\n";
6
+ }
7
+ const MAX_LINE_BUFFER = 10 * 1024 * 1024; // 10 MB
8
+ function makeLineParser(onMessage, onOverflow) {
9
+ let buf = "";
10
+ return (data) => {
11
+ buf += data.toString();
12
+ if (buf.length > MAX_LINE_BUFFER) {
13
+ buf = "";
14
+ onOverflow?.();
15
+ return;
16
+ }
17
+ const lines = buf.split("\n");
18
+ // Last element is either empty string or an incomplete line
19
+ buf = lines.pop() ?? "";
20
+ for (const line of lines) {
21
+ if (line.trim() === "")
22
+ continue;
23
+ let msg;
24
+ try {
25
+ msg = JSON.parse(line);
26
+ }
27
+ catch {
28
+ continue; // truly malformed JSON, skip this line
29
+ }
30
+ onMessage(msg);
31
+ }
32
+ };
33
+ }
34
+ export class IpcServer extends EventEmitter {
35
+ sockPath;
36
+ server = null;
37
+ clients = new Set();
38
+ logger;
39
+ constructor(sockPath, logger) {
40
+ super();
41
+ this.sockPath = sockPath;
42
+ this.logger = logger;
43
+ }
44
+ async listen() {
45
+ // Clean up stale socket file if it exists
46
+ if (existsSync(this.sockPath)) {
47
+ try {
48
+ unlinkSync(this.sockPath);
49
+ }
50
+ catch {
51
+ // Ignore if already gone — race with another process
52
+ }
53
+ }
54
+ return new Promise((resolve, reject) => {
55
+ this.server = createServer((socket) => {
56
+ this.acceptClient(socket);
57
+ });
58
+ this.server.on("error", reject);
59
+ this.server.listen(this.sockPath, () => {
60
+ try {
61
+ chmodSync(this.sockPath, 0o600);
62
+ }
63
+ catch { /* best-effort */ }
64
+ resolve();
65
+ });
66
+ });
67
+ }
68
+ acceptClient(socket) {
69
+ this.clients.add(socket);
70
+ const parse = makeLineParser((msg) => {
71
+ this.emit("message", msg, socket);
72
+ }, () => {
73
+ this.logger?.warn("IPC buffer overflow, dropping client");
74
+ socket.destroy();
75
+ this.clients.delete(socket);
76
+ });
77
+ socket.on("data", parse);
78
+ socket.on("close", () => {
79
+ this.clients.delete(socket);
80
+ });
81
+ socket.on("error", (err) => {
82
+ this.logger?.warn({ err }, "IPC client socket error, removing client");
83
+ this.clients.delete(socket);
84
+ });
85
+ }
86
+ broadcast(msg) {
87
+ const data = encode(msg);
88
+ for (const client of this.clients) {
89
+ if (!client.destroyed) {
90
+ client.write(data);
91
+ }
92
+ }
93
+ }
94
+ send(socket, msg) {
95
+ if (!socket.destroyed) {
96
+ socket.write(encode(msg));
97
+ }
98
+ }
99
+ async close() {
100
+ for (const client of this.clients) {
101
+ client.destroy();
102
+ }
103
+ this.clients.clear();
104
+ return new Promise((resolve) => {
105
+ if (!this.server) {
106
+ resolve();
107
+ return;
108
+ }
109
+ this.server.close(() => {
110
+ try {
111
+ if (existsSync(this.sockPath)) {
112
+ unlinkSync(this.sockPath);
113
+ }
114
+ }
115
+ catch {
116
+ // Best-effort socket file cleanup on shutdown
117
+ }
118
+ resolve();
119
+ });
120
+ });
121
+ }
122
+ }
123
+ export class IpcClient extends EventEmitter {
124
+ sockPath;
125
+ socket = null;
126
+ constructor(sockPath) {
127
+ super();
128
+ this.sockPath = sockPath;
129
+ }
130
+ async connect() {
131
+ return new Promise((resolve, reject) => {
132
+ const socket = createConnection(this.sockPath);
133
+ this.socket = socket;
134
+ const parse = makeLineParser((msg) => {
135
+ this.emit("message", msg);
136
+ });
137
+ socket.on("data", parse);
138
+ socket.on("error", (err) => {
139
+ this.emit("disconnect", err);
140
+ });
141
+ socket.on("close", () => {
142
+ this.emit("disconnect", new Error("socket closed"));
143
+ });
144
+ socket.once("error", reject);
145
+ socket.once("connect", () => {
146
+ socket.removeListener("error", reject);
147
+ resolve();
148
+ });
149
+ });
150
+ }
151
+ get connected() {
152
+ return this.socket != null && !this.socket.destroyed;
153
+ }
154
+ send(msg) {
155
+ if (this.socket && !this.socket.destroyed) {
156
+ this.socket.write(encode(msg));
157
+ }
158
+ }
159
+ async close() {
160
+ return new Promise((resolve) => {
161
+ if (!this.socket || this.socket.destroyed) {
162
+ resolve();
163
+ return;
164
+ }
165
+ this.socket.once("close", resolve);
166
+ this.socket.destroy();
167
+ });
168
+ }
169
+ }
170
+ //# sourceMappingURL=ipc-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ipc-bridge.js","sourceRoot":"","sources":["../../src/channel/ipc-bridge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * MCP Tool Server for agend.
4
+ *
5
+ * Runs as a SEPARATE process (CLI's child via --mcp-config).
6
+ * Communicates with the daemon through a Unix socket IPC connection.
7
+ * Provides standard MCP tools (reply, send_to_instance, etc.) — no
8
+ * CLI-specific channel protocol. Works with any MCP-compatible CLI.
9
+ */
10
+ export { TOOLS } from "./mcp-tools.js";
@@ -0,0 +1,196 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * MCP Tool Server for agend.
4
+ *
5
+ * Runs as a SEPARATE process (CLI's child via --mcp-config).
6
+ * Communicates with the daemon through a Unix socket IPC connection.
7
+ * Provides standard MCP tools (reply, send_to_instance, etc.) — no
8
+ * CLI-specific channel protocol. Works with any MCP-compatible CLI.
9
+ */
10
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
11
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
12
+ import { ListToolsRequestSchema, CallToolRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
13
+ import { basename } from "node:path";
14
+ import { IpcClient } from "./ipc-bridge.js";
15
+ import { TOOLS } from "./mcp-tools.js";
16
+ // ---------------------------------------------------------------------------
17
+ // Configuration
18
+ // ---------------------------------------------------------------------------
19
+ const SOCKET_PATH = process.env.AGEND_SOCKET_PATH ?? "";
20
+ const IPC_TIMEOUT_MS = 30_000;
21
+ const SLOW_IPC_TIMEOUT_MS = 60_000;
22
+ const SLOW_TOOLS = new Set(["start_instance", "create_instance", "delete_instance"]);
23
+ // ---------------------------------------------------------------------------
24
+ // Safety nets
25
+ // ---------------------------------------------------------------------------
26
+ // When the parent Claude process dies, stdin closes. Exit immediately to avoid
27
+ // becoming an orphaned process that spins CPU forever on reconnect loops.
28
+ process.stdin.on("end", () => {
29
+ process.stderr.write("agend: stdin closed (parent died) — exiting\n");
30
+ process.exit(0);
31
+ });
32
+ process.stdin.resume(); // ensure 'end' fires even if nothing reads stdin
33
+ process.on("unhandledRejection", (err) => {
34
+ process.stderr.write(`agend: unhandled rejection: ${err}\n`);
35
+ });
36
+ process.on("uncaughtException", (err) => {
37
+ process.stderr.write(`agend: uncaught exception: ${err}\n`);
38
+ });
39
+ // ---------------------------------------------------------------------------
40
+ // IPC client with request-response
41
+ // ---------------------------------------------------------------------------
42
+ let ipc = null;
43
+ let ipcConnected = false;
44
+ let requestCounter = 0;
45
+ let reconnecting = false;
46
+ let reconnectAttempts = 0;
47
+ const MAX_RECONNECT_ATTEMPTS = 20; // ~60s of retries
48
+ const pendingRequests = new Map();
49
+ function setupIpcListeners(client) {
50
+ client.on("message", (msg) => {
51
+ if (typeof msg.requestId === "number" && pendingRequests.has(msg.requestId)) {
52
+ const pending = pendingRequests.get(msg.requestId);
53
+ pendingRequests.delete(msg.requestId);
54
+ clearTimeout(pending.timer);
55
+ if (msg.error) {
56
+ pending.reject(new Error(String(msg.error)));
57
+ }
58
+ else {
59
+ pending.resolve(msg.result);
60
+ }
61
+ }
62
+ });
63
+ client.on("disconnect", () => {
64
+ ipcConnected = false;
65
+ process.stderr.write("agend: IPC disconnected — will reconnect\n");
66
+ // Reject all pending requests
67
+ for (const [id, pending] of pendingRequests) {
68
+ clearTimeout(pending.timer);
69
+ pending.reject(new Error("IPC disconnected"));
70
+ pendingRequests.delete(id);
71
+ }
72
+ scheduleReconnect();
73
+ });
74
+ }
75
+ async function connectIpc() {
76
+ try {
77
+ const client = new IpcClient(SOCKET_PATH);
78
+ await client.connect();
79
+ ipc = client;
80
+ ipcConnected = true;
81
+ reconnecting = false;
82
+ reconnectAttempts = 0;
83
+ setupIpcListeners(client);
84
+ // AGEND_INSTANCE_NAME: set by daemon via tmux env (internal sessions)
85
+ // AGEND_SESSION_NAME: set in .mcp.json env (external sessions, optional custom name)
86
+ // Fallback: unique name from working directory + PID (avoids collision when
87
+ // multiple Claude Code sessions work on the same project)
88
+ const sessionName = process.env.AGEND_INSTANCE_NAME
89
+ ?? process.env.AGEND_SESSION_NAME
90
+ ?? `external-${basename(process.cwd())}-${process.pid}`;
91
+ client.send({ type: "mcp_ready", sessionName });
92
+ process.stderr.write("agend: connected to daemon IPC\n");
93
+ }
94
+ catch (err) {
95
+ process.stderr.write(`agend: failed to connect to daemon IPC: ${err}\n`);
96
+ ipcConnected = false;
97
+ scheduleReconnect();
98
+ }
99
+ }
100
+ function scheduleReconnect() {
101
+ if (reconnecting)
102
+ return;
103
+ reconnectAttempts++;
104
+ if (reconnectAttempts > MAX_RECONNECT_ATTEMPTS) {
105
+ process.stderr.write(`agend: max reconnect attempts (${MAX_RECONNECT_ATTEMPTS}) exceeded — exiting\n`);
106
+ process.exit(1);
107
+ }
108
+ reconnecting = true;
109
+ const delay = 3000;
110
+ process.stderr.write(`agend: reconnecting in ${delay}ms (attempt ${reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS})...\n`);
111
+ setTimeout(() => {
112
+ reconnecting = false;
113
+ connectIpc();
114
+ }, delay);
115
+ }
116
+ function ipcRequest(tool, args) {
117
+ return new Promise((resolve, reject) => {
118
+ if (!ipcConnected || !ipc) {
119
+ reject(new Error("Not connected to daemon IPC"));
120
+ return;
121
+ }
122
+ const timeoutMs = SLOW_TOOLS.has(tool) ? SLOW_IPC_TIMEOUT_MS : IPC_TIMEOUT_MS;
123
+ const requestId = ++requestCounter;
124
+ const timer = setTimeout(() => {
125
+ pendingRequests.delete(requestId);
126
+ reject(new Error(`IPC request timed out after ${timeoutMs}ms`));
127
+ }, timeoutMs);
128
+ pendingRequests.set(requestId, { resolve, reject, timer });
129
+ try {
130
+ ipc.send({ type: "tool_call", tool, args, requestId });
131
+ }
132
+ catch (err) {
133
+ pendingRequests.delete(requestId);
134
+ clearTimeout(timer);
135
+ ipcConnected = false;
136
+ reject(new Error(`IPC send failed: ${err}`));
137
+ }
138
+ });
139
+ }
140
+ // ---------------------------------------------------------------------------
141
+ // MCP Server
142
+ // ---------------------------------------------------------------------------
143
+ const mcp = new Server({ name: "agend", version: "0.3.0" }, {
144
+ capabilities: {
145
+ tools: {},
146
+ },
147
+ instructions: [
148
+ "Reply using the reply tool. Use react for emoji reactions, edit_message for updates, download_attachment for files.",
149
+ "If the inbound message has image_path, Read that file — it is a photo the sender attached.",
150
+ "If the inbound message has attachment_file_id, call download_attachment with that file_id to fetch the file, then Read the returned path.",
151
+ "If the inbound message has reply_to_text, the user is quoting/replying to a previous message.",
152
+ "Use send_to_instance to communicate with other instances. Use list_instances to discover available instances.",
153
+ "Cross-instance messages (from_instance in meta) must be replied to via send_to_instance, NOT the reply tool.",
154
+ "High-level collaboration tools: request_information (ask a question), delegate_task (assign work), report_result (return results with correlation_id).",
155
+ "Use describe_instance to get detailed info about a specific instance before interacting with it.",
156
+ ].join("\n"),
157
+ });
158
+ // --- Tool definitions (see mcp-tools.ts) ---
159
+ export { TOOLS } from "./mcp-tools.js";
160
+ mcp.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
161
+ // --- Tool call handler ---
162
+ mcp.setRequestHandler(CallToolRequestSchema, async (req) => {
163
+ const args = (req.params.arguments ?? {});
164
+ try {
165
+ const result = await ipcRequest(req.params.name, args);
166
+ const text = typeof result === "string" ? result : JSON.stringify(result ?? "ok");
167
+ return { content: [{ type: "text", text }] };
168
+ }
169
+ catch (err) {
170
+ const message = err instanceof Error ? err.message : String(err);
171
+ return {
172
+ content: [{ type: "text", text: `Error: ${message}` }],
173
+ isError: true,
174
+ };
175
+ }
176
+ });
177
+ // ---------------------------------------------------------------------------
178
+ // Main
179
+ // ---------------------------------------------------------------------------
180
+ async function main() {
181
+ if (!SOCKET_PATH) {
182
+ process.stderr.write("agend: AGEND_SOCKET_PATH environment variable is required\n");
183
+ process.exit(1);
184
+ }
185
+ // Connect to daemon IPC first (will auto-reconnect on disconnect)
186
+ await connectIpc();
187
+ // Start MCP stdio transport (Claude <-> this process)
188
+ const transport = new StdioServerTransport();
189
+ await mcp.connect(transport);
190
+ process.stderr.write("agend: MCP server running\n");
191
+ }
192
+ main().catch((err) => {
193
+ process.stderr.write(`agend: fatal error: ${err}\n`);
194
+ process.exit(1);
195
+ });
196
+ //# sourceMappingURL=mcp-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-server.js","sourceRoot":"","sources":["../../src/channel/mcp-server.ts"],"names":[],"mappings":"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"}