@alfe.ai/openclaw-database 0.0.4 → 0.0.5
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/dist/index.cjs +2 -0
- package/dist/index.d.cts +2 -0
- package/dist/plugin.cjs +2 -0
- package/dist/plugin.d.cts +19 -0
- package/dist/plugin2.cjs +525 -0
- package/package.json +8 -6
package/dist/index.cjs
ADDED
package/dist/index.d.cts
ADDED
package/dist/plugin.cjs
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//#region src/plugin.d.ts
|
|
2
|
+
interface PluginApi {
|
|
3
|
+
logger: {
|
|
4
|
+
info: (...args: unknown[]) => void;
|
|
5
|
+
warn: (...args: unknown[]) => void;
|
|
6
|
+
error: (...args: unknown[]) => void;
|
|
7
|
+
debug: (...args: unknown[]) => void;
|
|
8
|
+
};
|
|
9
|
+
registerTool(tool: unknown): void;
|
|
10
|
+
}
|
|
11
|
+
declare const plugin: {
|
|
12
|
+
id: string;
|
|
13
|
+
name: string;
|
|
14
|
+
version: string;
|
|
15
|
+
activate(api: PluginApi): void;
|
|
16
|
+
deactivate(api: PluginApi): Promise<void>;
|
|
17
|
+
};
|
|
18
|
+
//#endregion
|
|
19
|
+
export { plugin as default };
|
package/dist/plugin2.cjs
ADDED
|
@@ -0,0 +1,525 @@
|
|
|
1
|
+
let mongodb = require("mongodb");
|
|
2
|
+
let _alfe_ai_config = require("@alfe.ai/config");
|
|
3
|
+
//#region src/tools.ts
|
|
4
|
+
const DEFAULT_DB = "org_default";
|
|
5
|
+
function str(required = true) {
|
|
6
|
+
return {
|
|
7
|
+
type: "string",
|
|
8
|
+
...required ? {} : { default: "" }
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
function optStr() {
|
|
12
|
+
return {
|
|
13
|
+
type: "string",
|
|
14
|
+
default: ""
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function registerTools(api, _client, _databases, audit, lazyInit) {
|
|
18
|
+
async function db(name) {
|
|
19
|
+
const { mongoClient, databases } = lazyInit ? await lazyInit() : {
|
|
20
|
+
mongoClient: _client ?? (() => {
|
|
21
|
+
throw new Error("MongoDB client not initialized");
|
|
22
|
+
})(),
|
|
23
|
+
databases: _databases
|
|
24
|
+
};
|
|
25
|
+
const dbName = name ?? DEFAULT_DB;
|
|
26
|
+
if (!databases.includes(dbName)) throw new Error(`Access denied: database "${dbName}" is not in the allowed list`);
|
|
27
|
+
return mongoClient.db(dbName);
|
|
28
|
+
}
|
|
29
|
+
api.registerTool({
|
|
30
|
+
name: "db_find",
|
|
31
|
+
description: "Find documents matching a filter",
|
|
32
|
+
label: "db_find",
|
|
33
|
+
parameters: {
|
|
34
|
+
type: "object",
|
|
35
|
+
properties: {
|
|
36
|
+
database: optStr(),
|
|
37
|
+
collection: str(),
|
|
38
|
+
filter: {
|
|
39
|
+
type: "object",
|
|
40
|
+
default: {}
|
|
41
|
+
},
|
|
42
|
+
sort: {
|
|
43
|
+
type: "object",
|
|
44
|
+
default: {}
|
|
45
|
+
},
|
|
46
|
+
limit: {
|
|
47
|
+
type: "number",
|
|
48
|
+
default: 20
|
|
49
|
+
},
|
|
50
|
+
skip: {
|
|
51
|
+
type: "number",
|
|
52
|
+
default: 0
|
|
53
|
+
},
|
|
54
|
+
projection: {
|
|
55
|
+
type: "object",
|
|
56
|
+
default: {}
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
required: ["collection"]
|
|
60
|
+
},
|
|
61
|
+
execute: async (_id, p) => {
|
|
62
|
+
const docs = await (await db(p.database)).collection(p.collection).find(p.filter).sort(p.sort).project(p.projection).skip(p.skip || 0).limit(p.limit || 20).toArray();
|
|
63
|
+
return {
|
|
64
|
+
documents: docs,
|
|
65
|
+
count: docs.length
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
api.registerTool({
|
|
70
|
+
name: "db_find_one",
|
|
71
|
+
description: "Find a single document matching a filter",
|
|
72
|
+
label: "db_find_one",
|
|
73
|
+
parameters: {
|
|
74
|
+
type: "object",
|
|
75
|
+
properties: {
|
|
76
|
+
database: optStr(),
|
|
77
|
+
collection: str(),
|
|
78
|
+
filter: {
|
|
79
|
+
type: "object",
|
|
80
|
+
default: {}
|
|
81
|
+
},
|
|
82
|
+
projection: {
|
|
83
|
+
type: "object",
|
|
84
|
+
default: {}
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
required: ["collection"]
|
|
88
|
+
},
|
|
89
|
+
execute: async (_id, p) => {
|
|
90
|
+
return await (await db(p.database)).collection(p.collection).findOne(p.filter, { projection: p.projection }) ?? { _not_found: true };
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
api.registerTool({
|
|
94
|
+
name: "db_insert",
|
|
95
|
+
description: "Insert one or more documents",
|
|
96
|
+
label: "db_insert",
|
|
97
|
+
parameters: {
|
|
98
|
+
type: "object",
|
|
99
|
+
properties: {
|
|
100
|
+
database: optStr(),
|
|
101
|
+
collection: str(),
|
|
102
|
+
documents: {
|
|
103
|
+
type: "array",
|
|
104
|
+
items: { type: "object" }
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
required: ["collection", "documents"]
|
|
108
|
+
},
|
|
109
|
+
execute: async (_id, p) => {
|
|
110
|
+
const docs = p.documents;
|
|
111
|
+
const result = await (await db(p.database)).collection(p.collection).insertMany(docs);
|
|
112
|
+
audit({
|
|
113
|
+
database: p.database || DEFAULT_DB,
|
|
114
|
+
collection: p.collection,
|
|
115
|
+
operation: "insert",
|
|
116
|
+
summary: `Inserted ${String(docs.length)} document(s)`
|
|
117
|
+
});
|
|
118
|
+
return {
|
|
119
|
+
insertedCount: result.insertedCount,
|
|
120
|
+
insertedIds: Object.values(result.insertedIds).map(String)
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
api.registerTool({
|
|
125
|
+
name: "db_update",
|
|
126
|
+
description: "Update documents matching a filter",
|
|
127
|
+
label: "db_update",
|
|
128
|
+
parameters: {
|
|
129
|
+
type: "object",
|
|
130
|
+
properties: {
|
|
131
|
+
database: optStr(),
|
|
132
|
+
collection: str(),
|
|
133
|
+
filter: { type: "object" },
|
|
134
|
+
update: { type: "object" },
|
|
135
|
+
upsert: {
|
|
136
|
+
type: "boolean",
|
|
137
|
+
default: false
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
required: [
|
|
141
|
+
"collection",
|
|
142
|
+
"filter",
|
|
143
|
+
"update"
|
|
144
|
+
]
|
|
145
|
+
},
|
|
146
|
+
execute: async (_id, p) => {
|
|
147
|
+
const result = await (await db(p.database)).collection(p.collection).updateMany(p.filter, p.update, { upsert: p.upsert || false });
|
|
148
|
+
audit({
|
|
149
|
+
database: p.database || DEFAULT_DB,
|
|
150
|
+
collection: p.collection,
|
|
151
|
+
operation: "update",
|
|
152
|
+
summary: `Modified ${String(result.modifiedCount)}`
|
|
153
|
+
});
|
|
154
|
+
return {
|
|
155
|
+
matchedCount: result.matchedCount,
|
|
156
|
+
modifiedCount: result.modifiedCount,
|
|
157
|
+
upsertedId: result.upsertedId ? String(result.upsertedId) : null
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
api.registerTool({
|
|
162
|
+
name: "db_delete",
|
|
163
|
+
description: "Delete documents matching a filter",
|
|
164
|
+
label: "db_delete",
|
|
165
|
+
parameters: {
|
|
166
|
+
type: "object",
|
|
167
|
+
properties: {
|
|
168
|
+
database: optStr(),
|
|
169
|
+
collection: str(),
|
|
170
|
+
filter: { type: "object" }
|
|
171
|
+
},
|
|
172
|
+
required: ["collection", "filter"]
|
|
173
|
+
},
|
|
174
|
+
execute: async (_id, p) => {
|
|
175
|
+
const result = await (await db(p.database)).collection(p.collection).deleteMany(p.filter);
|
|
176
|
+
audit({
|
|
177
|
+
database: p.database || DEFAULT_DB,
|
|
178
|
+
collection: p.collection,
|
|
179
|
+
operation: "delete",
|
|
180
|
+
summary: `Deleted ${String(result.deletedCount)}`
|
|
181
|
+
});
|
|
182
|
+
return { deletedCount: result.deletedCount };
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
api.registerTool({
|
|
186
|
+
name: "db_count",
|
|
187
|
+
description: "Count documents matching a filter",
|
|
188
|
+
label: "db_count",
|
|
189
|
+
parameters: {
|
|
190
|
+
type: "object",
|
|
191
|
+
properties: {
|
|
192
|
+
database: optStr(),
|
|
193
|
+
collection: str(),
|
|
194
|
+
filter: {
|
|
195
|
+
type: "object",
|
|
196
|
+
default: {}
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
required: ["collection"]
|
|
200
|
+
},
|
|
201
|
+
execute: async (_id, p) => {
|
|
202
|
+
return { count: await (await db(p.database)).collection(p.collection).countDocuments(p.filter) };
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
api.registerTool({
|
|
206
|
+
name: "db_aggregate",
|
|
207
|
+
description: "Run an aggregation pipeline",
|
|
208
|
+
label: "db_aggregate",
|
|
209
|
+
parameters: {
|
|
210
|
+
type: "object",
|
|
211
|
+
properties: {
|
|
212
|
+
database: optStr(),
|
|
213
|
+
collection: str(),
|
|
214
|
+
pipeline: {
|
|
215
|
+
type: "array",
|
|
216
|
+
items: { type: "object" }
|
|
217
|
+
}
|
|
218
|
+
},
|
|
219
|
+
required: ["collection", "pipeline"]
|
|
220
|
+
},
|
|
221
|
+
execute: async (_id, p) => {
|
|
222
|
+
const results = await (await db(p.database)).collection(p.collection).aggregate(p.pipeline).toArray();
|
|
223
|
+
return {
|
|
224
|
+
results,
|
|
225
|
+
count: results.length
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
api.registerTool({
|
|
230
|
+
name: "db_list_databases",
|
|
231
|
+
description: "List databases the agent can access",
|
|
232
|
+
label: "db_list_databases",
|
|
233
|
+
parameters: {
|
|
234
|
+
type: "object",
|
|
235
|
+
properties: {}
|
|
236
|
+
},
|
|
237
|
+
execute: async () => {
|
|
238
|
+
const { databases } = lazyInit ? await lazyInit() : { databases: _databases };
|
|
239
|
+
return { databases };
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
api.registerTool({
|
|
243
|
+
name: "db_list_collections",
|
|
244
|
+
description: "List collections in a database",
|
|
245
|
+
label: "db_list_collections",
|
|
246
|
+
parameters: {
|
|
247
|
+
type: "object",
|
|
248
|
+
properties: { database: optStr() }
|
|
249
|
+
},
|
|
250
|
+
execute: async (_id, p) => {
|
|
251
|
+
return { collections: (await (await db(p.database)).listCollections().toArray()).map((c) => ({
|
|
252
|
+
name: c.name,
|
|
253
|
+
type: c.type
|
|
254
|
+
})) };
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
api.registerTool({
|
|
258
|
+
name: "db_create_collection",
|
|
259
|
+
description: "Create a new collection",
|
|
260
|
+
label: "db_create_collection",
|
|
261
|
+
parameters: {
|
|
262
|
+
type: "object",
|
|
263
|
+
properties: {
|
|
264
|
+
database: optStr(),
|
|
265
|
+
collection: str()
|
|
266
|
+
},
|
|
267
|
+
required: ["collection"]
|
|
268
|
+
},
|
|
269
|
+
execute: async (_id, p) => {
|
|
270
|
+
await (await db(p.database)).createCollection(p.collection);
|
|
271
|
+
audit({
|
|
272
|
+
database: p.database || DEFAULT_DB,
|
|
273
|
+
collection: p.collection,
|
|
274
|
+
operation: "create_collection"
|
|
275
|
+
});
|
|
276
|
+
return { success: true };
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
api.registerTool({
|
|
280
|
+
name: "db_drop_collection",
|
|
281
|
+
description: "Drop a collection",
|
|
282
|
+
label: "db_drop_collection",
|
|
283
|
+
parameters: {
|
|
284
|
+
type: "object",
|
|
285
|
+
properties: {
|
|
286
|
+
database: optStr(),
|
|
287
|
+
collection: str()
|
|
288
|
+
},
|
|
289
|
+
required: ["collection"]
|
|
290
|
+
},
|
|
291
|
+
execute: async (_id, p) => {
|
|
292
|
+
await (await db(p.database)).dropCollection(p.collection);
|
|
293
|
+
audit({
|
|
294
|
+
database: p.database || DEFAULT_DB,
|
|
295
|
+
collection: p.collection,
|
|
296
|
+
operation: "drop_collection"
|
|
297
|
+
});
|
|
298
|
+
return { success: true };
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
api.registerTool({
|
|
302
|
+
name: "db_collection_schema",
|
|
303
|
+
description: "Inspect a collection's schema by sampling documents",
|
|
304
|
+
label: "db_collection_schema",
|
|
305
|
+
parameters: {
|
|
306
|
+
type: "object",
|
|
307
|
+
properties: {
|
|
308
|
+
database: optStr(),
|
|
309
|
+
collection: str()
|
|
310
|
+
},
|
|
311
|
+
required: ["collection"]
|
|
312
|
+
},
|
|
313
|
+
execute: async (_id, p) => {
|
|
314
|
+
const sample = await (await db(p.database)).collection(p.collection).find().limit(100).toArray();
|
|
315
|
+
const fieldTypes = /* @__PURE__ */ new Map();
|
|
316
|
+
for (const doc of sample) for (const [key, value] of Object.entries(doc)) {
|
|
317
|
+
const types = fieldTypes.get(key) ?? /* @__PURE__ */ new Set();
|
|
318
|
+
types.add(value === null ? "null" : typeof value);
|
|
319
|
+
fieldTypes.set(key, types);
|
|
320
|
+
}
|
|
321
|
+
return {
|
|
322
|
+
sampleSize: sample.length,
|
|
323
|
+
fields: [...fieldTypes.entries()].map(([name, types]) => ({
|
|
324
|
+
name,
|
|
325
|
+
types: [...types]
|
|
326
|
+
}))
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
});
|
|
330
|
+
api.registerTool({
|
|
331
|
+
name: "db_collection_stats",
|
|
332
|
+
description: "Get collection doc count, size, and indexes",
|
|
333
|
+
label: "db_collection_stats",
|
|
334
|
+
parameters: {
|
|
335
|
+
type: "object",
|
|
336
|
+
properties: {
|
|
337
|
+
database: optStr(),
|
|
338
|
+
collection: str()
|
|
339
|
+
},
|
|
340
|
+
required: ["collection"]
|
|
341
|
+
},
|
|
342
|
+
execute: async (_id, p) => {
|
|
343
|
+
const coll = (await db(p.database)).collection(p.collection);
|
|
344
|
+
const count = await coll.countDocuments();
|
|
345
|
+
const indexes = await coll.indexes();
|
|
346
|
+
return {
|
|
347
|
+
count,
|
|
348
|
+
indexCount: indexes.length,
|
|
349
|
+
indexes: indexes.map((i) => ({
|
|
350
|
+
name: i.name,
|
|
351
|
+
key: i.key
|
|
352
|
+
}))
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
api.registerTool({
|
|
357
|
+
name: "db_create_index",
|
|
358
|
+
description: "Create an index on a collection",
|
|
359
|
+
label: "db_create_index",
|
|
360
|
+
parameters: {
|
|
361
|
+
type: "object",
|
|
362
|
+
properties: {
|
|
363
|
+
database: optStr(),
|
|
364
|
+
collection: str(),
|
|
365
|
+
keys: { type: "object" },
|
|
366
|
+
options: {
|
|
367
|
+
type: "object",
|
|
368
|
+
default: {}
|
|
369
|
+
}
|
|
370
|
+
},
|
|
371
|
+
required: ["collection", "keys"]
|
|
372
|
+
},
|
|
373
|
+
execute: async (_id, p) => {
|
|
374
|
+
const indexName = await (await db(p.database)).collection(p.collection).createIndex(p.keys, p.options);
|
|
375
|
+
audit({
|
|
376
|
+
database: p.database || DEFAULT_DB,
|
|
377
|
+
collection: p.collection,
|
|
378
|
+
operation: "create_index",
|
|
379
|
+
summary: indexName
|
|
380
|
+
});
|
|
381
|
+
return { indexName };
|
|
382
|
+
}
|
|
383
|
+
});
|
|
384
|
+
api.registerTool({
|
|
385
|
+
name: "db_list_indexes",
|
|
386
|
+
description: "List indexes on a collection",
|
|
387
|
+
label: "db_list_indexes",
|
|
388
|
+
parameters: {
|
|
389
|
+
type: "object",
|
|
390
|
+
properties: {
|
|
391
|
+
database: optStr(),
|
|
392
|
+
collection: str()
|
|
393
|
+
},
|
|
394
|
+
required: ["collection"]
|
|
395
|
+
},
|
|
396
|
+
execute: async (_id, p) => {
|
|
397
|
+
return { indexes: (await (await db(p.database)).collection(p.collection).indexes()).map((i) => ({
|
|
398
|
+
name: i.name,
|
|
399
|
+
key: i.key,
|
|
400
|
+
unique: i.unique
|
|
401
|
+
})) };
|
|
402
|
+
}
|
|
403
|
+
});
|
|
404
|
+
api.registerTool({
|
|
405
|
+
name: "db_drop_index",
|
|
406
|
+
description: "Drop an index by name",
|
|
407
|
+
label: "db_drop_index",
|
|
408
|
+
parameters: {
|
|
409
|
+
type: "object",
|
|
410
|
+
properties: {
|
|
411
|
+
database: optStr(),
|
|
412
|
+
collection: str(),
|
|
413
|
+
indexName: str()
|
|
414
|
+
},
|
|
415
|
+
required: ["collection", "indexName"]
|
|
416
|
+
},
|
|
417
|
+
execute: async (_id, p) => {
|
|
418
|
+
await (await db(p.database)).collection(p.collection).dropIndex(p.indexName);
|
|
419
|
+
audit({
|
|
420
|
+
database: p.database || DEFAULT_DB,
|
|
421
|
+
collection: p.collection,
|
|
422
|
+
operation: "drop_index",
|
|
423
|
+
summary: p.indexName
|
|
424
|
+
});
|
|
425
|
+
return { success: true };
|
|
426
|
+
}
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
//#endregion
|
|
430
|
+
//#region src/plugin.ts
|
|
431
|
+
let mongoClient = null;
|
|
432
|
+
let initPromise = null;
|
|
433
|
+
async function fetchCredentials(apiUrl, apiKey) {
|
|
434
|
+
const res = await fetch(`${apiUrl}/agents/database/register`, {
|
|
435
|
+
method: "POST",
|
|
436
|
+
headers: {
|
|
437
|
+
"Content-Type": "application/json",
|
|
438
|
+
Authorization: `Bearer ${apiKey}`
|
|
439
|
+
}
|
|
440
|
+
});
|
|
441
|
+
if (!res.ok) throw new Error(`Failed to register database credentials: ${String(res.status)} ${res.statusText}`);
|
|
442
|
+
return (await res.json()).data;
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Lazy initializer — fetches credentials and connects to MongoDB on first use.
|
|
446
|
+
* Returns a shared promise so concurrent calls don't duplicate work.
|
|
447
|
+
*/
|
|
448
|
+
function ensureInitialized(apiUrl, apiKey) {
|
|
449
|
+
if (initPromise) return initPromise;
|
|
450
|
+
initPromise = (async () => {
|
|
451
|
+
const credentials = await fetchCredentials(apiUrl, apiKey);
|
|
452
|
+
if (!credentials.connectionString) throw new Error("No connection string returned — cluster may still be provisioning");
|
|
453
|
+
const url = new URL(credentials.connectionString);
|
|
454
|
+
url.username = credentials.username;
|
|
455
|
+
url.password = credentials.password;
|
|
456
|
+
const client = new mongodb.MongoClient(url.toString(), {
|
|
457
|
+
maxPoolSize: 3,
|
|
458
|
+
minPoolSize: 1,
|
|
459
|
+
serverSelectionTimeoutMS: 5e3
|
|
460
|
+
});
|
|
461
|
+
await client.connect();
|
|
462
|
+
mongoClient = client;
|
|
463
|
+
return {
|
|
464
|
+
mongoClient: client,
|
|
465
|
+
databases: credentials.databases,
|
|
466
|
+
apiUrl,
|
|
467
|
+
apiKey
|
|
468
|
+
};
|
|
469
|
+
})();
|
|
470
|
+
initPromise.catch(() => {
|
|
471
|
+
initPromise = null;
|
|
472
|
+
});
|
|
473
|
+
return initPromise;
|
|
474
|
+
}
|
|
475
|
+
function reportAudit(apiUrl, apiKey, entry) {
|
|
476
|
+
fetch(`${apiUrl}/agents/database/audit`, {
|
|
477
|
+
method: "POST",
|
|
478
|
+
headers: {
|
|
479
|
+
"Content-Type": "application/json",
|
|
480
|
+
Authorization: `Bearer ${apiKey}`
|
|
481
|
+
},
|
|
482
|
+
body: JSON.stringify(entry)
|
|
483
|
+
}).catch(() => {});
|
|
484
|
+
}
|
|
485
|
+
const plugin = {
|
|
486
|
+
id: "@alfe.ai/openclaw-database",
|
|
487
|
+
name: "Database",
|
|
488
|
+
version: "0.0.1",
|
|
489
|
+
activate(api) {
|
|
490
|
+
const log = api.logger;
|
|
491
|
+
log.info("Database plugin activating...");
|
|
492
|
+
let apiUrl;
|
|
493
|
+
let apiKey;
|
|
494
|
+
try {
|
|
495
|
+
const config = (0, _alfe_ai_config.resolveConfig)();
|
|
496
|
+
apiUrl = config.apiUrl;
|
|
497
|
+
apiKey = config.apiKey;
|
|
498
|
+
} catch (err) {
|
|
499
|
+
log.error(`Database plugin: failed to resolve config — ${err instanceof Error ? err.message : String(err)}`);
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
ensureInitialized(apiUrl, apiKey).then(({ databases }) => {
|
|
503
|
+
log.info(`Database plugin connected — ${String(databases.length)} databases available`);
|
|
504
|
+
}).catch((err) => {
|
|
505
|
+
log.warn(`Database plugin: background init failed (will retry on first tool use) — ${err instanceof Error ? err.message : String(err)}`);
|
|
506
|
+
});
|
|
507
|
+
registerTools(api, null, [], (entry) => {
|
|
508
|
+
reportAudit(apiUrl, apiKey, entry);
|
|
509
|
+
}, () => ensureInitialized(apiUrl, apiKey));
|
|
510
|
+
},
|
|
511
|
+
async deactivate(api) {
|
|
512
|
+
api.logger.info("Database plugin deactivating...");
|
|
513
|
+
if (mongoClient) {
|
|
514
|
+
await mongoClient.close();
|
|
515
|
+
mongoClient = null;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
};
|
|
519
|
+
//#endregion
|
|
520
|
+
Object.defineProperty(exports, "plugin", {
|
|
521
|
+
enumerable: true,
|
|
522
|
+
get: function() {
|
|
523
|
+
return plugin;
|
|
524
|
+
}
|
|
525
|
+
});
|
package/package.json
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alfe.ai/openclaw-database",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "OpenClaw database plugin — MongoDB access for agents via MCP tools",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/plugin.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
8
8
|
"exports": {
|
|
9
9
|
".": {
|
|
10
|
-
"
|
|
11
|
-
"
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"require": "./dist/index.cjs",
|
|
12
|
+
"import": "./dist/index.js"
|
|
12
13
|
},
|
|
13
14
|
"./plugin": {
|
|
14
|
-
"
|
|
15
|
-
"
|
|
15
|
+
"types": "./dist/plugin.d.ts",
|
|
16
|
+
"require": "./dist/plugin.cjs",
|
|
17
|
+
"import": "./dist/plugin.js"
|
|
16
18
|
}
|
|
17
19
|
},
|
|
18
20
|
"openclaw": {
|
|
@@ -26,7 +28,7 @@
|
|
|
26
28
|
],
|
|
27
29
|
"dependencies": {
|
|
28
30
|
"mongodb": "^6.12.0",
|
|
29
|
-
"@alfe.ai/config": "0.0.
|
|
31
|
+
"@alfe.ai/config": "0.0.7"
|
|
30
32
|
},
|
|
31
33
|
"license": "UNLICENSED",
|
|
32
34
|
"scripts": {
|