@ebowwa/glm-daemon 0.3.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/memory.js ADDED
@@ -0,0 +1,323 @@
1
+ "use strict";
2
+ /**
3
+ * Conversation Memory - Generic conversation tracking for any channel
4
+ *
5
+ * Tracks chat history per user/conversation with persistence.
6
+ * Can be used by Telegram, Discord, or any other channel.
7
+ *
8
+ * Storage format: JSONL (JSON Lines)
9
+ * Each line is a JSON object: {"id": "...", "messages": [...], "lastUpdated": timestamp}
10
+ */
11
+ var __extends = (this && this.__extends) || (function () {
12
+ var extendStatics = function (d, b) {
13
+ extendStatics = Object.setPrototypeOf ||
14
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
15
+ function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
16
+ return extendStatics(d, b);
17
+ };
18
+ return function (d, b) {
19
+ if (typeof b !== "function" && b !== null)
20
+ throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
21
+ extendStatics(d, b);
22
+ function __() { this.constructor = d; }
23
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
24
+ };
25
+ })();
26
+ Object.defineProperty(exports, "__esModule", { value: true });
27
+ exports.StringConversationMemory = exports.NumericConversationMemory = exports.ConversationMemory = void 0;
28
+ var fs_1 = require("fs");
29
+ var path_1 = require("path");
30
+ /**
31
+ * Generic conversation memory that tracks chat history per conversation ID.
32
+ *
33
+ * Uses JSONL format for efficient append-only writes and streaming reads.
34
+ * Automatically migrates from old JSON format on first load.
35
+ *
36
+ * The ID type is generic (string | number) to support different channel types:
37
+ * - Telegram: number (chatId)
38
+ * - Discord: string (channelId/userId)
39
+ * - Slack: string (channelId)
40
+ *
41
+ * @example
42
+ * ```ts
43
+ * const memory = new ConversationMemory({ maxMessages: 20 });
44
+ * memory.add(12345, 'user', 'Hello!');
45
+ * memory.add(12345, 'assistant', 'Hi there!');
46
+ * const history = memory.get(12345);
47
+ * ```
48
+ */
49
+ var ConversationMemory = /** @class */ (function () {
50
+ function ConversationMemory(config) {
51
+ if (config === void 0) { config = {}; }
52
+ var _a, _b;
53
+ this.conversations = new Map();
54
+ this.needsFullSave = false;
55
+ // Default to .jsonl extension
56
+ var defaultFile = "./conversations.jsonl";
57
+ this.file = config.file || defaultFile;
58
+ // Auto-migrate from .json to .jsonl if needed
59
+ if (config.autoMigrate !== false && !(0, fs_1.existsSync)(this.file)) {
60
+ this.migrateFromJson(this.file);
61
+ }
62
+ this.maxMessages = (_a = config.maxMessages) !== null && _a !== void 0 ? _a : 10;
63
+ this.includeTimestamps = (_b = config.includeTimestamps) !== null && _b !== void 0 ? _b : true;
64
+ this.load();
65
+ }
66
+ /**
67
+ * Migrate from old JSON format to JSONL
68
+ */
69
+ ConversationMemory.prototype.migrateFromJson = function (jsonlFile) {
70
+ // Check for old .json file
71
+ var jsonFile = jsonlFile.replace(/\.jsonl$/, ".json");
72
+ if (!(0, fs_1.existsSync)(jsonFile))
73
+ return;
74
+ try {
75
+ var data = JSON.parse((0, fs_1.readFileSync)(jsonFile, "utf-8"));
76
+ var entries = [];
77
+ for (var _i = 0, _a = Object.entries(data); _i < _a.length; _i++) {
78
+ var _b = _a[_i], id = _b[0], messages = _b[1];
79
+ entries.push({
80
+ id: id,
81
+ messages: messages,
82
+ lastUpdated: Date.now(),
83
+ });
84
+ }
85
+ // Write as JSONL
86
+ var dir = (0, path_1.dirname)(jsonlFile);
87
+ if (!(0, fs_1.existsSync)(dir)) {
88
+ (0, fs_1.mkdirSync)(dir, { recursive: true });
89
+ }
90
+ var lines = entries.map(function (e) { return JSON.stringify(e); }).join("\n");
91
+ (0, fs_1.writeFileSync)(jsonlFile, lines + (lines ? "\n" : ""));
92
+ // Backup old file instead of deleting
93
+ var backupFile = jsonFile + ".backup";
94
+ (0, fs_1.renameSync)(jsonFile, backupFile);
95
+ console.log("Migrated ".concat(jsonFile, " to ").concat(jsonlFile, " (").concat(entries.length, " conversations)"));
96
+ }
97
+ catch (error) {
98
+ console.error("Migration failed: ".concat(error));
99
+ }
100
+ };
101
+ /**
102
+ * Load conversations from JSONL file
103
+ * Uses synchronous read for constructor compatibility
104
+ */
105
+ ConversationMemory.prototype.load = function () {
106
+ if (!(0, fs_1.existsSync)(this.file))
107
+ return;
108
+ try {
109
+ var content = (0, fs_1.readFileSync)(this.file, "utf-8");
110
+ var lines = content.split("\n");
111
+ for (var _i = 0, lines_1 = lines; _i < lines_1.length; _i++) {
112
+ var line = lines_1[_i];
113
+ if (!line.trim())
114
+ continue;
115
+ try {
116
+ var entry = JSON.parse(line);
117
+ var key = this.parseKey(entry.id);
118
+ this.conversations.set(key, entry.messages);
119
+ }
120
+ catch (_a) {
121
+ // Skip malformed lines
122
+ }
123
+ }
124
+ }
125
+ catch (_b) {
126
+ // Start fresh on error
127
+ }
128
+ };
129
+ /**
130
+ * Parse string key back to original type
131
+ */
132
+ ConversationMemory.prototype.parseKey = function (id) {
133
+ // Try to parse as number if it looks like one
134
+ if (/^-?\d+$/.test(id)) {
135
+ return Number(id);
136
+ }
137
+ return id;
138
+ };
139
+ /**
140
+ * Convert IdType to string for storage
141
+ */
142
+ ConversationMemory.prototype.stringifyKey = function (id) {
143
+ return String(id);
144
+ };
145
+ /**
146
+ * Save all conversations to disk (full rewrite)
147
+ * Used when entries are deleted or modified
148
+ */
149
+ ConversationMemory.prototype.saveFull = function () {
150
+ try {
151
+ var dir = (0, path_1.dirname)(this.file);
152
+ if (!(0, fs_1.existsSync)(dir)) {
153
+ (0, fs_1.mkdirSync)(dir, { recursive: true });
154
+ }
155
+ var lines = [];
156
+ for (var _i = 0, _a = this.conversations; _i < _a.length; _i++) {
157
+ var _b = _a[_i], id = _b[0], messages = _b[1];
158
+ var entry = {
159
+ id: this.stringifyKey(id),
160
+ messages: messages,
161
+ lastUpdated: Date.now(),
162
+ };
163
+ lines.push(JSON.stringify(entry));
164
+ }
165
+ (0, fs_1.writeFileSync)(this.file, lines.join("\n") + (lines.length ? "\n" : ""));
166
+ this.needsFullSave = false;
167
+ }
168
+ catch (error) {
169
+ console.error("Save failed: ".concat(error));
170
+ }
171
+ };
172
+ /**
173
+ * Append a single entry to the file (efficient for adds)
174
+ */
175
+ ConversationMemory.prototype.appendEntry = function (conversationId, messages) {
176
+ try {
177
+ var dir = (0, path_1.dirname)(this.file);
178
+ if (!(0, fs_1.existsSync)(dir)) {
179
+ (0, fs_1.mkdirSync)(dir, { recursive: true });
180
+ }
181
+ var entry = {
182
+ id: this.stringifyKey(conversationId),
183
+ messages: messages,
184
+ lastUpdated: Date.now(),
185
+ };
186
+ // Check if file exists and has content to determine if we need newline
187
+ var hasContent = (0, fs_1.existsSync)(this.file) && (0, fs_1.readFileSync)(this.file, "utf-8").length > 0;
188
+ var prefix = hasContent ? "" : "";
189
+ var line = JSON.stringify(entry) + "\n";
190
+ // We need to do a full save to replace the old entry for this conversation
191
+ // JSONL doesn't support in-place updates, so we mark for full save
192
+ this.needsFullSave = true;
193
+ // For now, do a full save since we need to replace the entry
194
+ this.saveFull();
195
+ }
196
+ catch (error) {
197
+ console.error("Append failed: ".concat(error));
198
+ }
199
+ };
200
+ /**
201
+ * Add a message to a conversation
202
+ */
203
+ ConversationMemory.prototype.add = function (conversationId, role, content) {
204
+ if (!this.conversations.has(conversationId)) {
205
+ this.conversations.set(conversationId, []);
206
+ }
207
+ var history = this.conversations.get(conversationId);
208
+ var message = { role: role, content: content };
209
+ if (this.includeTimestamps) {
210
+ message.timestamp = Date.now();
211
+ }
212
+ history.push(message);
213
+ // Keep only last N messages
214
+ if (history.length > this.maxMessages) {
215
+ history.splice(0, history.length - this.maxMessages);
216
+ }
217
+ // Save the updated conversation
218
+ this.appendEntry(conversationId, history);
219
+ };
220
+ /**
221
+ * Get conversation history for a specific conversation
222
+ */
223
+ ConversationMemory.prototype.get = function (conversationId) {
224
+ return this.conversations.get(conversationId) || [];
225
+ };
226
+ /**
227
+ * Get all conversations
228
+ */
229
+ ConversationMemory.prototype.getAll = function () {
230
+ return new Map(this.conversations);
231
+ };
232
+ /**
233
+ * Clear a specific conversation
234
+ */
235
+ ConversationMemory.prototype.clear = function (conversationId) {
236
+ this.conversations.delete(conversationId);
237
+ this.saveFull();
238
+ };
239
+ /**
240
+ * Clear all conversations
241
+ */
242
+ ConversationMemory.prototype.clearAll = function () {
243
+ this.conversations.clear();
244
+ this.saveFull();
245
+ };
246
+ /**
247
+ * Check if a conversation exists
248
+ */
249
+ ConversationMemory.prototype.has = function (conversationId) {
250
+ return this.conversations.has(conversationId);
251
+ };
252
+ /**
253
+ * Get the number of conversations
254
+ */
255
+ ConversationMemory.prototype.size = function () {
256
+ return this.conversations.size;
257
+ };
258
+ /**
259
+ * Get the messages count for a specific conversation
260
+ */
261
+ ConversationMemory.prototype.messageCount = function (conversationId) {
262
+ var _a;
263
+ return ((_a = this.conversations.get(conversationId)) === null || _a === void 0 ? void 0 : _a.length) || 0;
264
+ };
265
+ /**
266
+ * Get formatted history for API calls (OpenAI/Anthropic format)
267
+ */
268
+ ConversationMemory.prototype.getForAPI = function (conversationId) {
269
+ return this.get(conversationId).map(function (_a) {
270
+ var role = _a.role, content = _a.content;
271
+ return ({
272
+ role: role,
273
+ content: content,
274
+ });
275
+ });
276
+ };
277
+ /**
278
+ * Force a full save (useful before shutdown)
279
+ */
280
+ ConversationMemory.prototype.flush = function () {
281
+ if (this.needsFullSave || this.conversations.size > 0) {
282
+ this.saveFull();
283
+ }
284
+ };
285
+ /**
286
+ * Get the file path being used
287
+ */
288
+ ConversationMemory.prototype.getFilePath = function () {
289
+ return this.file;
290
+ };
291
+ /**
292
+ * Check if the storage uses JSONL format
293
+ */
294
+ ConversationMemory.prototype.isJsonl = function () {
295
+ return this.file.endsWith(".jsonl");
296
+ };
297
+ return ConversationMemory;
298
+ }());
299
+ exports.ConversationMemory = ConversationMemory;
300
+ /**
301
+ * Pre-configured memory for numeric IDs (like Telegram chat IDs)
302
+ */
303
+ var NumericConversationMemory = /** @class */ (function (_super) {
304
+ __extends(NumericConversationMemory, _super);
305
+ function NumericConversationMemory(config) {
306
+ if (config === void 0) { config = {}; }
307
+ return _super.call(this, config) || this;
308
+ }
309
+ return NumericConversationMemory;
310
+ }(ConversationMemory));
311
+ exports.NumericConversationMemory = NumericConversationMemory;
312
+ /**
313
+ * Pre-configured memory for string IDs (like Discord/Slack channel IDs)
314
+ */
315
+ var StringConversationMemory = /** @class */ (function (_super) {
316
+ __extends(StringConversationMemory, _super);
317
+ function StringConversationMemory(config) {
318
+ if (config === void 0) { config = {}; }
319
+ return _super.call(this, config) || this;
320
+ }
321
+ return StringConversationMemory;
322
+ }(ConversationMemory));
323
+ exports.StringConversationMemory = StringConversationMemory;
package/src/state.js ADDED
@@ -0,0 +1,168 @@
1
+ "use strict";
2
+ /**
3
+ * GLM Daemon - State Manager
4
+ *
5
+ * Manages SLAM state persistence to disk.
6
+ */
7
+ var __assign = (this && this.__assign) || function () {
8
+ __assign = Object.assign || function(t) {
9
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
10
+ s = arguments[i];
11
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
12
+ t[p] = s[p];
13
+ }
14
+ return t;
15
+ };
16
+ return __assign.apply(this, arguments);
17
+ };
18
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
19
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
20
+ return new (P || (P = Promise))(function (resolve, reject) {
21
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
22
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
23
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
24
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
25
+ });
26
+ };
27
+ var __generator = (this && this.__generator) || function (thisArg, body) {
28
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
29
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
30
+ function verb(n) { return function (v) { return step([n, v]); }; }
31
+ function step(op) {
32
+ if (f) throw new TypeError("Generator is already executing.");
33
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
34
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
35
+ if (y = 0, t) op = [op[0] & 2, t.value];
36
+ switch (op[0]) {
37
+ case 0: case 1: t = op; break;
38
+ case 4: _.label++; return { value: op[1], done: false };
39
+ case 5: _.label++; y = op[1]; op = [0]; continue;
40
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
41
+ default:
42
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
43
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
44
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
45
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
46
+ if (t[2]) _.ops.pop();
47
+ _.trys.pop(); continue;
48
+ }
49
+ op = body.call(thisArg, _);
50
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
51
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
52
+ }
53
+ };
54
+ Object.defineProperty(exports, "__esModule", { value: true });
55
+ exports.StateManager = void 0;
56
+ var fs_1 = require("fs");
57
+ var StateManager = /** @class */ (function () {
58
+ function StateManager(statePath) {
59
+ this.statePath = statePath;
60
+ }
61
+ /**
62
+ * Load state from disk
63
+ */
64
+ StateManager.prototype.load = function () {
65
+ return __awaiter(this, void 0, void 0, function () {
66
+ var content, _a;
67
+ return __generator(this, function (_b) {
68
+ switch (_b.label) {
69
+ case 0:
70
+ _b.trys.push([0, 2, , 3]);
71
+ return [4 /*yield*/, fs_1.promises.readFile(this.statePath, "utf-8")];
72
+ case 1:
73
+ content = _b.sent();
74
+ return [2 /*return*/, JSON.parse(content)];
75
+ case 2:
76
+ _a = _b.sent();
77
+ // File doesn't exist or invalid JSON
78
+ return [2 /*return*/, null];
79
+ case 3: return [2 /*return*/];
80
+ }
81
+ });
82
+ });
83
+ };
84
+ /**
85
+ * Save state to disk
86
+ */
87
+ StateManager.prototype.save = function (state) {
88
+ return __awaiter(this, void 0, void 0, function () {
89
+ return __generator(this, function (_a) {
90
+ switch (_a.label) {
91
+ case 0: return [4 /*yield*/, fs_1.promises.writeFile(this.statePath, JSON.stringify(state, null, 2), "utf-8")];
92
+ case 1:
93
+ _a.sent();
94
+ return [2 /*return*/];
95
+ }
96
+ });
97
+ });
98
+ };
99
+ /**
100
+ * Delete state file
101
+ */
102
+ StateManager.prototype.delete = function () {
103
+ return __awaiter(this, void 0, void 0, function () {
104
+ var _a;
105
+ return __generator(this, function (_b) {
106
+ switch (_b.label) {
107
+ case 0:
108
+ _b.trys.push([0, 2, , 3]);
109
+ return [4 /*yield*/, fs_1.promises.unlink(this.statePath)];
110
+ case 1:
111
+ _b.sent();
112
+ return [3 /*break*/, 3];
113
+ case 2:
114
+ _a = _b.sent();
115
+ return [3 /*break*/, 3];
116
+ case 3: return [2 /*return*/];
117
+ }
118
+ });
119
+ });
120
+ };
121
+ /**
122
+ * Check if state file exists
123
+ */
124
+ StateManager.prototype.exists = function () {
125
+ return __awaiter(this, void 0, void 0, function () {
126
+ var _a;
127
+ return __generator(this, function (_b) {
128
+ switch (_b.label) {
129
+ case 0:
130
+ _b.trys.push([0, 2, , 3]);
131
+ return [4 /*yield*/, fs_1.promises.access(this.statePath)];
132
+ case 1:
133
+ _b.sent();
134
+ return [2 /*return*/, true];
135
+ case 2:
136
+ _a = _b.sent();
137
+ return [2 /*return*/, false];
138
+ case 3: return [2 /*return*/];
139
+ }
140
+ });
141
+ });
142
+ };
143
+ /**
144
+ * Update a portion of state (merge)
145
+ */
146
+ StateManager.prototype.update = function (updates) {
147
+ return __awaiter(this, void 0, void 0, function () {
148
+ var current, updated;
149
+ return __generator(this, function (_a) {
150
+ switch (_a.label) {
151
+ case 0: return [4 /*yield*/, this.load()];
152
+ case 1:
153
+ current = _a.sent();
154
+ if (!current) {
155
+ throw new Error("No existing state to update");
156
+ }
157
+ updated = __assign(__assign({}, current), updates);
158
+ return [4 /*yield*/, this.save(updated)];
159
+ case 2:
160
+ _a.sent();
161
+ return [2 /*return*/, updated];
162
+ }
163
+ });
164
+ });
165
+ };
166
+ return StateManager;
167
+ }());
168
+ exports.StateManager = StateManager;
package/src/tools.js ADDED
@@ -0,0 +1,192 @@
1
+ "use strict";
2
+ /**
3
+ * GLM Daemon - Tool Bridge
4
+ *
5
+ * Connects GLM agents to MCP servers for tool access.
6
+ */
7
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
8
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
9
+ return new (P || (P = Promise))(function (resolve, reject) {
10
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
11
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
12
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
13
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
14
+ });
15
+ };
16
+ var __generator = (this && this.__generator) || function (thisArg, body) {
17
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
18
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
19
+ function verb(n) { return function (v) { return step([n, v]); }; }
20
+ function step(op) {
21
+ if (f) throw new TypeError("Generator is already executing.");
22
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
23
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
24
+ if (y = 0, t) op = [op[0] & 2, t.value];
25
+ switch (op[0]) {
26
+ case 0: case 1: t = op; break;
27
+ case 4: _.label++; return { value: op[1], done: false };
28
+ case 5: _.label++; y = op[1]; op = [0]; continue;
29
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
30
+ default:
31
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
32
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
33
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
34
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
35
+ if (t[2]) _.ops.pop();
36
+ _.trys.pop(); continue;
37
+ }
38
+ op = body.call(thisArg, _);
39
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
40
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
41
+ }
42
+ };
43
+ Object.defineProperty(exports, "__esModule", { value: true });
44
+ exports.ToolBridge = void 0;
45
+ var ToolBridge = /** @class */ (function () {
46
+ function ToolBridge(config) {
47
+ if (config === void 0) { config = {}; }
48
+ this.availableTools = [];
49
+ this.config = config;
50
+ this.toolTimeout = config.toolTimeout || 30000;
51
+ this.maxRetries = config.maxRetries || 3;
52
+ }
53
+ /**
54
+ * Get list of available tools
55
+ */
56
+ ToolBridge.prototype.getAvailableTools = function () {
57
+ return this.availableTools;
58
+ };
59
+ /**
60
+ * Set available tools (from MCP discovery)
61
+ */
62
+ ToolBridge.prototype.setAvailableTools = function (tools) {
63
+ this.availableTools = tools;
64
+ };
65
+ /**
66
+ * Check if a tool is allowed
67
+ */
68
+ ToolBridge.prototype.isToolAllowed = function (toolName) {
69
+ var _a;
70
+ // Check blacklist first
71
+ if ((_a = this.config.blockedTools) === null || _a === void 0 ? void 0 : _a.includes(toolName)) {
72
+ return false;
73
+ }
74
+ // If whitelist exists, check it
75
+ if (this.config.allowedTools && this.config.allowedTools.length > 0) {
76
+ return this.config.allowedTools.includes(toolName);
77
+ }
78
+ // Default: allow if not blocked
79
+ return true;
80
+ };
81
+ /**
82
+ * Execute a tool with timeout and retry
83
+ */
84
+ ToolBridge.prototype.executeTool = function (toolName, args) {
85
+ return __awaiter(this, void 0, void 0, function () {
86
+ var lastError, _loop_1, this_1, attempt, state_1;
87
+ return __generator(this, function (_a) {
88
+ switch (_a.label) {
89
+ case 0:
90
+ if (!this.isToolAllowed(toolName)) {
91
+ return [2 /*return*/, {
92
+ success: false,
93
+ error: "Tool not allowed: ".concat(toolName),
94
+ }];
95
+ }
96
+ lastError = null;
97
+ _loop_1 = function (attempt) {
98
+ var result, error_1;
99
+ return __generator(this, function (_b) {
100
+ switch (_b.label) {
101
+ case 0:
102
+ _b.trys.push([0, 2, , 5]);
103
+ return [4 /*yield*/, this_1.executeWithTimeout(toolName, args)];
104
+ case 1:
105
+ result = _b.sent();
106
+ return [2 /*return*/, { value: { success: true, result: result } }];
107
+ case 2:
108
+ error_1 = _b.sent();
109
+ lastError = error_1;
110
+ if (!(attempt < this_1.maxRetries - 1)) return [3 /*break*/, 4];
111
+ return [4 /*yield*/, new Promise(function (resolve) {
112
+ return setTimeout(resolve, Math.pow(2, attempt) * 1000);
113
+ })];
114
+ case 3:
115
+ _b.sent();
116
+ _b.label = 4;
117
+ case 4: return [3 /*break*/, 5];
118
+ case 5: return [2 /*return*/];
119
+ }
120
+ });
121
+ };
122
+ this_1 = this;
123
+ attempt = 0;
124
+ _a.label = 1;
125
+ case 1:
126
+ if (!(attempt < this.maxRetries)) return [3 /*break*/, 4];
127
+ return [5 /*yield**/, _loop_1(attempt)];
128
+ case 2:
129
+ state_1 = _a.sent();
130
+ if (typeof state_1 === "object")
131
+ return [2 /*return*/, state_1.value];
132
+ _a.label = 3;
133
+ case 3:
134
+ attempt++;
135
+ return [3 /*break*/, 1];
136
+ case 4: return [2 /*return*/, {
137
+ success: false,
138
+ error: (lastError === null || lastError === void 0 ? void 0 : lastError.message) || "Unknown error",
139
+ }];
140
+ }
141
+ });
142
+ });
143
+ };
144
+ /**
145
+ * Execute tool with timeout
146
+ */
147
+ ToolBridge.prototype.executeWithTimeout = function (toolName, args) {
148
+ return __awaiter(this, void 0, void 0, function () {
149
+ var _this = this;
150
+ return __generator(this, function (_a) {
151
+ return [2 /*return*/, new Promise(function (resolve, reject) {
152
+ var timer = setTimeout(function () {
153
+ reject(new Error("Tool timeout: ".concat(toolName)));
154
+ }, _this.toolTimeout);
155
+ // TODO: Actually call MCP tool here
156
+ // For now, this is a placeholder
157
+ setTimeout(function () {
158
+ clearTimeout(timer);
159
+ resolve("Executed ".concat(toolName, " with ").concat(JSON.stringify(args)));
160
+ }, 100);
161
+ })];
162
+ });
163
+ });
164
+ };
165
+ /**
166
+ * Discover tools from MCP servers
167
+ */
168
+ ToolBridge.prototype.discoverMCPTools = function () {
169
+ return __awaiter(this, void 0, void 0, function () {
170
+ var commonTools;
171
+ return __generator(this, function (_a) {
172
+ if (!this.config.enableMCP) {
173
+ return [2 /*return*/];
174
+ }
175
+ commonTools = [
176
+ "Read",
177
+ "Write",
178
+ "Edit",
179
+ "Grep",
180
+ "Glob",
181
+ "Bash",
182
+ "git_status",
183
+ "git_commit",
184
+ ];
185
+ this.setAvailableTools(commonTools);
186
+ return [2 /*return*/];
187
+ });
188
+ });
189
+ };
190
+ return ToolBridge;
191
+ }());
192
+ exports.ToolBridge = ToolBridge;