@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,323 @@
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.HistoryDB = void 0;
37
+ const path = __importStar(require("path"));
38
+ const fs = __importStar(require("fs"));
39
+ const node_sqlite_1 = require("node:sqlite");
40
+ const MAX_LIMIT = 200;
41
+ const DEFAULT_LIMIT = 50;
42
+ const PREVIEW_LENGTH = 120;
43
+ // Singleton cache: one DB per (agentsBaseDir + agentId)
44
+ const cache = new Map();
45
+ class HistoryDB {
46
+ constructor(dbPath, agentId) {
47
+ this.agentId = agentId;
48
+ fs.mkdirSync(path.dirname(dbPath), { recursive: true });
49
+ this.db = new node_sqlite_1.DatabaseSync(dbPath);
50
+ this.db.exec('PRAGMA journal_mode=WAL');
51
+ this.db.exec('PRAGMA synchronous=NORMAL');
52
+ this.db.exec('PRAGMA foreign_keys=ON');
53
+ this._initSchema();
54
+ this.insertStmt = this.db.prepare(`INSERT INTO messages (chat_id, session_id, source, role, content, sender_name, sender_id, platform_message_id, media_files, ts)
55
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
56
+ }
57
+ static forAgent(agentsBaseDir, agentId) {
58
+ const key = `${agentsBaseDir}::${agentId}`;
59
+ if (!cache.has(key)) {
60
+ const dbPath = path.join(agentsBaseDir, agentId, 'history.db');
61
+ cache.set(key, new HistoryDB(dbPath, agentId));
62
+ }
63
+ return cache.get(key);
64
+ }
65
+ // Used by AgentRunner: agentDir is workspace/.., so DB lives at agentDir/history.db
66
+ // which equals agentsBaseDir/agentId/history.db without requiring workspace to be nested correctly.
67
+ static forDir(agentDir, agentId) {
68
+ const key = `dir::${agentDir}::${agentId}`;
69
+ if (!cache.has(key)) {
70
+ const dbPath = path.join(agentDir, 'history.db');
71
+ cache.set(key, new HistoryDB(dbPath, agentId));
72
+ }
73
+ return cache.get(key);
74
+ }
75
+ static evict(agentsBaseDir, agentId) {
76
+ cache.delete(`${agentsBaseDir}::${agentId}`);
77
+ }
78
+ static evictDir(agentDir, agentId) {
79
+ cache.delete(`dir::${agentDir}::${agentId}`);
80
+ }
81
+ _initSchema() {
82
+ this.db.exec(`
83
+ CREATE TABLE IF NOT EXISTS messages (
84
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
85
+ chat_id TEXT NOT NULL,
86
+ session_id TEXT NOT NULL,
87
+ source TEXT NOT NULL,
88
+ role TEXT NOT NULL,
89
+ content TEXT NOT NULL,
90
+ sender_name TEXT,
91
+ sender_id TEXT,
92
+ platform_message_id TEXT,
93
+ media_files TEXT,
94
+ ts INTEGER NOT NULL,
95
+ created_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000)
96
+ );
97
+
98
+ CREATE INDEX IF NOT EXISTS idx_messages_chat_ts ON messages(chat_id, ts DESC);
99
+ CREATE INDEX IF NOT EXISTS idx_messages_session ON messages(session_id, ts ASC);
100
+ CREATE INDEX IF NOT EXISTS idx_messages_source ON messages(source, ts DESC);
101
+
102
+ CREATE VIRTUAL TABLE IF NOT EXISTS messages_fts USING fts5(
103
+ content,
104
+ sender_name,
105
+ content='messages',
106
+ content_rowid='id'
107
+ );
108
+
109
+ CREATE TRIGGER IF NOT EXISTS messages_ai AFTER INSERT ON messages BEGIN
110
+ INSERT INTO messages_fts(rowid, content, sender_name)
111
+ VALUES (new.id, new.content, new.sender_name);
112
+ END;
113
+
114
+ CREATE TRIGGER IF NOT EXISTS messages_ad AFTER DELETE ON messages BEGIN
115
+ INSERT INTO messages_fts(messages_fts, rowid, content, sender_name)
116
+ VALUES ('delete', old.id, old.content, old.sender_name);
117
+ END;
118
+
119
+ `);
120
+ }
121
+ insertMessage(msg) {
122
+ try {
123
+ this.insertStmt.run(msg.chatId, msg.sessionId, msg.source, msg.role, msg.content, msg.senderName ?? null, msg.senderId ?? null, msg.platformMessageId ?? null, msg.mediaFiles ? JSON.stringify(msg.mediaFiles) : null, msg.ts);
124
+ }
125
+ catch (err) {
126
+ // Non-fatal — history is best-effort
127
+ console.error(`[HistoryDB:${this.agentId}] insertMessage failed:`, err);
128
+ }
129
+ }
130
+ listChats() {
131
+ const rows = this.db.prepare(`
132
+ SELECT
133
+ m.chat_id,
134
+ m.source,
135
+ MAX(CASE WHEN m.role = 'user' THEN m.sender_name END) AS display_name,
136
+ COUNT(*) AS message_count,
137
+ MAX(m.ts) AS last_active,
138
+ (
139
+ SELECT SUBSTR(m2.content, 1, ${PREVIEW_LENGTH})
140
+ FROM messages m2
141
+ WHERE m2.chat_id = m.chat_id
142
+ ORDER BY m2.ts DESC
143
+ LIMIT 1
144
+ ) AS last_preview
145
+ FROM messages m
146
+ GROUP BY m.chat_id
147
+ ORDER BY last_active DESC
148
+ `).all();
149
+ return rows.map((row) => ({
150
+ chatId: row.chat_id,
151
+ source: row.source,
152
+ displayName: row.display_name,
153
+ messageCount: row.message_count,
154
+ lastActive: row.last_active,
155
+ lastMessagePreview: row.last_preview,
156
+ }));
157
+ }
158
+ getMessages(chatId, opts = {}) {
159
+ const limit = Math.min(opts.limit ?? DEFAULT_LIMIT, MAX_LIMIT);
160
+ const conditions = ['chat_id = ?'];
161
+ const params = [chatId];
162
+ if (opts.sessionId) {
163
+ conditions.push('session_id = ?');
164
+ params.push(opts.sessionId);
165
+ }
166
+ if (opts.before !== undefined) {
167
+ conditions.push('ts < ?');
168
+ params.push(opts.before);
169
+ }
170
+ if (opts.after !== undefined) {
171
+ conditions.push('ts > ?');
172
+ params.push(opts.after);
173
+ }
174
+ // Fetch limit+1 to determine hasMore
175
+ params.push(limit + 1);
176
+ const sql = `
177
+ SELECT id, chat_id, session_id, source, role, content, sender_name, sender_id,
178
+ platform_message_id, media_files, ts
179
+ FROM messages
180
+ WHERE ${conditions.join(' AND ')}
181
+ ORDER BY ts DESC
182
+ LIMIT ?
183
+ `;
184
+ const rows = this.db.prepare(sql).all(...params);
185
+ const hasMore = rows.length > limit;
186
+ const slice = hasMore ? rows.slice(0, limit) : rows;
187
+ const messages = slice.map((r) => this._rowToMessage(r));
188
+ const nextCursor = hasMore && slice.length > 0
189
+ ? slice[slice.length - 1]['ts']
190
+ : null;
191
+ return { messages, hasMore, nextCursor };
192
+ }
193
+ searchMessages(chatId, query, opts = {}) {
194
+ const limit = Math.min(opts.limit ?? 20, 100);
195
+ const offset = opts.offset ?? 0;
196
+ if (!query.trim()) {
197
+ return { results: [], total: 0, hasMore: false };
198
+ }
199
+ const sanitizedQuery = query.replace(/['"*\-]/g, ' ').trim();
200
+ if (!sanitizedQuery) {
201
+ return { results: [], total: 0, hasMore: false };
202
+ }
203
+ try {
204
+ const countStmt = this.db.prepare(`
205
+ SELECT COUNT(*) as cnt
206
+ FROM messages_fts
207
+ JOIN messages ON messages.id = messages_fts.rowid
208
+ WHERE messages.chat_id = ? AND messages_fts MATCH ?
209
+ `);
210
+ const countRow = countStmt.get(chatId, sanitizedQuery);
211
+ const total = countRow?.cnt ?? 0;
212
+ const stmt = this.db.prepare(`
213
+ SELECT
214
+ messages.id, messages.chat_id, messages.session_id, messages.source,
215
+ messages.role, messages.content, messages.sender_name, messages.sender_id,
216
+ messages.platform_message_id, messages.media_files, messages.ts,
217
+ snippet(messages_fts, 0, '<b>', '</b>', '...', 32) AS snippet
218
+ FROM messages_fts
219
+ JOIN messages ON messages.id = messages_fts.rowid
220
+ WHERE messages.chat_id = ? AND messages_fts MATCH ?
221
+ ORDER BY messages.ts DESC
222
+ LIMIT ? OFFSET ?
223
+ `);
224
+ const rows = stmt.all(chatId, sanitizedQuery, limit, offset);
225
+ const results = rows.map((r) => ({
226
+ ...this._rowToMessage(r),
227
+ snippet: r['snippet'] ?? '',
228
+ }));
229
+ return { results, total, hasMore: offset + results.length < total };
230
+ }
231
+ catch {
232
+ return { results: [], total: 0, hasMore: false };
233
+ }
234
+ }
235
+ listSessions() {
236
+ const rows = this.db.prepare(`
237
+ SELECT
238
+ chat_id,
239
+ session_id,
240
+ source,
241
+ COUNT(*) AS message_count,
242
+ MIN(ts) AS created_at,
243
+ MAX(ts) AS last_activity,
244
+ (SELECT content FROM messages m2
245
+ WHERE m2.session_id = m.session_id
246
+ ORDER BY ts DESC LIMIT 1) AS last_message
247
+ FROM messages m
248
+ GROUP BY session_id
249
+ ORDER BY last_activity DESC
250
+ `).all();
251
+ return rows.map((row) => ({
252
+ chatId: row.chat_id || null,
253
+ sessionId: row.session_id,
254
+ source: row.source,
255
+ messageCount: row.message_count,
256
+ createdAt: row.created_at,
257
+ lastActivity: row.last_activity,
258
+ lastMessage: row.last_message ?? null,
259
+ sessionName: null,
260
+ }));
261
+ }
262
+ clearChat(chatId) {
263
+ this.db.prepare('DELETE FROM messages WHERE chat_id = ?').run(chatId);
264
+ }
265
+ clearSession(chatId, sessionId) {
266
+ const rows = this.db.prepare(`SELECT media_files FROM messages WHERE chat_id = ? AND session_id = ? AND media_files IS NOT NULL`).all(chatId, sessionId);
267
+ const mediaPaths = [];
268
+ for (const row of rows) {
269
+ try {
270
+ mediaPaths.push(...JSON.parse(row.media_files));
271
+ }
272
+ catch { /* skip */ }
273
+ }
274
+ this.db.prepare('DELETE FROM messages WHERE chat_id = ? AND session_id = ?').run(chatId, sessionId);
275
+ return mediaPaths;
276
+ }
277
+ /**
278
+ * Delete all messages older than cutoffMs (Unix ms timestamp).
279
+ * Returns relative media_files paths from deleted rows for disk cleanup.
280
+ * FTS5 index stays consistent via the AFTER DELETE trigger.
281
+ */
282
+ pruneOlderThan(cutoffMs) {
283
+ const rows = this.db.prepare(`SELECT media_files FROM messages WHERE ts < ? AND media_files IS NOT NULL`).all(cutoffMs);
284
+ const mediaPaths = [];
285
+ for (const row of rows) {
286
+ try {
287
+ const paths = JSON.parse(row.media_files);
288
+ mediaPaths.push(...paths);
289
+ }
290
+ catch {
291
+ // malformed JSON — skip
292
+ }
293
+ }
294
+ this.db.prepare(`DELETE FROM messages WHERE ts < ?`).run(cutoffMs);
295
+ return mediaPaths;
296
+ }
297
+ _rowToMessage(r) {
298
+ let mediaFiles;
299
+ if (r['media_files'] && typeof r['media_files'] === 'string') {
300
+ try {
301
+ mediaFiles = JSON.parse(r['media_files']);
302
+ }
303
+ catch {
304
+ mediaFiles = undefined;
305
+ }
306
+ }
307
+ return {
308
+ id: r['id'],
309
+ chatId: r['chat_id'],
310
+ sessionId: r['session_id'],
311
+ source: r['source'],
312
+ role: r['role'],
313
+ content: r['content'],
314
+ senderName: r['sender_name'] ?? undefined,
315
+ senderId: r['sender_id'] ?? undefined,
316
+ platformMessageId: r['platform_message_id'] ?? undefined,
317
+ mediaFiles,
318
+ ts: r['ts'],
319
+ };
320
+ }
321
+ }
322
+ exports.HistoryDB = HistoryDB;
323
+ //# sourceMappingURL=db.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/history/db.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ export declare class MediaStore {
2
+ static mediaDir(agentsBaseDir: string, agentId: string, chatId: string): string;
3
+ static agentMediaRoot(agentsBaseDir: string, agentId: string): string;
4
+ /**
5
+ * Copy a file from srcPath into the permanent media directory for chatId.
6
+ * Returns the relative path stored in HistoryMessage.mediaFiles[].
7
+ */
8
+ static copyToMedia(agentsBaseDir: string, agentId: string, chatId: string, srcPath: string): string;
9
+ /**
10
+ * Resolve a relative media path to an absolute filesystem path.
11
+ * Throws if the resolved path escapes the agent's media root (path traversal guard).
12
+ */
13
+ static resolvePath(agentsBaseDir: string, agentId: string, relativePath: string): string;
14
+ /**
15
+ * Delete files in the ui-upload staging area that are older than STAGING_MAX_AGE_MS.
16
+ * Safe to call periodically (e.g. hourly) to prevent disk accumulation.
17
+ */
18
+ static cleanupStaging(agentsBaseDir: string): void;
19
+ /**
20
+ * Delete all media files for a chatId (called by /clear).
21
+ */
22
+ static clearChatMedia(agentsBaseDir: string, agentId: string, chatId: string): void;
23
+ static deleteMediaFiles(agentsBaseDir: string, agentId: string, relativePaths: string[]): void;
24
+ static isAllowedMime(mime: string): boolean;
25
+ static get maxUploadBytes(): number;
26
+ }
27
+ //# sourceMappingURL=media-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media-store.d.ts","sourceRoot":"","sources":["../../src/history/media-store.ts"],"names":[],"mappings":"AAQA,qBAAa,UAAU;IACrB,MAAM,CAAC,QAAQ,CAAC,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM;IAI/E,MAAM,CAAC,cAAc,CAAC,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM;IAIrE;;;OAGG;IACH,MAAM,CAAC,WAAW,CAChB,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GACd,MAAM;IAUT;;;OAGG;IACH,MAAM,CAAC,WAAW,CAAC,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM;IAsBxF;;;OAGG;IACH,MAAM,CAAC,cAAc,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI;IA8BlD;;OAEG;IACH,MAAM,CAAC,cAAc,CAAC,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAOnF,MAAM,CAAC,gBAAgB,CAAC,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,IAAI;IAS9F,MAAM,CAAC,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI3C,MAAM,KAAK,cAAc,IAAI,MAAM,CAElC;CACF"}
@@ -0,0 +1,158 @@
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.MediaStore = void 0;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const MAX_UPLOAD_BYTES = 20 * 1024 * 1024; // 20 MB
40
+ const ALLOWED_MIME_PREFIXES = ['image/', 'application/pdf'];
41
+ /** Staging files older than this are eligible for cleanup */
42
+ const STAGING_MAX_AGE_MS = 24 * 60 * 60 * 1000; // 24 hours
43
+ class MediaStore {
44
+ static mediaDir(agentsBaseDir, agentId, chatId) {
45
+ return path.join(agentsBaseDir, agentId, 'media', chatId);
46
+ }
47
+ static agentMediaRoot(agentsBaseDir, agentId) {
48
+ return path.join(agentsBaseDir, agentId, 'media');
49
+ }
50
+ /**
51
+ * Copy a file from srcPath into the permanent media directory for chatId.
52
+ * Returns the relative path stored in HistoryMessage.mediaFiles[].
53
+ */
54
+ static copyToMedia(agentsBaseDir, agentId, chatId, srcPath) {
55
+ const dir = MediaStore.mediaDir(agentsBaseDir, agentId, chatId);
56
+ fs.mkdirSync(dir, { recursive: true });
57
+ const basename = `${Date.now()}-${path.basename(srcPath)}`;
58
+ const destName = basename.length > 128 ? basename.slice(0, 128) : basename;
59
+ const destPath = path.join(dir, destName);
60
+ fs.copyFileSync(srcPath, destPath);
61
+ return path.join('media', chatId, destName);
62
+ }
63
+ /**
64
+ * Resolve a relative media path to an absolute filesystem path.
65
+ * Throws if the resolved path escapes the agent's media root (path traversal guard).
66
+ */
67
+ static resolvePath(agentsBaseDir, agentId, relativePath) {
68
+ const root = MediaStore.agentMediaRoot(agentsBaseDir, agentId);
69
+ // Strip leading "media/" prefix if present (callers may or may not include it)
70
+ const withoutPrefix = relativePath.startsWith('media/')
71
+ ? relativePath.slice(6)
72
+ : relativePath;
73
+ const resolved = path.resolve(root, withoutPrefix);
74
+ if (!resolved.startsWith(root + path.sep) && resolved !== root) {
75
+ throw new Error('Path traversal detected');
76
+ }
77
+ // Resolve symlinks to prevent escaping the media root via symlink attacks.
78
+ // Only do this if the path already exists (realpathSync throws if not found).
79
+ if (fs.existsSync(resolved)) {
80
+ const real = fs.realpathSync(resolved);
81
+ if (!real.startsWith(root + path.sep) && real !== root) {
82
+ throw new Error('Path traversal detected');
83
+ }
84
+ return real;
85
+ }
86
+ return resolved;
87
+ }
88
+ /**
89
+ * Delete files in the ui-upload staging area that are older than STAGING_MAX_AGE_MS.
90
+ * Safe to call periodically (e.g. hourly) to prevent disk accumulation.
91
+ */
92
+ static cleanupStaging(agentsBaseDir) {
93
+ const agentsDir = agentsBaseDir;
94
+ if (!fs.existsSync(agentsDir))
95
+ return;
96
+ const now = Date.now();
97
+ for (const agentId of fs.readdirSync(agentsDir)) {
98
+ const stagingDir = path.join(agentsDir, agentId, 'media', 'ui-upload');
99
+ if (!fs.existsSync(stagingDir))
100
+ continue;
101
+ // Walk up to 2 levels: ui-upload/ and ui-upload/{subdir}/
102
+ for (const entry of fs.readdirSync(stagingDir)) {
103
+ const entryPath = path.join(stagingDir, entry);
104
+ const stat = fs.statSync(entryPath);
105
+ if (stat.isDirectory()) {
106
+ for (const file of fs.readdirSync(entryPath)) {
107
+ const filePath = path.join(entryPath, file);
108
+ try {
109
+ const fstat = fs.statSync(filePath);
110
+ if (now - fstat.mtimeMs > STAGING_MAX_AGE_MS)
111
+ fs.unlinkSync(filePath);
112
+ }
113
+ catch { /* skip */ }
114
+ }
115
+ // Remove empty subdir
116
+ try {
117
+ if (fs.readdirSync(entryPath).length === 0)
118
+ fs.rmdirSync(entryPath);
119
+ }
120
+ catch { /* skip */ }
121
+ }
122
+ else if (stat.isFile() && now - stat.mtimeMs > STAGING_MAX_AGE_MS) {
123
+ try {
124
+ fs.unlinkSync(entryPath);
125
+ }
126
+ catch { /* skip */ }
127
+ }
128
+ }
129
+ }
130
+ }
131
+ /**
132
+ * Delete all media files for a chatId (called by /clear).
133
+ */
134
+ static clearChatMedia(agentsBaseDir, agentId, chatId) {
135
+ const dir = MediaStore.mediaDir(agentsBaseDir, agentId, chatId);
136
+ if (fs.existsSync(dir)) {
137
+ fs.rmSync(dir, { recursive: true, force: true });
138
+ }
139
+ }
140
+ static deleteMediaFiles(agentsBaseDir, agentId, relativePaths) {
141
+ for (const rel of relativePaths) {
142
+ try {
143
+ const abs = MediaStore.resolvePath(agentsBaseDir, agentId, rel);
144
+ if (fs.existsSync(abs))
145
+ fs.unlinkSync(abs);
146
+ }
147
+ catch { /* skip — path traversal or missing file */ }
148
+ }
149
+ }
150
+ static isAllowedMime(mime) {
151
+ return ALLOWED_MIME_PREFIXES.some((p) => mime.startsWith(p));
152
+ }
153
+ static get maxUploadBytes() {
154
+ return MAX_UPLOAD_BYTES;
155
+ }
156
+ }
157
+ exports.MediaStore = MediaStore;
158
+ //# sourceMappingURL=media-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media-store.js","sourceRoot":"","sources":["../../src/history/media-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ export type HistorySource = 'telegram' | 'discord' | 'api' | 'ui';
2
+ export type MessageRole = 'user' | 'assistant' | 'system';
3
+ export interface HistoryMessage {
4
+ id?: number;
5
+ chatId: string;
6
+ sessionId: string;
7
+ source: HistorySource;
8
+ role: MessageRole;
9
+ content: string;
10
+ senderName?: string;
11
+ senderId?: string;
12
+ platformMessageId?: string;
13
+ mediaFiles?: string[];
14
+ ts: number;
15
+ }
16
+ export interface MessagePage {
17
+ messages: HistoryMessage[];
18
+ hasMore: boolean;
19
+ nextCursor: number | null;
20
+ }
21
+ export interface SearchResult extends HistoryMessage {
22
+ snippet: string;
23
+ }
24
+ export interface SearchPage {
25
+ results: SearchResult[];
26
+ total: number;
27
+ hasMore: boolean;
28
+ }
29
+ export interface ChatSummary {
30
+ chatId: string;
31
+ source: HistorySource;
32
+ displayName: string | null;
33
+ messageCount: number;
34
+ lastActive: number;
35
+ lastMessagePreview: string | null;
36
+ }
37
+ export interface PaginationOpts {
38
+ limit?: number;
39
+ before?: number;
40
+ after?: number;
41
+ sessionId?: string;
42
+ }
43
+ export interface SearchOpts {
44
+ limit?: number;
45
+ offset?: number;
46
+ }
47
+ export interface SessionSummary {
48
+ chatId: string | null;
49
+ sessionId: string;
50
+ source: HistorySource;
51
+ messageCount: number;
52
+ createdAt: number;
53
+ lastActivity: number;
54
+ lastMessage: string | null;
55
+ sessionName: string | null;
56
+ }
57
+ export interface AgentSessionSummary {
58
+ agentId: string;
59
+ description: string;
60
+ sessions: SessionSummary[];
61
+ }
62
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/history/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,SAAS,GAAG,KAAK,GAAG,IAAI,CAAC;AAClE,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,WAAW,GAAG,QAAQ,CAAC;AAE1D,MAAM,WAAW,cAAc;IAC7B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,aAAa,CAAC;IACtB,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,YAAa,SAAQ,cAAc;IAClD,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,aAAa,CAAC;IACtB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,aAAa,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,cAAc,EAAE,CAAC;CAC5B"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/history/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}