@0xmaxma/claude-gateway 1.0.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.
Files changed (192) hide show
  1. package/README.md +791 -0
  2. package/config.template.json +87 -0
  3. package/dist/agent/context-isolation.d.ts +28 -0
  4. package/dist/agent/context-isolation.d.ts.map +1 -0
  5. package/dist/agent/context-isolation.js +80 -0
  6. package/dist/agent/context-isolation.js.map +1 -0
  7. package/dist/agent/runner.d.ts +211 -0
  8. package/dist/agent/runner.d.ts.map +1 -0
  9. package/dist/agent/runner.js +1802 -0
  10. package/dist/agent/runner.js.map +1 -0
  11. package/dist/agent/workspace-loader.d.ts +31 -0
  12. package/dist/agent/workspace-loader.d.ts.map +1 -0
  13. package/dist/agent/workspace-loader.js +207 -0
  14. package/dist/agent/workspace-loader.js.map +1 -0
  15. package/dist/api/auth.d.ts +25 -0
  16. package/dist/api/auth.d.ts.map +1 -0
  17. package/dist/api/auth.js +77 -0
  18. package/dist/api/auth.js.map +1 -0
  19. package/dist/api/cron-router.d.ts +22 -0
  20. package/dist/api/cron-router.d.ts.map +1 -0
  21. package/dist/api/cron-router.js +197 -0
  22. package/dist/api/cron-router.js.map +1 -0
  23. package/dist/api/gateway-router.d.ts +52 -0
  24. package/dist/api/gateway-router.d.ts.map +1 -0
  25. package/dist/api/gateway-router.js +215 -0
  26. package/dist/api/gateway-router.js.map +1 -0
  27. package/dist/api/router.d.ts +5 -0
  28. package/dist/api/router.d.ts.map +1 -0
  29. package/dist/api/router.js +1098 -0
  30. package/dist/api/router.js.map +1 -0
  31. package/dist/api/skills-router.d.ts +5 -0
  32. package/dist/api/skills-router.d.ts.map +1 -0
  33. package/dist/api/skills-router.js +424 -0
  34. package/dist/api/skills-router.js.map +1 -0
  35. package/dist/api/workspace-router.d.ts +4 -0
  36. package/dist/api/workspace-router.d.ts.map +1 -0
  37. package/dist/api/workspace-router.js +149 -0
  38. package/dist/api/workspace-router.js.map +1 -0
  39. package/dist/config/loader.d.ts +16 -0
  40. package/dist/config/loader.d.ts.map +1 -0
  41. package/dist/config/loader.js +235 -0
  42. package/dist/config/loader.js.map +1 -0
  43. package/dist/config/migrator.d.ts +70 -0
  44. package/dist/config/migrator.d.ts.map +1 -0
  45. package/dist/config/migrator.js +343 -0
  46. package/dist/config/migrator.js.map +1 -0
  47. package/dist/config/watcher.d.ts +30 -0
  48. package/dist/config/watcher.d.ts.map +1 -0
  49. package/dist/config/watcher.js +170 -0
  50. package/dist/config/watcher.js.map +1 -0
  51. package/dist/cron/manager.d.ts +48 -0
  52. package/dist/cron/manager.d.ts.map +1 -0
  53. package/dist/cron/manager.js +580 -0
  54. package/dist/cron/manager.js.map +1 -0
  55. package/dist/cron/scheduler.d.ts +50 -0
  56. package/dist/cron/scheduler.d.ts.map +1 -0
  57. package/dist/cron/scheduler.js +231 -0
  58. package/dist/cron/scheduler.js.map +1 -0
  59. package/dist/discord/receiver.d.ts +17 -0
  60. package/dist/discord/receiver.d.ts.map +1 -0
  61. package/dist/discord/receiver.js +108 -0
  62. package/dist/discord/receiver.js.map +1 -0
  63. package/dist/heartbeat/history.d.ts +24 -0
  64. package/dist/heartbeat/history.d.ts.map +1 -0
  65. package/dist/heartbeat/history.js +50 -0
  66. package/dist/heartbeat/history.js.map +1 -0
  67. package/dist/heartbeat/parser.d.ts +26 -0
  68. package/dist/heartbeat/parser.d.ts.map +1 -0
  69. package/dist/heartbeat/parser.js +283 -0
  70. package/dist/heartbeat/parser.js.map +1 -0
  71. package/dist/history/cleanup.d.ts +21 -0
  72. package/dist/history/cleanup.d.ts.map +1 -0
  73. package/dist/history/cleanup.js +171 -0
  74. package/dist/history/cleanup.js.map +1 -0
  75. package/dist/history/db.d.ts +27 -0
  76. package/dist/history/db.d.ts.map +1 -0
  77. package/dist/history/db.js +323 -0
  78. package/dist/history/db.js.map +1 -0
  79. package/dist/history/media-store.d.ts +27 -0
  80. package/dist/history/media-store.d.ts.map +1 -0
  81. package/dist/history/media-store.js +158 -0
  82. package/dist/history/media-store.js.map +1 -0
  83. package/dist/history/types.d.ts +62 -0
  84. package/dist/history/types.d.ts.map +1 -0
  85. package/dist/history/types.js +3 -0
  86. package/dist/history/types.js.map +1 -0
  87. package/dist/index.d.ts +3 -0
  88. package/dist/index.d.ts.map +1 -0
  89. package/dist/index.js +483 -0
  90. package/dist/index.js.map +1 -0
  91. package/dist/logger.d.ts +3 -0
  92. package/dist/logger.d.ts.map +1 -0
  93. package/dist/logger.js +81 -0
  94. package/dist/logger.js.map +1 -0
  95. package/dist/memory/manager.d.ts +45 -0
  96. package/dist/memory/manager.d.ts.map +1 -0
  97. package/dist/memory/manager.js +178 -0
  98. package/dist/memory/manager.js.map +1 -0
  99. package/dist/session/compactor.d.ts +22 -0
  100. package/dist/session/compactor.d.ts.map +1 -0
  101. package/dist/session/compactor.js +151 -0
  102. package/dist/session/compactor.js.map +1 -0
  103. package/dist/session/process.d.ts +76 -0
  104. package/dist/session/process.d.ts.map +1 -0
  105. package/dist/session/process.js +729 -0
  106. package/dist/session/process.js.map +1 -0
  107. package/dist/session/store.d.ts +102 -0
  108. package/dist/session/store.d.ts.map +1 -0
  109. package/dist/session/store.js +533 -0
  110. package/dist/session/store.js.map +1 -0
  111. package/dist/skills/index.d.ts +9 -0
  112. package/dist/skills/index.d.ts.map +1 -0
  113. package/dist/skills/index.js +15 -0
  114. package/dist/skills/index.js.map +1 -0
  115. package/dist/skills/invoker.d.ts +16 -0
  116. package/dist/skills/invoker.d.ts.map +1 -0
  117. package/dist/skills/invoker.js +36 -0
  118. package/dist/skills/invoker.js.map +1 -0
  119. package/dist/skills/loader.d.ts +23 -0
  120. package/dist/skills/loader.d.ts.map +1 -0
  121. package/dist/skills/loader.js +183 -0
  122. package/dist/skills/loader.js.map +1 -0
  123. package/dist/skills/parser.d.ts +55 -0
  124. package/dist/skills/parser.d.ts.map +1 -0
  125. package/dist/skills/parser.js +178 -0
  126. package/dist/skills/parser.js.map +1 -0
  127. package/dist/skills/sync.d.ts +10 -0
  128. package/dist/skills/sync.d.ts.map +1 -0
  129. package/dist/skills/sync.js +130 -0
  130. package/dist/skills/sync.js.map +1 -0
  131. package/dist/skills/watcher.d.ts +16 -0
  132. package/dist/skills/watcher.d.ts.map +1 -0
  133. package/dist/skills/watcher.js +25 -0
  134. package/dist/skills/watcher.js.map +1 -0
  135. package/dist/telegram/markdown.d.ts +25 -0
  136. package/dist/telegram/markdown.d.ts.map +1 -0
  137. package/dist/telegram/markdown.js +237 -0
  138. package/dist/telegram/markdown.js.map +1 -0
  139. package/dist/telegram/receiver.d.ts +17 -0
  140. package/dist/telegram/receiver.d.ts.map +1 -0
  141. package/dist/telegram/receiver.js +104 -0
  142. package/dist/telegram/receiver.js.map +1 -0
  143. package/dist/types.d.ts +224 -0
  144. package/dist/types.d.ts.map +1 -0
  145. package/dist/types.js +3 -0
  146. package/dist/types.js.map +1 -0
  147. package/dist/ui/web-ui.d.ts +6 -0
  148. package/dist/ui/web-ui.d.ts.map +1 -0
  149. package/dist/ui/web-ui.js +227 -0
  150. package/dist/ui/web-ui.js.map +1 -0
  151. package/dist/watch/factory.d.ts +26 -0
  152. package/dist/watch/factory.d.ts.map +1 -0
  153. package/dist/watch/factory.js +43 -0
  154. package/dist/watch/factory.js.map +1 -0
  155. package/dist/webhook/manager.d.ts +34 -0
  156. package/dist/webhook/manager.d.ts.map +1 -0
  157. package/dist/webhook/manager.js +120 -0
  158. package/dist/webhook/manager.js.map +1 -0
  159. package/mcp/bun.lock +264 -0
  160. package/mcp/channel-manager.ts +115 -0
  161. package/mcp/package.json +15 -0
  162. package/mcp/router.ts +69 -0
  163. package/mcp/server.ts +129 -0
  164. package/mcp/tools/agent/handlers.ts +578 -0
  165. package/mcp/tools/agent/module.ts +163 -0
  166. package/mcp/tools/browser/module.ts +321 -0
  167. package/mcp/tools/browser/skills/open-browser/SKILL.md +89 -0
  168. package/mcp/tools/cron/client.ts +65 -0
  169. package/mcp/tools/cron/module.ts +158 -0
  170. package/mcp/tools/cron/skills/cron/SKILL.md +46 -0
  171. package/mcp/tools/discord/access.ts +197 -0
  172. package/mcp/tools/discord/client.ts +31 -0
  173. package/mcp/tools/discord/commands.ts +48 -0
  174. package/mcp/tools/discord/inbound.ts +53 -0
  175. package/mcp/tools/discord/module.ts +442 -0
  176. package/mcp/tools/discord/outbound.ts +90 -0
  177. package/mcp/tools/discord/receiver-server.ts +58 -0
  178. package/mcp/tools/discord/skills/access/SKILL.md +86 -0
  179. package/mcp/tools/discord/skills/configure/SKILL.md +53 -0
  180. package/mcp/tools/discord/threading.ts +37 -0
  181. package/mcp/tools/discord/types.ts +106 -0
  182. package/mcp/tools/skills/handlers.ts +196 -0
  183. package/mcp/tools/skills/module.ts +163 -0
  184. package/mcp/tools/telegram/module.ts +454 -0
  185. package/mcp/tools/telegram/pure.ts +224 -0
  186. package/mcp/tools/telegram/receiver-server.ts +1656 -0
  187. package/mcp/tools/telegram/skills/access/SKILL.md +169 -0
  188. package/mcp/tools/telegram/skills/configure/SKILL.md +118 -0
  189. package/mcp/tools/telegram/typing.ts +327 -0
  190. package/mcp/types.ts +128 -0
  191. package/package.json +62 -0
  192. package/resource/claude_gateway.svg +112 -0
