@lanonasis/cli 3.0.1 ā 3.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/enhanced-memory.d.ts +5 -0
- package/dist/commands/enhanced-memory.js +404 -0
- package/dist/commands/mcp.js +27 -6
- package/dist/index.js +0 -0
- package/dist/mcp/access-control.d.ts +68 -0
- package/dist/mcp/access-control.js +228 -0
- package/dist/mcp/enhanced-server.d.ts +38 -0
- package/dist/mcp/enhanced-server.js +320 -0
- package/dist/mcp/logger.d.ts +20 -0
- package/dist/mcp/logger.js +47 -0
- package/dist/mcp/memory-state.d.ts +81 -0
- package/dist/mcp/memory-state.js +301 -0
- package/dist/mcp/schemas/tool-schemas.d.ts +8 -8
- package/dist/mcp/vector-store.d.ts +31 -0
- package/dist/mcp/vector-store.js +92 -0
- package/package.json +1 -1
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enhanced Memory Commands - mem0-inspired advanced operations
|
|
3
|
+
*/
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import ora from 'ora';
|
|
6
|
+
import { table } from 'table';
|
|
7
|
+
import inquirer from 'inquirer';
|
|
8
|
+
import { getMCPClient } from '../utils/mcp-client.js';
|
|
9
|
+
import { CLIConfig } from '../utils/config.js';
|
|
10
|
+
export function enhancedMemoryCommands(program) {
|
|
11
|
+
const memory = program.command('memory').description('Enhanced memory operations with mem0-inspired features');
|
|
12
|
+
// Bulk pause memories
|
|
13
|
+
memory.command('bulk-pause')
|
|
14
|
+
.description('Pause multiple memories by criteria')
|
|
15
|
+
.option('--category <category>', 'Pause memories in specific category')
|
|
16
|
+
.option('--app <app_id>', 'Pause memories from specific app')
|
|
17
|
+
.option('--before <date>', 'Pause memories created before date (ISO format)')
|
|
18
|
+
.option('--ids <ids>', 'Comma-separated memory IDs to pause')
|
|
19
|
+
.option('--dry-run', 'Show what would be paused without executing')
|
|
20
|
+
.action(async (options) => {
|
|
21
|
+
const spinner = ora('Processing bulk pause operation...').start();
|
|
22
|
+
try {
|
|
23
|
+
const client = getMCPClient();
|
|
24
|
+
if (!client.isConnectedToServer()) {
|
|
25
|
+
spinner.info('Connecting to MCP server...');
|
|
26
|
+
const config = new CLIConfig();
|
|
27
|
+
await client.connect({ useRemote: !!config.get('token') });
|
|
28
|
+
}
|
|
29
|
+
const bulkArgs = { operation: 'pause' };
|
|
30
|
+
if (options.category)
|
|
31
|
+
bulkArgs.category = options.category;
|
|
32
|
+
if (options.app)
|
|
33
|
+
bulkArgs.app_id = options.app;
|
|
34
|
+
if (options.before)
|
|
35
|
+
bulkArgs.before = options.before;
|
|
36
|
+
if (options.ids)
|
|
37
|
+
bulkArgs.memory_ids = options.ids.split(',').map((id) => id.trim());
|
|
38
|
+
if (options.dryRun) {
|
|
39
|
+
spinner.succeed('Dry run mode - showing affected memories');
|
|
40
|
+
console.log(chalk.yellow('This would pause memories matching the criteria'));
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const result = await client.callTool('memory_bulk_operations', bulkArgs);
|
|
44
|
+
spinner.succeed(`Bulk pause completed: ${result.result?.affected_count} memories paused`);
|
|
45
|
+
if (result.result?.results && result.result?.results.length > 0) {
|
|
46
|
+
console.log(chalk.cyan('\nš Operation Results:'));
|
|
47
|
+
const tableData = [
|
|
48
|
+
[chalk.bold('Memory ID'), chalk.bold('Status'), chalk.bold('Previous State')]
|
|
49
|
+
];
|
|
50
|
+
result.result?.results.forEach((r) => {
|
|
51
|
+
tableData.push([
|
|
52
|
+
r.memory_id.substring(0, 8) + '...',
|
|
53
|
+
r.success ? chalk.green('ā Paused') : chalk.red('ā Failed'),
|
|
54
|
+
r.previous_state
|
|
55
|
+
]);
|
|
56
|
+
});
|
|
57
|
+
console.log(table(tableData));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
spinner.fail(`Bulk pause failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
// Archive old memories
|
|
66
|
+
memory.command('archive')
|
|
67
|
+
.description('Archive memories older than specified date')
|
|
68
|
+
.requiredOption('--before <date>', 'Archive memories created before date (ISO format)')
|
|
69
|
+
.option('--app <app_id>', 'Archive memories from specific app')
|
|
70
|
+
.option('--dry-run', 'Show what would be archived without executing')
|
|
71
|
+
.action(async (options) => {
|
|
72
|
+
const spinner = ora('Processing archive operation...').start();
|
|
73
|
+
try {
|
|
74
|
+
const client = getMCPClient();
|
|
75
|
+
if (!client.isConnectedToServer()) {
|
|
76
|
+
spinner.info('Connecting to MCP server...');
|
|
77
|
+
const config = new CLIConfig();
|
|
78
|
+
await client.connect({ useRemote: !!config.get('token') });
|
|
79
|
+
}
|
|
80
|
+
const bulkArgs = {
|
|
81
|
+
operation: 'archive',
|
|
82
|
+
before: options.before
|
|
83
|
+
};
|
|
84
|
+
if (options.app)
|
|
85
|
+
bulkArgs.app_id = options.app;
|
|
86
|
+
if (options.dryRun) {
|
|
87
|
+
spinner.succeed('Dry run mode - showing memories to be archived');
|
|
88
|
+
console.log(chalk.yellow(`This would archive memories created before ${options.before}`));
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const result = await client.callTool('memory_bulk_operations', bulkArgs);
|
|
92
|
+
spinner.succeed(`Archive completed: ${result.result?.affected_count} memories archived`);
|
|
93
|
+
console.log(chalk.green(`\nā Successfully archived ${result.result?.affected_count} memories`));
|
|
94
|
+
console.log(chalk.cyan(` Archived memories created before: ${options.before}`));
|
|
95
|
+
if (options.app) {
|
|
96
|
+
console.log(chalk.cyan(` From app: ${options.app}`));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
spinner.fail(`Archive failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
// Find related memories
|
|
105
|
+
memory.command('related')
|
|
106
|
+
.description('Find memories related to a specific memory')
|
|
107
|
+
.argument('<memory_id>', 'Source memory ID')
|
|
108
|
+
.option('-l, --limit <number>', 'Maximum related memories to show', '5')
|
|
109
|
+
.option('-t, --threshold <number>', 'Similarity threshold (0-1)', '0.6')
|
|
110
|
+
.action(async (memoryId, options) => {
|
|
111
|
+
const spinner = ora('Finding related memories...').start();
|
|
112
|
+
try {
|
|
113
|
+
const client = getMCPClient();
|
|
114
|
+
if (!client.isConnectedToServer()) {
|
|
115
|
+
spinner.info('Connecting to MCP server...');
|
|
116
|
+
const config = new CLIConfig();
|
|
117
|
+
await client.connect({ useRemote: !!config.get('token') });
|
|
118
|
+
}
|
|
119
|
+
const result = await client.callTool('memory_find_related', {
|
|
120
|
+
memory_id: memoryId,
|
|
121
|
+
limit: parseInt(options.limit),
|
|
122
|
+
threshold: parseFloat(options.threshold)
|
|
123
|
+
});
|
|
124
|
+
spinner.succeed(`Found ${result.result?.count} related memories`);
|
|
125
|
+
if (result.result?.count === 0) {
|
|
126
|
+
console.log(chalk.yellow('\nNo related memories found'));
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
console.log(chalk.cyan('\nš Source Memory:'));
|
|
130
|
+
console.log(` ${chalk.bold(result.result?.source_memory.title)}`);
|
|
131
|
+
console.log(` ${result.result?.source_memory.content.substring(0, 100)}...`);
|
|
132
|
+
console.log(chalk.cyan('\nš Related Memories:'));
|
|
133
|
+
result.result?.related_memories.forEach((memory, index) => {
|
|
134
|
+
console.log(`\n${chalk.bold(`${index + 1}. ${memory.title}`)}`);
|
|
135
|
+
console.log(` ID: ${chalk.gray(memory.id)}`);
|
|
136
|
+
const similarity = memory.relevance_score ?? memory.score;
|
|
137
|
+
if (similarity !== undefined) {
|
|
138
|
+
console.log(` Similarity: ${chalk.green((similarity * 100).toFixed(1) + '%')}`);
|
|
139
|
+
}
|
|
140
|
+
const content = memory.content ?? memory.metadata?.content ?? '';
|
|
141
|
+
console.log(` Content: ${content
|
|
142
|
+
? `${content.substring(0, 80)}...`
|
|
143
|
+
: chalk.gray('[no preview]')}`);
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
spinner.fail(`Related search failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
148
|
+
process.exit(1);
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
// Advanced filtering
|
|
152
|
+
memory.command('filter')
|
|
153
|
+
.description('Filter memories with advanced criteria')
|
|
154
|
+
.option('--app-id <app_id>', 'Filter by application ID')
|
|
155
|
+
.option('--category <category>', 'Filter by category/tag')
|
|
156
|
+
.option('--since <date>', 'Filter memories since date (ISO format)')
|
|
157
|
+
.option('--before <date>', 'Filter memories before date (ISO format)')
|
|
158
|
+
.option('--state <state>', 'Filter by memory state (active, paused, archived)')
|
|
159
|
+
.option('--limit <number>', 'Maximum results', '20')
|
|
160
|
+
.action(async (options) => {
|
|
161
|
+
const spinner = ora('Filtering memories...').start();
|
|
162
|
+
try {
|
|
163
|
+
const client = getMCPClient();
|
|
164
|
+
if (!client.isConnectedToServer()) {
|
|
165
|
+
spinner.info('Connecting to MCP server...');
|
|
166
|
+
const config = new CLIConfig();
|
|
167
|
+
await client.connect({ useRemote: !!config.get('token') });
|
|
168
|
+
}
|
|
169
|
+
const searchArgs = {
|
|
170
|
+
query: '*', // Wildcard search
|
|
171
|
+
limit: parseInt(options.limit)
|
|
172
|
+
};
|
|
173
|
+
if (options.appId)
|
|
174
|
+
searchArgs.app_id = options.appId;
|
|
175
|
+
if (options.category)
|
|
176
|
+
searchArgs.category = options.category;
|
|
177
|
+
if (options.since)
|
|
178
|
+
searchArgs.since = options.since;
|
|
179
|
+
if (options.before)
|
|
180
|
+
searchArgs.before = options.before;
|
|
181
|
+
const result = await client.callTool('memory_search_memories', searchArgs);
|
|
182
|
+
spinner.succeed(`Found ${result.result?.total || result.result?.results.length} memories`);
|
|
183
|
+
if (result.result?.results.length === 0) {
|
|
184
|
+
console.log(chalk.yellow('\nNo memories match the filter criteria'));
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
console.log(chalk.cyan('\nš Filtered Memories:'));
|
|
188
|
+
const tableData = [
|
|
189
|
+
[chalk.bold('ID'), chalk.bold('Title'), chalk.bold('Type'), chalk.bold('Created')]
|
|
190
|
+
];
|
|
191
|
+
result.result?.results.forEach((memory) => {
|
|
192
|
+
tableData.push([
|
|
193
|
+
memory.id.substring(0, 8) + '...',
|
|
194
|
+
memory.title.substring(0, 30) + (memory.title.length > 30 ? '...' : ''),
|
|
195
|
+
memory.memory_type || 'context',
|
|
196
|
+
new Date(memory.created_at).toLocaleDateString()
|
|
197
|
+
]);
|
|
198
|
+
});
|
|
199
|
+
console.log(table(tableData));
|
|
200
|
+
// Show filter summary
|
|
201
|
+
console.log(chalk.cyan('\nš Filter Summary:'));
|
|
202
|
+
if (options.appId)
|
|
203
|
+
console.log(` App ID: ${options.appId}`);
|
|
204
|
+
if (options.category)
|
|
205
|
+
console.log(` Category: ${options.category}`);
|
|
206
|
+
if (options.since)
|
|
207
|
+
console.log(` Since: ${options.since}`);
|
|
208
|
+
if (options.before)
|
|
209
|
+
console.log(` Before: ${options.before}`);
|
|
210
|
+
if (options.state)
|
|
211
|
+
console.log(` State: ${options.state}`);
|
|
212
|
+
}
|
|
213
|
+
catch (error) {
|
|
214
|
+
spinner.fail(`Filter failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
215
|
+
process.exit(1);
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
// Memory analytics
|
|
219
|
+
memory.command('analytics')
|
|
220
|
+
.description('Show memory usage analytics and insights')
|
|
221
|
+
.option('--app <app_id>', 'Analytics for specific app')
|
|
222
|
+
.option('--period <days>', 'Analysis period in days', '30')
|
|
223
|
+
.action(async (options) => {
|
|
224
|
+
const spinner = ora('Generating memory analytics...').start();
|
|
225
|
+
try {
|
|
226
|
+
const client = getMCPClient();
|
|
227
|
+
if (!client.isConnectedToServer()) {
|
|
228
|
+
spinner.info('Connecting to MCP server...');
|
|
229
|
+
const config = new CLIConfig();
|
|
230
|
+
await client.connect({ useRemote: !!config.get('token') });
|
|
231
|
+
}
|
|
232
|
+
// Get all memories for analysis
|
|
233
|
+
const allMemories = await client.callTool('memory_search_memories', {
|
|
234
|
+
query: '*',
|
|
235
|
+
limit: 1000
|
|
236
|
+
});
|
|
237
|
+
spinner.succeed('Analytics generated');
|
|
238
|
+
const memories = allMemories.result?.results || [];
|
|
239
|
+
// Basic statistics
|
|
240
|
+
console.log(chalk.cyan('\nš Memory Analytics'));
|
|
241
|
+
console.log(chalk.cyan('=================='));
|
|
242
|
+
console.log(`Total Memories: ${chalk.bold(memories.length)}`);
|
|
243
|
+
// Memory types breakdown
|
|
244
|
+
const typeBreakdown = {};
|
|
245
|
+
memories.forEach((m) => {
|
|
246
|
+
const type = m.memory_type || 'context';
|
|
247
|
+
typeBreakdown[type] = (typeBreakdown[type] || 0) + 1;
|
|
248
|
+
});
|
|
249
|
+
console.log(chalk.cyan('\nš Memory Types:'));
|
|
250
|
+
Object.entries(typeBreakdown).forEach(([type, count]) => {
|
|
251
|
+
const percentage = ((count / memories.length) * 100).toFixed(1);
|
|
252
|
+
console.log(` ${type}: ${chalk.bold(count)} (${percentage}%)`);
|
|
253
|
+
});
|
|
254
|
+
// Recent activity
|
|
255
|
+
const now = new Date();
|
|
256
|
+
const periodDays = parseInt(options.period);
|
|
257
|
+
const cutoffDate = new Date(now.getTime() - (periodDays * 24 * 60 * 60 * 1000));
|
|
258
|
+
const recentMemories = memories.filter((m) => new Date(m.created_at) >= cutoffDate);
|
|
259
|
+
console.log(chalk.cyan(`\nš
Recent Activity (${periodDays} days):`));
|
|
260
|
+
console.log(` New memories: ${chalk.bold(recentMemories.length)}`);
|
|
261
|
+
console.log(` Daily average: ${chalk.bold((recentMemories.length / periodDays).toFixed(1))}`);
|
|
262
|
+
// App breakdown if not filtering by specific app
|
|
263
|
+
if (!options.app) {
|
|
264
|
+
const appBreakdown = {};
|
|
265
|
+
memories.forEach((m) => {
|
|
266
|
+
const app = m.app_id || 'default';
|
|
267
|
+
appBreakdown[app] = (appBreakdown[app] || 0) + 1;
|
|
268
|
+
});
|
|
269
|
+
console.log(chalk.cyan('\nš§ App Usage:'));
|
|
270
|
+
Object.entries(appBreakdown)
|
|
271
|
+
.sort(([, a], [, b]) => b - a)
|
|
272
|
+
.slice(0, 5)
|
|
273
|
+
.forEach(([app, count]) => {
|
|
274
|
+
const percentage = ((count / memories.length) * 100).toFixed(1);
|
|
275
|
+
console.log(` ${app}: ${chalk.bold(count)} (${percentage}%)`);
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
catch (error) {
|
|
280
|
+
spinner.fail(`Analytics failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
281
|
+
process.exit(1);
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
// Interactive memory management
|
|
285
|
+
memory.command('manage')
|
|
286
|
+
.description('Interactive memory management interface')
|
|
287
|
+
.action(async () => {
|
|
288
|
+
console.log(chalk.cyan('š§ Interactive Memory Management'));
|
|
289
|
+
console.log(chalk.cyan('================================'));
|
|
290
|
+
try {
|
|
291
|
+
const client = getMCPClient();
|
|
292
|
+
if (!client.isConnectedToServer()) {
|
|
293
|
+
const spinner = ora('Connecting to MCP server...').start();
|
|
294
|
+
const config = new CLIConfig();
|
|
295
|
+
await client.connect({ useRemote: !!config.get('token') });
|
|
296
|
+
spinner.succeed('Connected to MCP server');
|
|
297
|
+
}
|
|
298
|
+
while (true) {
|
|
299
|
+
const { action } = await inquirer.prompt([
|
|
300
|
+
{
|
|
301
|
+
type: 'list',
|
|
302
|
+
name: 'action',
|
|
303
|
+
message: 'What would you like to do?',
|
|
304
|
+
choices: [
|
|
305
|
+
{ name: 'š Search memories', value: 'search' },
|
|
306
|
+
{ name: 'š View analytics', value: 'analytics' },
|
|
307
|
+
{ name: 'š Find related memories', value: 'related' },
|
|
308
|
+
{ name: 'āøļø Bulk pause memories', value: 'bulk_pause' },
|
|
309
|
+
{ name: 'š¦ Archive old memories', value: 'archive' },
|
|
310
|
+
{ name: 'šŖ Exit', value: 'exit' }
|
|
311
|
+
]
|
|
312
|
+
}
|
|
313
|
+
]);
|
|
314
|
+
if (action === 'exit') {
|
|
315
|
+
console.log(chalk.green('š Goodbye!'));
|
|
316
|
+
break;
|
|
317
|
+
}
|
|
318
|
+
// Handle each action
|
|
319
|
+
switch (action) {
|
|
320
|
+
case 'search':
|
|
321
|
+
case 'search': {
|
|
322
|
+
const { query } = await inquirer.prompt([
|
|
323
|
+
{ type: 'input', name: 'query', message: 'Enter search query:' }
|
|
324
|
+
]);
|
|
325
|
+
if (query) {
|
|
326
|
+
const spinner = ora('Searching...').start();
|
|
327
|
+
const results = await client.callTool('memory_search_memories', { query });
|
|
328
|
+
spinner.succeed(`Found ${results.result?.results.length} memories`);
|
|
329
|
+
results.result?.results.slice(0, 5).forEach((m, i) => {
|
|
330
|
+
console.log(`\n${i + 1}. ${chalk.bold(m.title)}`);
|
|
331
|
+
console.log(` ${m.content.substring(0, 100)}...`);
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
break;
|
|
335
|
+
}
|
|
336
|
+
case 'analytics': {
|
|
337
|
+
console.log(chalk.cyan('š Generating analytics...'));
|
|
338
|
+
// Could call the analytics logic here
|
|
339
|
+
break;
|
|
340
|
+
}
|
|
341
|
+
case 'related': {
|
|
342
|
+
const { memoryId } = await inquirer.prompt([
|
|
343
|
+
{ type: 'input', name: 'memoryId', message: 'Enter memory ID:' }
|
|
344
|
+
]);
|
|
345
|
+
if (memoryId) {
|
|
346
|
+
const spinner = ora('Finding related memories...').start();
|
|
347
|
+
const related = await client.callTool('memory_find_related', { memory_id: memoryId });
|
|
348
|
+
spinner.succeed(`Found ${related.result?.count} related memories`);
|
|
349
|
+
related.result?.related_memories?.slice(0, 3).forEach((m, i) => {
|
|
350
|
+
console.log(`\n${i + 1}. ${chalk.bold(m.title)}`);
|
|
351
|
+
console.log(` Similarity: ${chalk.green((m.relevance_score * 100).toFixed(1) + '%')}`);
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
break;
|
|
355
|
+
}
|
|
356
|
+
case 'bulk_pause': {
|
|
357
|
+
const { pauseCriteria } = await inquirer.prompt([
|
|
358
|
+
{
|
|
359
|
+
type: 'list',
|
|
360
|
+
name: 'pauseCriteria',
|
|
361
|
+
message: 'Pause memories by:',
|
|
362
|
+
choices: [
|
|
363
|
+
{ name: 'Before specific date', value: 'date' },
|
|
364
|
+
{ name: 'By category', value: 'category' },
|
|
365
|
+
{ name: 'By app', value: 'app' }
|
|
366
|
+
]
|
|
367
|
+
}
|
|
368
|
+
]);
|
|
369
|
+
console.log(chalk.yellow(`Selected: ${pauseCriteria}`));
|
|
370
|
+
// Could implement the specific pause logic here
|
|
371
|
+
break;
|
|
372
|
+
}
|
|
373
|
+
case 'archive': {
|
|
374
|
+
const { archiveDate } = await inquirer.prompt([
|
|
375
|
+
{
|
|
376
|
+
type: 'input',
|
|
377
|
+
name: 'archiveDate',
|
|
378
|
+
message: 'Archive memories before date (YYYY-MM-DD):',
|
|
379
|
+
validate: (input) => {
|
|
380
|
+
const date = new Date(input);
|
|
381
|
+
return !isNaN(date.getTime()) || 'Please enter a valid date';
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
]);
|
|
385
|
+
if (archiveDate) {
|
|
386
|
+
const spinner = ora('Archiving memories...').start();
|
|
387
|
+
const result = await client.callTool('memory_bulk_operations', {
|
|
388
|
+
operation: 'archive',
|
|
389
|
+
before: archiveDate
|
|
390
|
+
});
|
|
391
|
+
spinner.succeed(`Archived ${result.result?.affected_count} memories`);
|
|
392
|
+
}
|
|
393
|
+
break;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
console.log(); // Add spacing
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
catch (error) {
|
|
400
|
+
console.error(chalk.red(`Management interface failed: ${error instanceof Error ? error.message : 'Unknown error'}`));
|
|
401
|
+
process.exit(1);
|
|
402
|
+
}
|
|
403
|
+
});
|
|
404
|
+
}
|
package/dist/commands/mcp.js
CHANGED
|
@@ -2,6 +2,7 @@ import chalk from 'chalk';
|
|
|
2
2
|
import ora from 'ora';
|
|
3
3
|
import { table } from 'table';
|
|
4
4
|
import { getMCPClient } from '../utils/mcp-client.js';
|
|
5
|
+
import { EnhancedMCPClient } from '../mcp/client/enhanced-client.js';
|
|
5
6
|
import { CLIConfig } from '../utils/config.js';
|
|
6
7
|
export function mcpCommands(program) {
|
|
7
8
|
const mcp = program
|
|
@@ -92,12 +93,32 @@ export function mcpCommands(program) {
|
|
|
92
93
|
config.set('mcpServerUrl', options.url);
|
|
93
94
|
}
|
|
94
95
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
96
|
+
let connected = false;
|
|
97
|
+
// Use Enhanced MCP Client for better connection handling
|
|
98
|
+
const enhancedClient = new EnhancedMCPClient();
|
|
99
|
+
if (options.url) {
|
|
100
|
+
// Connect to specific URL (WebSocket or remote)
|
|
101
|
+
const serverConfig = {
|
|
102
|
+
name: 'user-specified',
|
|
103
|
+
type: (options.url.startsWith('wss://') ? 'websocket' : 'stdio'),
|
|
104
|
+
url: options.url,
|
|
105
|
+
priority: 1
|
|
106
|
+
};
|
|
107
|
+
connected = await enhancedClient.connectSingle(serverConfig);
|
|
108
|
+
if (connected) {
|
|
109
|
+
spinner.succeed(chalk.green(`Connected to MCP server at ${options.url}`));
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
// Fall back to old client for local connections
|
|
115
|
+
const client = getMCPClient();
|
|
116
|
+
connected = await client.connect({
|
|
117
|
+
connectionMode,
|
|
118
|
+
serverPath: options.server,
|
|
119
|
+
serverUrl: options.url
|
|
120
|
+
});
|
|
121
|
+
}
|
|
101
122
|
if (connected) {
|
|
102
123
|
spinner.succeed(chalk.green(`Connected to MCP server in ${connectionMode} mode`));
|
|
103
124
|
if (connectionMode === 'remote') {
|
package/dist/index.js
CHANGED
|
File without changes
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Access Control System
|
|
3
|
+
* Implements granular permissions and audit logging inspired by mem0's ACL system
|
|
4
|
+
*/
|
|
5
|
+
export interface AccessControlRule {
|
|
6
|
+
id: string;
|
|
7
|
+
user_id: string;
|
|
8
|
+
app_id: string;
|
|
9
|
+
memory_id?: string;
|
|
10
|
+
permission: 'read' | 'write' | 'delete' | 'admin';
|
|
11
|
+
granted: boolean;
|
|
12
|
+
created_at: string;
|
|
13
|
+
expires_at?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface AccessLog {
|
|
16
|
+
id: string;
|
|
17
|
+
user_id: string;
|
|
18
|
+
app_id: string;
|
|
19
|
+
memory_id: string;
|
|
20
|
+
access_type: string;
|
|
21
|
+
timestamp: string;
|
|
22
|
+
success: boolean;
|
|
23
|
+
metadata?: Record<string, any>;
|
|
24
|
+
}
|
|
25
|
+
export declare class MemoryAccessControl {
|
|
26
|
+
private config;
|
|
27
|
+
private accessRules;
|
|
28
|
+
private accessLogs;
|
|
29
|
+
constructor();
|
|
30
|
+
/**
|
|
31
|
+
* Check if user has access to create memories in an app
|
|
32
|
+
*/
|
|
33
|
+
checkCreateAccess(userId: string, appId: string): Promise<boolean>;
|
|
34
|
+
/**
|
|
35
|
+
* Check if user has access to read a specific memory
|
|
36
|
+
*/
|
|
37
|
+
checkMemoryAccess(memoryId: string, appId: string): Promise<boolean>;
|
|
38
|
+
/**
|
|
39
|
+
* Get all memories accessible to a user in an app
|
|
40
|
+
*/
|
|
41
|
+
getAccessibleMemories(userId: string, appId: string): Promise<string[]>;
|
|
42
|
+
/**
|
|
43
|
+
* Log memory access for audit purposes
|
|
44
|
+
*/
|
|
45
|
+
logMemoryAccess(memoryId: string, appId: string, accessType: string, metadata?: Record<string, any>): Promise<void>;
|
|
46
|
+
/**
|
|
47
|
+
* Grant access to a memory or app
|
|
48
|
+
*/
|
|
49
|
+
grantAccess(userId: string, appId: string, permission: 'read' | 'write' | 'delete' | 'admin', memoryId?: string, expiresAt?: string): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Revoke access to a memory or app
|
|
52
|
+
*/
|
|
53
|
+
revokeAccess(userId: string, appId: string, memoryId?: string): Promise<void>;
|
|
54
|
+
/**
|
|
55
|
+
* Get access logs for audit purposes
|
|
56
|
+
*/
|
|
57
|
+
getAccessLogs(userId?: string, appId?: string, memoryId?: string, limit?: number): AccessLog[];
|
|
58
|
+
/**
|
|
59
|
+
* Private helper methods
|
|
60
|
+
*/
|
|
61
|
+
private getAccessRules;
|
|
62
|
+
private isUserApp;
|
|
63
|
+
private getCurrentUserId;
|
|
64
|
+
private getMemoryInfo;
|
|
65
|
+
private getUserMemories;
|
|
66
|
+
private getSharedMemories;
|
|
67
|
+
private generateId;
|
|
68
|
+
}
|