@@ -0,0 +1,231 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.CronScheduler = void 0;
37
+ const events_1 = require("events");
38
+ const nodeCron = __importStar(require("node-cron"));
39
+ const parser_1 = require("../heartbeat/parser");
40
+ const history_1 = require("../heartbeat/history");
41
+ const DEFAULT_RATE_LIMIT_MINUTES = 30;
42
+ /** Overridable via HEARTBEAT_RESPONSE_TIMEOUT_MS env var (for unit tests). */
43
+ function getResponseTimeoutMs() {
44
+ const envVal = process.env.HEARTBEAT_RESPONSE_TIMEOUT_MS;
45
+ if (envVal) {
46
+ const parsed = parseInt(envVal, 10);
47
+ if (!isNaN(parsed) && parsed > 0)
48
+ return parsed;
49
+ }
50
+ return 60000;
51
+ }
52
+ function buildSessionId(agentId, taskName) {
53
+ return `heartbeat:${agentId}:${taskName}:${Date.now()}`;
54
+ }
55
+ class CronScheduler extends events_1.EventEmitter {
56
+ constructor(agentId, runner, logger, agentConfig, history) {
57
+ super();
58
+ this.tasks = [];
59
+ this.lastProactiveMessageAt = null;
60
+ /** Populated during load() to support triggerTask() in tests */
61
+ this.taskDefs = new Map();
62
+ this.agentId = agentId;
63
+ this.runner = runner;
64
+ this.logger = logger;
65
+ this.agentConfig = agentConfig;
66
+ this.history = history ?? new history_1.HeartbeatHistory();
67
+ }
68
+ get id() {
69
+ return this.agentId;
70
+ }
71
+ /** Hot-reload: update the rate limit without restarting the scheduler */
72
+ updateRateLimit(minutes) {
73
+ if (!this.agentConfig.heartbeat) {
74
+ this.agentConfig.heartbeat = {};
75
+ }
76
+ this.agentConfig.heartbeat.rateLimitMinutes = minutes;
77
+ this.logger.info('Heartbeat rate limit updated', { rateLimitMinutes: minutes });
78
+ }
79
+ /**
80
+ * Parse the heartbeat.md content, cancel existing cron tasks,
81
+ * and schedule new ones.
82
+ */
83
+ load(heartbeatContent) {
84
+ // Cancel existing tasks and clear stored definitions
85
+ this.stop();
86
+ let heartbeatTasks;
87
+ try {
88
+ heartbeatTasks = (0, parser_1.parseHeartbeat)(heartbeatContent);
89
+ }
90
+ catch (err) {
91
+ this.logger.error('Failed to parse heartbeat content', { error: err.message });
92
+ return;
93
+ }
94
+ for (const task of heartbeatTasks) {
95
+ this.logger.info(`Scheduling heartbeat task "${task.name}"`, { cron: task.cron });
96
+ // Store for triggerTask() support
97
+ this.taskDefs.set(task.name, { name: task.name, prompt: task.prompt });
98
+ const scheduled = nodeCron.schedule(task.cron, async () => {
99
+ await this.runTask(task.name, task.prompt);
100
+ });
101
+ this.tasks.push(scheduled);
102
+ }
103
+ this.logger.info(`Loaded ${this.tasks.length} heartbeat task(s)`, { agentId: this.agentId });
104
+ }
105
+ /**
106
+ * Get the rate-limit window in milliseconds.
107
+ */
108
+ getRateLimitWindowMs() {
109
+ const minutes = this.agentConfig.heartbeat?.rateLimitMinutes ?? DEFAULT_RATE_LIMIT_MINUTES;
110
+ return minutes * 60 * 1000;
111
+ }
112
+ /**
113
+ * Execute a single heartbeat task:
114
+ * 1. Check rate limit
115
+ * 2. Create ephemeral session (in-memory, not persisted)
116
+ * 3. Send prompt to agent runner
117
+ * 4. Capture response, detect HEARTBEAT_OK
118
+ * 5. Emit heartbeat:result event and record in history
119
+ */
120
+ async runTask(name, prompt) {
121
+ const startedAt = Date.now();
122
+ const rateLimitWindowMs = this.getRateLimitWindowMs();
123
+ // Rate limit check
124
+ if (this.lastProactiveMessageAt !== null &&
125
+ startedAt - this.lastProactiveMessageAt.getTime() < rateLimitWindowMs) {
126
+ const sessionId = buildSessionId(this.agentId, name);
127
+ const result = {
128
+ taskName: name,
129
+ sessionId,
130
+ suppressed: true,
131
+ rateLimited: true,
132
+ response: '',
133
+ durationMs: 0,
134
+ ts: new Date(startedAt).toISOString(),
135
+ };
136
+ this.logger.info(`Heartbeat task "${name}" suppressed by rate limit`, {
137
+ lastProactiveMessageAt: this.lastProactiveMessageAt.toISOString(),
138
+ });
139
+ this.emit('heartbeat:rate-limited', result);
140
+ this.history.record(this.agentId, result);
141
+ this.emit('heartbeat:result', result);
142
+ return;
143
+ }
144
+ // Create ephemeral session (in-memory only, not persisted to disk)
145
+ const session = {
146
+ sessionId: buildSessionId(this.agentId, name),
147
+ agentId: this.agentId,
148
+ taskName: name,
149
+ startedAt,
150
+ };
151
+ this.logger.info(`Running heartbeat task "${name}"`, { sessionId: session.sessionId });
152
+ // Collect response lines from agent output
153
+ const responseLines = [];
154
+ let heartbeatOk = false;
155
+ let responseTimer = null;
156
+ let resolved = false;
157
+ const result = await new Promise((resolve) => {
158
+ const outputHandler = (line) => {
159
+ responseLines.push(line);
160
+ // Case-insensitive HEARTBEAT_OK detection
161
+ if (line.toUpperCase().includes('HEARTBEAT_OK')) {
162
+ heartbeatOk = true;
163
+ this.logger.info(`Heartbeat task "${name}" returned HEARTBEAT_OK — suppressing Telegram message`, { sessionId: session.sessionId });
164
+ }
165
+ };
166
+ const finish = () => {
167
+ if (resolved)
168
+ return;
169
+ resolved = true;
170
+ this.runner.removeListener('output', outputHandler);
171
+ if (responseTimer) {
172
+ clearTimeout(responseTimer);
173
+ responseTimer = null;
174
+ }
175
+ const durationMs = Date.now() - startedAt;
176
+ const response = responseLines.join('\n');
177
+ resolve({
178
+ taskName: name,
179
+ sessionId: session.sessionId,
180
+ suppressed: heartbeatOk,
181
+ rateLimited: false,
182
+ response,
183
+ durationMs,
184
+ ts: new Date(startedAt).toISOString(),
185
+ });
186
+ };
187
+ this.runner.on('output', outputHandler);
188
+ // Update rate limit timestamp before sending (prevents concurrent tasks from bypassing)
189
+ this.lastProactiveMessageAt = new Date(startedAt);
190
+ // Send the prompt to the agent using the ephemeral session
191
+ this.runner.sendMessage(prompt);
192
+ // Resolve after timeout — collects all output within the window
193
+ responseTimer = setTimeout(finish, getResponseTimeoutMs());
194
+ });
195
+ // Record and emit
196
+ this.history.record(this.agentId, result);
197
+ this.emit('heartbeat:result', result);
198
+ }
199
+ /**
200
+ * Stop all scheduled cron tasks.
201
+ */
202
+ stop() {
203
+ for (const task of this.tasks) {
204
+ task.stop();
205
+ }
206
+ this.tasks = [];
207
+ this.taskDefs.clear();
208
+ }
209
+ /**
210
+ * Get the HeartbeatHistory instance used by this scheduler.
211
+ */
212
+ getHistory() {
213
+ return this.history;
214
+ }
215
+ /**
216
+ * Manually trigger a named task by name (testing only — requires NODE_ENV=test).
217
+ */
218
+ async triggerTask(taskName) {
219
+ if (process.env.NODE_ENV !== 'test') {
220
+ this.logger.warn('triggerTask() called outside of test environment — ignoring');
221
+ return;
222
+ }
223
+ const taskDef = this.taskDefs.get(taskName);
224
+ if (!taskDef) {
225
+ throw new Error(`No task named "${taskName}" is scheduled`);
226
+ }
227
+ await this.runTask(taskDef.name, taskDef.prompt);
228
+ }
229
+ }
230
+ exports.CronScheduler = CronScheduler;
231
+ //# sourceMappingURL=scheduler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../../src/cron/scheduler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import { AgentConfig } from '../types';
2
+ export declare class DiscordReceiver {
3
+ private readonly agentConfig;
4
+ private readonly callbackPort;
5
+ private readonly logDir;
6
+ private process;
7
+ private stopping;
8
+ private restartCount;
9
+ private readonly logger;
10
+ constructor(agentConfig: AgentConfig, callbackPort: number, logDir: string);
11
+ start(): void;
12
+ private spawnProcess;
13
+ private scheduleRestart;
14
+ stop(): void;
15
+ isRunning(): boolean;
16
+ }
17
+ //# sourceMappingURL=receiver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"receiver.d.ts","sourceRoot":"","sources":["../../src/discord/receiver.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAMvC,qBAAa,eAAe;IAOxB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM;IARzB,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkC;gBAGtC,WAAW,EAAE,WAAW,EACxB,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM;IAKjC,KAAK,IAAI,IAAI;IAMb,OAAO,CAAC,YAAY;IAoCpB,OAAO,CAAC,eAAe;IAcvB,IAAI,IAAI,IAAI;IAKZ,SAAS,IAAI,OAAO;CAGrB"}
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.DiscordReceiver = void 0;
37
+ const child_process_1 = require("child_process");
38
+ const path = __importStar(require("path"));
39
+ const logger_1 = require("../logger");
40
+ const AUTO_RESTART_DELAY_MS = 5000;
41
+ const MAX_RESTARTS = 3;
42
+ class DiscordReceiver {
43
+ constructor(agentConfig, callbackPort, logDir) {
44
+ this.agentConfig = agentConfig;
45
+ this.callbackPort = callbackPort;
46
+ this.logDir = logDir;
47
+ this.process = null;
48
+ this.stopping = false;
49
+ this.restartCount = 0;
50
+ this.logger = (0, logger_1.createLogger)(`${agentConfig.id}:discord-receiver`, logDir);
51
+ }
52
+ start() {
53
+ this.stopping = false;
54
+ this.restartCount = 0;
55
+ this.spawnProcess();
56
+ }
57
+ spawnProcess() {
58
+ const receiverPath = path.resolve(__dirname, '..', '..', 'mcp', 'tools', 'discord', 'receiver-server.ts');
59
+ const stateDir = path.join(this.agentConfig.workspace, '.discord-state');
60
+ this.process = (0, child_process_1.spawn)('bun', [receiverPath], {
61
+ env: {
62
+ ...process.env,
63
+ DISCORD_BOT_TOKEN: this.agentConfig.discord?.botToken ?? '',
64
+ DISCORD_STATE_DIR: stateDir,
65
+ DISCORD_DM_POLICY: this.agentConfig.discord?.dmPolicy ?? 'pairing',
66
+ DISCORD_DM_ALLOWLIST: (this.agentConfig.discord?.dmAllowlist ?? []).join(','),
67
+ DISCORD_GUILD_ALLOWLIST: (this.agentConfig.discord?.guildAllowlist ?? []).join(','),
68
+ DISCORD_CHANNEL_ALLOWLIST: (this.agentConfig.discord?.channelAllowlist ?? []).join(','),
69
+ GATEWAY_AGENT_ID: this.agentConfig.id,
70
+ CLAUDE_CHANNEL_CALLBACK: `http://127.0.0.1:${this.callbackPort}/channel`,
71
+ },
72
+ stdio: ['ignore', 'pipe', 'pipe'],
73
+ });
74
+ this.process.stdout?.on('data', (d) => this.logger.debug('discord receiver stdout', { data: d.toString().trim() }));
75
+ this.process.stderr?.on('data', (d) => this.logger.info('discord receiver', { data: d.toString().trim() }));
76
+ this.process.on('exit', (code, signal) => {
77
+ this.logger.info('DiscordReceiver exited', { code, signal });
78
+ this.process = null;
79
+ if (!this.stopping)
80
+ this.scheduleRestart();
81
+ });
82
+ this.process.on('error', (err) => this.logger.error('DiscordReceiver error', { error: err.message }));
83
+ this.logger.info('DiscordReceiver started');
84
+ }
85
+ scheduleRestart() {
86
+ if (this.restartCount >= MAX_RESTARTS) {
87
+ this.logger.error('DiscordReceiver max restarts reached');
88
+ return;
89
+ }
90
+ this.restartCount++;
91
+ this.logger.warn(`Restarting DiscordReceiver in ${AUTO_RESTART_DELAY_MS}ms`, {
92
+ attempt: this.restartCount,
93
+ });
94
+ setTimeout(() => {
95
+ if (!this.stopping)
96
+ this.spawnProcess();
97
+ }, AUTO_RESTART_DELAY_MS);
98
+ }
99
+ stop() {
100
+ this.stopping = true;
101
+ this.process?.kill('SIGTERM');
102
+ }
103
+ isRunning() {
104
+ return this.process !== null && !this.process.killed;
105
+ }
106
+ }
107
+ exports.DiscordReceiver = DiscordReceiver;
108
+ //# sourceMappingURL=receiver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"receiver.js","sourceRoot":"","sources":["../../src/discord/receiver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { HeartbeatResult } from '../types';
2
+ /**
3
+ * In-memory ring buffer of HeartbeatResult entries per agent.
4
+ * Stores up to MAX_ENTRIES_PER_AGENT results per agent; oldest entries are
5
+ * dropped once the limit is reached.
6
+ */
7
+ export declare class HeartbeatHistory {
8
+ private readonly store;
9
+ /**
10
+ * Record a heartbeat result for the given agent.
11
+ * Drops the oldest entry once MAX_ENTRIES_PER_AGENT is reached.
12
+ */
13
+ record(agentId: string, result: HeartbeatResult): void;
14
+ /**
15
+ * Return all results for an agent (optionally filtered by taskName).
16
+ * Results are in reverse-chronological order (newest first).
17
+ */
18
+ getHistory(agentId: string, taskName?: string): HeartbeatResult[];
19
+ /**
20
+ * Return the most recent result for a specific task, or null if none exists.
21
+ */
22
+ getLastResult(agentId: string, taskName: string): HeartbeatResult | null;
23
+ }
24
+ //# sourceMappingURL=history.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history.d.ts","sourceRoot":"","sources":["../../src/heartbeat/history.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAI3C;;;;GAIG;AACH,qBAAa,gBAAgB;IAE3B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAwC;IAE9D;;;OAGG;IACH,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI;IActD;;;OAGG;IACH,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,eAAe,EAAE;IAQjE;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI;CAIzE"}
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HeartbeatHistory = void 0;
4
+ const MAX_ENTRIES_PER_AGENT = 100;
5
+ /**
6
+ * In-memory ring buffer of HeartbeatResult entries per agent.
7
+ * Stores up to MAX_ENTRIES_PER_AGENT results per agent; oldest entries are
8
+ * dropped once the limit is reached.
9
+ */
10
+ class HeartbeatHistory {
11
+ constructor() {
12
+ // Map<agentId, HeartbeatResult[]> — newest at index 0 (prepend strategy)
13
+ this.store = new Map();
14
+ }
15
+ /**
16
+ * Record a heartbeat result for the given agent.
17
+ * Drops the oldest entry once MAX_ENTRIES_PER_AGENT is reached.
18
+ */
19
+ record(agentId, result) {
20
+ if (!this.store.has(agentId)) {
21
+ this.store.set(agentId, []);
22
+ }
23
+ const entries = this.store.get(agentId);
24
+ // Prepend so index 0 is always the most recent
25
+ entries.unshift(result);
26
+ if (entries.length > MAX_ENTRIES_PER_AGENT) {
27
+ entries.splice(MAX_ENTRIES_PER_AGENT); // drop oldest
28
+ }
29
+ }
30
+ /**
31
+ * Return all results for an agent (optionally filtered by taskName).
32
+ * Results are in reverse-chronological order (newest first).
33
+ */
34
+ getHistory(agentId, taskName) {
35
+ const entries = this.store.get(agentId) ?? [];
36
+ if (taskName === undefined) {
37
+ return [...entries];
38
+ }
39
+ return entries.filter((r) => r.taskName === taskName);
40
+ }
41
+ /**
42
+ * Return the most recent result for a specific task, or null if none exists.
43
+ */
44
+ getLastResult(agentId, taskName) {
45
+ const entries = this.store.get(agentId) ?? [];
46
+ return entries.find((r) => r.taskName === taskName) ?? null;
47
+ }
48
+ }
49
+ exports.HeartbeatHistory = HeartbeatHistory;
50
+ //# sourceMappingURL=history.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history.js","sourceRoot":"","sources":["../../src/heartbeat/history.ts"],"names":[],"mappings":";;;AAEA,MAAM,qBAAqB,GAAG,GAAG,CAAC;AAElC;;;;GAIG;AACH,MAAa,gBAAgB;IAA7B;QACE,yEAAyE;QACxD,UAAK,GAAG,IAAI,GAAG,EAA6B,CAAC;IAuChE,CAAC;IArCC;;;OAGG;IACH,MAAM,CAAC,OAAe,EAAE,MAAuB;QAC7C,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;YAC7B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAC9B,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAE,CAAC;QAEzC,+CAA+C;QAC/C,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAExB,IAAI,OAAO,CAAC,MAAM,GAAG,qBAAqB,EAAE,CAAC;YAC3C,OAAO,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC,CAAC,cAAc;QACvD,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,UAAU,CAAC,OAAe,EAAE,QAAiB;QAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QAC9C,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC;QACtB,CAAC;QACD,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC;IACxD,CAAC;IAED;;OAEG;IACH,aAAa,CAAC,OAAe,EAAE,QAAgB;QAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QAC9C,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,IAAI,IAAI,CAAC;IAC9D,CAAC;CACF;AAzCD,4CAyCC"}
@@ -0,0 +1,26 @@
1
+ import { HeartbeatTask } from '../types';
2
+ export declare class InvalidCronError extends Error {
3
+ constructor(taskName: string, expr: string);
4
+ }
5
+ export declare class InvalidIntervalError extends Error {
6
+ constructor(taskName: string, interval: string);
7
+ }
8
+ export declare class MissingPromptError extends Error {
9
+ constructor(taskName: string);
10
+ }
11
+ export declare class MissingNameError extends Error {
12
+ constructor(index: number);
13
+ }
14
+ export declare class AmbiguousScheduleError extends Error {
15
+ constructor(taskName: string);
16
+ }
17
+ export declare class MissingScheduleError extends Error {
18
+ constructor(taskName: string);
19
+ }
20
+ /**
21
+ * Convert an interval string to a 5-field cron expression.
22
+ * Supported: 30m, 2h, 1d, 1w
23
+ */
24
+ export declare function intervalToCron(interval: string): string;
25
+ export declare function parseHeartbeat(content: string): HeartbeatTask[];
26
+ //# sourceMappingURL=parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/heartbeat/parser.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAIzC,qBAAa,gBAAiB,SAAQ,KAAK;gBAC7B,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;CAI3C;AAED,qBAAa,oBAAqB,SAAQ,KAAK;gBACjC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;CAI/C;AAED,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,QAAQ,EAAE,MAAM;CAI7B;AAED,qBAAa,gBAAiB,SAAQ,KAAK;gBAC7B,KAAK,EAAE,MAAM;CAI1B;AAED,qBAAa,sBAAuB,SAAQ,KAAK;gBACnC,QAAQ,EAAE,MAAM;CAI7B;AAED,qBAAa,oBAAqB,SAAQ,KAAK;gBACjC,QAAQ,EAAE,MAAM;CAI7B;AA8ED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAwBvD;AAsCD,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,EAAE,CA0E/D"}