@soulcraft/brainy 3.19.0 → 3.19.1
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/CHANGELOG.md +2 -0
- package/bin/brainy.js +9 -2335
- package/dist/api/DataAPI.d.ts +1 -1
- package/dist/augmentations/cacheAugmentation.d.ts +1 -1
- package/dist/augmentations/metricsAugmentation.d.ts +20 -20
- package/dist/brainy.d.ts +1 -1
- package/dist/brainyData.js +1 -2
- package/dist/cli/catalog.js +8 -12
- package/dist/cli/commands/conversation.d.ts +22 -0
- package/dist/cli/commands/conversation.js +528 -0
- package/dist/cli/commands/core.js +61 -17
- package/dist/cli/commands/neural.js +4 -5
- package/dist/cli/commands/types.d.ts +30 -0
- package/dist/cli/commands/types.js +194 -0
- package/dist/cli/commands/utility.js +2 -3
- package/dist/cli/index.js +44 -2
- package/dist/cli/interactive.d.ts +3 -3
- package/dist/cli/interactive.js +5 -5
- package/dist/hnsw/hnswIndexOptimized.d.ts +1 -1
- package/dist/mcp/brainyMCPBroadcast.d.ts +2 -2
- package/dist/mcp/brainyMCPBroadcast.js +1 -1
- package/dist/mcp/brainyMCPClient.js +8 -4
- package/dist/neural/types.d.ts +2 -2
- package/dist/streaming/pipeline.d.ts +1 -1
- package/dist/universal/fs.d.ts +24 -66
- package/package.json +2 -2
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 💬 Conversation CLI Commands
|
|
3
|
+
*
|
|
4
|
+
* CLI interface for infinite agent memory and conversation management
|
|
5
|
+
*/
|
|
6
|
+
import inquirer from 'inquirer';
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import ora from 'ora';
|
|
9
|
+
import * as fs from '../../universal/fs.js';
|
|
10
|
+
import * as path from '../../universal/path.js';
|
|
11
|
+
import { Brainy } from '../../brainy.js';
|
|
12
|
+
export const conversationCommand = {
|
|
13
|
+
command: 'conversation [action]',
|
|
14
|
+
describe: '💬 Conversation and context management',
|
|
15
|
+
builder: (yargs) => {
|
|
16
|
+
return yargs
|
|
17
|
+
.positional('action', {
|
|
18
|
+
describe: 'Conversation operation to perform',
|
|
19
|
+
type: 'string',
|
|
20
|
+
choices: ['setup', 'remove', 'search', 'context', 'thread', 'stats', 'export', 'import']
|
|
21
|
+
})
|
|
22
|
+
.option('conversation-id', {
|
|
23
|
+
describe: 'Conversation ID',
|
|
24
|
+
type: 'string',
|
|
25
|
+
alias: 'c'
|
|
26
|
+
})
|
|
27
|
+
.option('query', {
|
|
28
|
+
describe: 'Search query or context query',
|
|
29
|
+
type: 'string',
|
|
30
|
+
alias: 'q'
|
|
31
|
+
})
|
|
32
|
+
.option('role', {
|
|
33
|
+
describe: 'Filter by message role',
|
|
34
|
+
type: 'string',
|
|
35
|
+
choices: ['user', 'assistant', 'system', 'tool'],
|
|
36
|
+
alias: 'r'
|
|
37
|
+
})
|
|
38
|
+
.option('limit', {
|
|
39
|
+
describe: 'Maximum results',
|
|
40
|
+
type: 'number',
|
|
41
|
+
default: 10,
|
|
42
|
+
alias: 'l'
|
|
43
|
+
})
|
|
44
|
+
.option('format', {
|
|
45
|
+
describe: 'Output format',
|
|
46
|
+
type: 'string',
|
|
47
|
+
choices: ['json', 'table', 'text'],
|
|
48
|
+
default: 'table',
|
|
49
|
+
alias: 'f'
|
|
50
|
+
})
|
|
51
|
+
.option('output', {
|
|
52
|
+
describe: 'Output file path',
|
|
53
|
+
type: 'string',
|
|
54
|
+
alias: 'o'
|
|
55
|
+
})
|
|
56
|
+
.example('$0 conversation setup', 'Set up MCP server for Claude Code')
|
|
57
|
+
.example('$0 conversation search -q "authentication" -l 5', 'Search messages')
|
|
58
|
+
.example('$0 conversation context -q "how to implement JWT"', 'Get relevant context')
|
|
59
|
+
.example('$0 conversation thread -c conv_123', 'Get conversation thread')
|
|
60
|
+
.example('$0 conversation stats', 'Show conversation statistics');
|
|
61
|
+
},
|
|
62
|
+
handler: async (argv) => {
|
|
63
|
+
const action = argv.action || 'setup';
|
|
64
|
+
try {
|
|
65
|
+
switch (action) {
|
|
66
|
+
case 'setup':
|
|
67
|
+
await handleSetup(argv);
|
|
68
|
+
break;
|
|
69
|
+
case 'remove':
|
|
70
|
+
await handleRemove(argv);
|
|
71
|
+
break;
|
|
72
|
+
case 'search':
|
|
73
|
+
await handleSearch(argv);
|
|
74
|
+
break;
|
|
75
|
+
case 'context':
|
|
76
|
+
await handleContext(argv);
|
|
77
|
+
break;
|
|
78
|
+
case 'thread':
|
|
79
|
+
await handleThread(argv);
|
|
80
|
+
break;
|
|
81
|
+
case 'stats':
|
|
82
|
+
await handleStats(argv);
|
|
83
|
+
break;
|
|
84
|
+
case 'export':
|
|
85
|
+
await handleExport(argv);
|
|
86
|
+
break;
|
|
87
|
+
case 'import':
|
|
88
|
+
await handleImport(argv);
|
|
89
|
+
break;
|
|
90
|
+
default:
|
|
91
|
+
console.log(chalk.yellow(`Unknown action: ${action}`));
|
|
92
|
+
console.log('Run "brainy conversation --help" for usage information');
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
console.error(chalk.red(`Error: ${error.message}`));
|
|
97
|
+
process.exit(1);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* Handle setup command - Set up MCP server for Claude Code
|
|
103
|
+
*/
|
|
104
|
+
async function handleSetup(argv) {
|
|
105
|
+
console.log(chalk.bold.cyan('\n🧠 Brainy Infinite Memory Setup\n'));
|
|
106
|
+
// Check for existing setup
|
|
107
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE || '~';
|
|
108
|
+
const brainyDir = path.join(homeDir, '.brainy-memory');
|
|
109
|
+
const dataDir = path.join(brainyDir, 'data');
|
|
110
|
+
const serverPath = path.join(brainyDir, 'mcp-server.js');
|
|
111
|
+
const configPath = path.join(homeDir, '.config', 'claude-code', 'mcp-servers.json');
|
|
112
|
+
// Check if already set up
|
|
113
|
+
if (await fs.exists(brainyDir)) {
|
|
114
|
+
const { overwrite } = await inquirer.prompt([
|
|
115
|
+
{
|
|
116
|
+
type: 'confirm',
|
|
117
|
+
name: 'overwrite',
|
|
118
|
+
message: 'Brainy memory setup already exists. Overwrite?',
|
|
119
|
+
default: false
|
|
120
|
+
}
|
|
121
|
+
]);
|
|
122
|
+
if (!overwrite) {
|
|
123
|
+
console.log(chalk.yellow('Setup cancelled'));
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
const spinner = ora('Creating Brainy memory directory...').start();
|
|
128
|
+
try {
|
|
129
|
+
// Create directories
|
|
130
|
+
await fs.mkdir(brainyDir, { recursive: true });
|
|
131
|
+
await fs.mkdir(dataDir, { recursive: true });
|
|
132
|
+
spinner.succeed('Created Brainy memory directory');
|
|
133
|
+
// Create MCP server script
|
|
134
|
+
spinner.start('Creating MCP server script...');
|
|
135
|
+
const serverScript = `#!/usr/bin/env node
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Brainy Infinite Memory MCP Server
|
|
139
|
+
*
|
|
140
|
+
* This server provides conversation and context management
|
|
141
|
+
* for Claude Code through the Model Control Protocol (MCP).
|
|
142
|
+
*/
|
|
143
|
+
|
|
144
|
+
import { Brainy } from '@soulcraft/brainy'
|
|
145
|
+
import { BrainyMCPService } from '@soulcraft/brainy'
|
|
146
|
+
import { MCPConversationToolset } from '@soulcraft/brainy'
|
|
147
|
+
|
|
148
|
+
async function main() {
|
|
149
|
+
try {
|
|
150
|
+
// Initialize Brainy with filesystem storage
|
|
151
|
+
const brain = new Brainy({
|
|
152
|
+
storage: {
|
|
153
|
+
type: 'filesystem',
|
|
154
|
+
path: '${dataDir.replace(/\\/g, '/')}'
|
|
155
|
+
},
|
|
156
|
+
silent: true // Suppress console output
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
await brain.init()
|
|
160
|
+
|
|
161
|
+
// Create MCP service
|
|
162
|
+
const mcpService = new BrainyMCPService(brain, {
|
|
163
|
+
enableAuth: false // Local usage, no auth needed
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
// Create conversation toolset
|
|
167
|
+
const conversationTools = new MCPConversationToolset(brain)
|
|
168
|
+
await conversationTools.init()
|
|
169
|
+
|
|
170
|
+
// Register conversation tools
|
|
171
|
+
const tools = await conversationTools.getAvailableTools()
|
|
172
|
+
|
|
173
|
+
console.error('🧠 Brainy Memory Server started')
|
|
174
|
+
console.error(\`📊 \${tools.length} conversation tools available\`)
|
|
175
|
+
console.error('✅ Ready for Claude Code integration')
|
|
176
|
+
|
|
177
|
+
// Handle MCP requests via stdio
|
|
178
|
+
process.stdin.on('data', async (data) => {
|
|
179
|
+
try {
|
|
180
|
+
const request = JSON.parse(data.toString())
|
|
181
|
+
|
|
182
|
+
// Route conversation tool requests
|
|
183
|
+
let response
|
|
184
|
+
if (request.toolName && request.toolName.startsWith('conversation_')) {
|
|
185
|
+
response = await conversationTools.handleRequest(request)
|
|
186
|
+
} else {
|
|
187
|
+
response = await mcpService.handleRequest(request)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Write response to stdout
|
|
191
|
+
process.stdout.write(JSON.stringify(response) + '\\n')
|
|
192
|
+
} catch (error) {
|
|
193
|
+
console.error('Error handling request:', error)
|
|
194
|
+
}
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
// Handle shutdown gracefully
|
|
198
|
+
process.on('SIGINT', () => {
|
|
199
|
+
console.error('\\n🛑 Shutting down Brainy Memory Server')
|
|
200
|
+
process.exit(0)
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
} catch (error) {
|
|
204
|
+
console.error('Failed to start Brainy Memory Server:', error)
|
|
205
|
+
process.exit(1)
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
main()
|
|
210
|
+
`;
|
|
211
|
+
await fs.writeFile(serverPath, serverScript, 'utf8');
|
|
212
|
+
// Make executable on Unix systems
|
|
213
|
+
try {
|
|
214
|
+
await import('fs').then(fsModule => {
|
|
215
|
+
fsModule.promises.chmod(serverPath, 0o755).catch(() => { });
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
catch {
|
|
219
|
+
// Windows doesn't need chmod
|
|
220
|
+
}
|
|
221
|
+
spinner.succeed('Created MCP server script');
|
|
222
|
+
// Create Claude Code config
|
|
223
|
+
spinner.start('Configuring Claude Code...');
|
|
224
|
+
const configDir = path.dirname(configPath);
|
|
225
|
+
await fs.mkdir(configDir, { recursive: true });
|
|
226
|
+
let mcpConfig = {};
|
|
227
|
+
if (await fs.exists(configPath)) {
|
|
228
|
+
const existingConfig = await fs.readFile(configPath, 'utf8');
|
|
229
|
+
mcpConfig = JSON.parse(existingConfig);
|
|
230
|
+
}
|
|
231
|
+
mcpConfig['brainy-memory'] = {
|
|
232
|
+
command: 'node',
|
|
233
|
+
args: [serverPath],
|
|
234
|
+
env: {
|
|
235
|
+
NODE_ENV: 'production'
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
await fs.writeFile(configPath, JSON.stringify(mcpConfig, null, 2), 'utf8');
|
|
239
|
+
spinner.succeed('Configured Claude Code');
|
|
240
|
+
// Initialize Brainy database
|
|
241
|
+
spinner.start('Initializing Brainy database...');
|
|
242
|
+
const brain = new Brainy({
|
|
243
|
+
storage: {
|
|
244
|
+
type: 'filesystem',
|
|
245
|
+
options: {
|
|
246
|
+
path: dataDir
|
|
247
|
+
}
|
|
248
|
+
},
|
|
249
|
+
silent: true
|
|
250
|
+
});
|
|
251
|
+
await brain.init();
|
|
252
|
+
spinner.succeed('Initialized Brainy database');
|
|
253
|
+
// Success!
|
|
254
|
+
console.log(chalk.bold.green('\n✅ Setup complete!\n'));
|
|
255
|
+
console.log(chalk.cyan('📁 Memory storage:'), brainyDir);
|
|
256
|
+
console.log(chalk.cyan('🔧 MCP server:'), serverPath);
|
|
257
|
+
console.log(chalk.cyan('⚙️ Claude Code config:'), configPath);
|
|
258
|
+
console.log();
|
|
259
|
+
console.log(chalk.bold('🚀 Next steps:'));
|
|
260
|
+
console.log(' 1. Restart Claude Code to load the MCP server');
|
|
261
|
+
console.log(' 2. Start a new conversation - your history will be saved automatically!');
|
|
262
|
+
console.log(' 3. Claude will use past context to help you work faster');
|
|
263
|
+
console.log();
|
|
264
|
+
console.log(chalk.dim('Run "brainy conversation stats" to see your conversation statistics'));
|
|
265
|
+
}
|
|
266
|
+
catch (error) {
|
|
267
|
+
spinner.fail('Setup failed');
|
|
268
|
+
throw error;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Handle remove command - Remove MCP server and optionally data
|
|
273
|
+
*/
|
|
274
|
+
async function handleRemove(argv) {
|
|
275
|
+
console.log(chalk.bold.cyan('\n🗑️ Brainy Infinite Memory Removal\n'));
|
|
276
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE || '~';
|
|
277
|
+
const brainyDir = path.join(homeDir, '.brainy-memory');
|
|
278
|
+
const configPath = path.join(homeDir, '.config', 'claude-code', 'mcp-servers.json');
|
|
279
|
+
// Check if setup exists
|
|
280
|
+
const brainyExists = await fs.exists(brainyDir);
|
|
281
|
+
const configExists = await fs.exists(configPath);
|
|
282
|
+
if (!brainyExists && !configExists) {
|
|
283
|
+
console.log(chalk.yellow('No Brainy memory setup found. Nothing to remove.'));
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
// Show what will be removed
|
|
287
|
+
console.log(chalk.white('The following will be removed:'));
|
|
288
|
+
if (brainyExists) {
|
|
289
|
+
console.log(chalk.dim(` • ${brainyDir} (memory data and MCP server)`));
|
|
290
|
+
}
|
|
291
|
+
if (configExists) {
|
|
292
|
+
console.log(chalk.dim(` • MCP config entry in ${configPath}`));
|
|
293
|
+
}
|
|
294
|
+
console.log();
|
|
295
|
+
// Confirm removal
|
|
296
|
+
const { confirm } = await inquirer.prompt([
|
|
297
|
+
{
|
|
298
|
+
type: 'confirm',
|
|
299
|
+
name: 'confirm',
|
|
300
|
+
message: 'Are you sure you want to remove Brainy infinite memory?',
|
|
301
|
+
default: false
|
|
302
|
+
}
|
|
303
|
+
]);
|
|
304
|
+
if (!confirm) {
|
|
305
|
+
console.log(chalk.yellow('Removal cancelled'));
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
const spinner = ora('Removing Brainy memory setup...').start();
|
|
309
|
+
try {
|
|
310
|
+
// Remove Brainy directory
|
|
311
|
+
if (brainyExists) {
|
|
312
|
+
// Use Node.js fs for rm operation as universal fs doesn't have it
|
|
313
|
+
const nodefs = await import('fs');
|
|
314
|
+
await nodefs.promises.rm(brainyDir, { recursive: true, force: true });
|
|
315
|
+
spinner.text = 'Removed memory directory...';
|
|
316
|
+
}
|
|
317
|
+
// Remove MCP config entry
|
|
318
|
+
if (configExists) {
|
|
319
|
+
try {
|
|
320
|
+
const configContent = await fs.readFile(configPath, 'utf8');
|
|
321
|
+
const mcpConfig = JSON.parse(configContent);
|
|
322
|
+
if (mcpConfig['brainy-memory']) {
|
|
323
|
+
delete mcpConfig['brainy-memory'];
|
|
324
|
+
await fs.writeFile(configPath, JSON.stringify(mcpConfig, null, 2), 'utf8');
|
|
325
|
+
spinner.text = 'Removed MCP configuration...';
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
catch (error) {
|
|
329
|
+
// If config file is corrupted or empty, skip
|
|
330
|
+
spinner.warn('Could not update MCP config file');
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
spinner.succeed('Successfully removed Brainy infinite memory');
|
|
334
|
+
console.log();
|
|
335
|
+
console.log(chalk.bold('✅ Cleanup complete'));
|
|
336
|
+
console.log();
|
|
337
|
+
console.log(chalk.white('All conversation data and MCP configuration have been removed.'));
|
|
338
|
+
console.log(chalk.dim('Run "brainy conversation setup" to set up again.'));
|
|
339
|
+
console.log();
|
|
340
|
+
}
|
|
341
|
+
catch (error) {
|
|
342
|
+
spinner.fail('Removal failed');
|
|
343
|
+
console.error(chalk.red('Error:'), error.message);
|
|
344
|
+
throw error;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Handle search command - Search messages
|
|
349
|
+
*/
|
|
350
|
+
async function handleSearch(argv) {
|
|
351
|
+
if (!argv.query) {
|
|
352
|
+
console.log(chalk.yellow('Query required. Use -q or --query'));
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
const spinner = ora('Searching conversations...').start();
|
|
356
|
+
const brain = new Brainy();
|
|
357
|
+
await brain.init();
|
|
358
|
+
const conv = brain.conversation();
|
|
359
|
+
await conv.init();
|
|
360
|
+
const results = await conv.searchMessages({
|
|
361
|
+
query: argv.query,
|
|
362
|
+
limit: argv.limit || 10,
|
|
363
|
+
role: argv.role,
|
|
364
|
+
includeContent: true,
|
|
365
|
+
includeMetadata: true
|
|
366
|
+
});
|
|
367
|
+
spinner.succeed(`Found ${results.length} messages`);
|
|
368
|
+
if (results.length === 0) {
|
|
369
|
+
console.log(chalk.yellow('No messages found'));
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
// Display results
|
|
373
|
+
console.log();
|
|
374
|
+
for (const result of results) {
|
|
375
|
+
console.log(chalk.bold.cyan(`${result.message.role}:`), result.snippet);
|
|
376
|
+
console.log(chalk.dim(` Score: ${result.score.toFixed(3)} | Conv: ${result.conversationId}`));
|
|
377
|
+
console.log();
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Handle context command - Get relevant context
|
|
382
|
+
*/
|
|
383
|
+
async function handleContext(argv) {
|
|
384
|
+
if (!argv.query) {
|
|
385
|
+
console.log(chalk.yellow('Query required. Use -q or --query'));
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
const spinner = ora('Retrieving relevant context...').start();
|
|
389
|
+
const brain = new Brainy();
|
|
390
|
+
await brain.init();
|
|
391
|
+
const conv = brain.conversation();
|
|
392
|
+
await conv.init();
|
|
393
|
+
const context = await conv.getRelevantContext(argv.query, {
|
|
394
|
+
limit: argv.limit || 10,
|
|
395
|
+
includeArtifacts: true,
|
|
396
|
+
includeSimilarConversations: true
|
|
397
|
+
});
|
|
398
|
+
spinner.succeed(`Retrieved ${context.messages.length} relevant messages`);
|
|
399
|
+
if (context.messages.length === 0) {
|
|
400
|
+
console.log(chalk.yellow('No relevant context found'));
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
// Display context
|
|
404
|
+
console.log();
|
|
405
|
+
console.log(chalk.bold('📊 Context Statistics:'));
|
|
406
|
+
console.log(chalk.dim(` Messages: ${context.messages.length}`));
|
|
407
|
+
console.log(chalk.dim(` Tokens: ${context.totalTokens}`));
|
|
408
|
+
console.log(chalk.dim(` Query time: ${context.metadata.queryTime}ms`));
|
|
409
|
+
console.log();
|
|
410
|
+
console.log(chalk.bold('💬 Relevant Messages:'));
|
|
411
|
+
for (const msg of context.messages) {
|
|
412
|
+
console.log();
|
|
413
|
+
console.log(chalk.cyan(`${msg.role} (score: ${msg.relevanceScore.toFixed(3)}):`));
|
|
414
|
+
console.log(msg.content.substring(0, 200) + (msg.content.length > 200 ? '...' : ''));
|
|
415
|
+
}
|
|
416
|
+
if (context.similarConversations && context.similarConversations.length > 0) {
|
|
417
|
+
console.log();
|
|
418
|
+
console.log(chalk.bold('🔗 Similar Conversations:'));
|
|
419
|
+
for (const conv of context.similarConversations) {
|
|
420
|
+
console.log(chalk.dim(` - ${conv.title || conv.id} (${conv.relevance.toFixed(2)})`));
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Handle thread command - Get conversation thread
|
|
426
|
+
*/
|
|
427
|
+
async function handleThread(argv) {
|
|
428
|
+
if (!argv.conversationId) {
|
|
429
|
+
console.log(chalk.yellow('Conversation ID required. Use -c or --conversation-id'));
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
const spinner = ora('Loading conversation thread...').start();
|
|
433
|
+
const brain = new Brainy();
|
|
434
|
+
await brain.init();
|
|
435
|
+
const conv = brain.conversation();
|
|
436
|
+
await conv.init();
|
|
437
|
+
const thread = await conv.getConversationThread(argv.conversationId, {
|
|
438
|
+
includeArtifacts: true
|
|
439
|
+
});
|
|
440
|
+
spinner.succeed(`Loaded ${thread.messages.length} messages`);
|
|
441
|
+
// Display thread
|
|
442
|
+
console.log();
|
|
443
|
+
console.log(chalk.bold('📊 Thread Information:'));
|
|
444
|
+
console.log(chalk.dim(` Conversation: ${thread.id}`));
|
|
445
|
+
console.log(chalk.dim(` Messages: ${thread.metadata.messageCount}`));
|
|
446
|
+
console.log(chalk.dim(` Tokens: ${thread.metadata.totalTokens}`));
|
|
447
|
+
console.log(chalk.dim(` Started: ${new Date(thread.metadata.startTime).toLocaleString()}`));
|
|
448
|
+
console.log();
|
|
449
|
+
console.log(chalk.bold('💬 Messages:'));
|
|
450
|
+
for (const msg of thread.messages) {
|
|
451
|
+
console.log();
|
|
452
|
+
console.log(chalk.cyan(`${msg.role}:`), msg.content);
|
|
453
|
+
console.log(chalk.dim(` ${new Date(msg.createdAt).toLocaleString()}`));
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Handle stats command - Show statistics
|
|
458
|
+
*/
|
|
459
|
+
async function handleStats(argv) {
|
|
460
|
+
const spinner = ora('Calculating statistics...').start();
|
|
461
|
+
const brain = new Brainy();
|
|
462
|
+
await brain.init();
|
|
463
|
+
const conv = brain.conversation();
|
|
464
|
+
await conv.init();
|
|
465
|
+
const stats = await conv.getConversationStats();
|
|
466
|
+
spinner.succeed('Statistics calculated');
|
|
467
|
+
// Display stats
|
|
468
|
+
console.log();
|
|
469
|
+
console.log(chalk.bold.cyan('📊 Conversation Statistics\n'));
|
|
470
|
+
console.log(chalk.bold('Overall:'));
|
|
471
|
+
console.log(chalk.dim(` Conversations: ${stats.totalConversations}`));
|
|
472
|
+
console.log(chalk.dim(` Messages: ${stats.totalMessages}`));
|
|
473
|
+
console.log(chalk.dim(` Total Tokens: ${stats.totalTokens.toLocaleString()}`));
|
|
474
|
+
console.log(chalk.dim(` Avg Messages/Conversation: ${stats.averageMessagesPerConversation.toFixed(1)}`));
|
|
475
|
+
console.log(chalk.dim(` Avg Tokens/Message: ${stats.averageTokensPerMessage.toFixed(1)}`));
|
|
476
|
+
console.log();
|
|
477
|
+
if (Object.keys(stats.roles).length > 0) {
|
|
478
|
+
console.log(chalk.bold('By Role:'));
|
|
479
|
+
for (const [role, count] of Object.entries(stats.roles)) {
|
|
480
|
+
console.log(chalk.dim(` ${role}: ${count}`));
|
|
481
|
+
}
|
|
482
|
+
console.log();
|
|
483
|
+
}
|
|
484
|
+
if (Object.keys(stats.phases).length > 0) {
|
|
485
|
+
console.log(chalk.bold('By Phase:'));
|
|
486
|
+
for (const [phase, count] of Object.entries(stats.phases)) {
|
|
487
|
+
console.log(chalk.dim(` ${phase}: ${count}`));
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Handle export command - Export conversation
|
|
493
|
+
*/
|
|
494
|
+
async function handleExport(argv) {
|
|
495
|
+
if (!argv.conversationId) {
|
|
496
|
+
console.log(chalk.yellow('Conversation ID required. Use -c or --conversation-id'));
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
const spinner = ora('Exporting conversation...').start();
|
|
500
|
+
const brain = new Brainy();
|
|
501
|
+
await brain.init();
|
|
502
|
+
const conv = brain.conversation();
|
|
503
|
+
await conv.init();
|
|
504
|
+
const exported = await conv.exportConversation(argv.conversationId);
|
|
505
|
+
const output = argv.output || `conversation_${argv.conversationId}.json`;
|
|
506
|
+
await fs.writeFile(output, JSON.stringify(exported, null, 2), 'utf8');
|
|
507
|
+
spinner.succeed(`Exported to ${output}`);
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* Handle import command - Import conversation
|
|
511
|
+
*/
|
|
512
|
+
async function handleImport(argv) {
|
|
513
|
+
const inputFile = argv.output;
|
|
514
|
+
if (!inputFile) {
|
|
515
|
+
console.log(chalk.yellow('Input file required. Use -o or --output'));
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
const spinner = ora('Importing conversation...').start();
|
|
519
|
+
const brain = new Brainy();
|
|
520
|
+
await brain.init();
|
|
521
|
+
const conv = brain.conversation();
|
|
522
|
+
await conv.init();
|
|
523
|
+
const data = JSON.parse(await fs.readFile(inputFile, 'utf8'));
|
|
524
|
+
const conversationId = await conv.importConversation(data);
|
|
525
|
+
spinner.succeed(`Imported as conversation ${conversationId}`);
|
|
526
|
+
}
|
|
527
|
+
export default conversationCommand;
|
|
528
|
+
//# sourceMappingURL=conversation.js.map
|
|
@@ -5,12 +5,13 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import chalk from 'chalk';
|
|
7
7
|
import ora from 'ora';
|
|
8
|
-
import { readFileSync, writeFileSync } from 'fs';
|
|
9
|
-
import {
|
|
8
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
9
|
+
import { Brainy } from '../../brainy.js';
|
|
10
|
+
import { BrainyTypes, NounType } from '../../index.js';
|
|
10
11
|
let brainyInstance = null;
|
|
11
12
|
const getBrainy = async () => {
|
|
12
13
|
if (!brainyInstance) {
|
|
13
|
-
brainyInstance = new
|
|
14
|
+
brainyInstance = new Brainy();
|
|
14
15
|
await brainyInstance.init();
|
|
15
16
|
}
|
|
16
17
|
return brainyInstance;
|
|
@@ -41,11 +42,36 @@ export const coreCommands = {
|
|
|
41
42
|
if (options.id) {
|
|
42
43
|
metadata.id = options.id;
|
|
43
44
|
}
|
|
45
|
+
// Determine noun type
|
|
46
|
+
let nounType;
|
|
44
47
|
if (options.type) {
|
|
45
|
-
|
|
48
|
+
// Validate provided type
|
|
49
|
+
if (!BrainyTypes.isValidNoun(options.type)) {
|
|
50
|
+
spinner.fail(`Invalid noun type: ${options.type}`);
|
|
51
|
+
console.log(chalk.dim('Run "brainy types --noun" to see valid types'));
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
nounType = options.type;
|
|
46
55
|
}
|
|
47
|
-
|
|
48
|
-
|
|
56
|
+
else {
|
|
57
|
+
// Use AI to suggest type
|
|
58
|
+
spinner.text = 'Detecting type with AI...';
|
|
59
|
+
const suggestion = await BrainyTypes.suggestNoun(typeof text === 'string' ? { content: text, ...metadata } : text);
|
|
60
|
+
if (suggestion.confidence < 0.6) {
|
|
61
|
+
spinner.fail('Could not determine type with confidence');
|
|
62
|
+
console.log(chalk.yellow(`Suggestion: ${suggestion.type} (${(suggestion.confidence * 100).toFixed(1)}%)`));
|
|
63
|
+
console.log(chalk.dim('Use --type flag to specify explicitly'));
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
nounType = suggestion.type;
|
|
67
|
+
spinner.text = `Using detected type: ${nounType}`;
|
|
68
|
+
}
|
|
69
|
+
// Add with explicit type
|
|
70
|
+
const result = await brain.add({
|
|
71
|
+
data: text,
|
|
72
|
+
type: nounType,
|
|
73
|
+
metadata
|
|
74
|
+
});
|
|
49
75
|
spinner.succeed('Added successfully');
|
|
50
76
|
if (!options.json) {
|
|
51
77
|
console.log(chalk.green(`✓ Added with ID: ${result}`));
|
|
@@ -88,7 +114,7 @@ export const coreCommands = {
|
|
|
88
114
|
process.exit(1);
|
|
89
115
|
}
|
|
90
116
|
}
|
|
91
|
-
const results = await brain.search(query, searchOptions.limit
|
|
117
|
+
const results = await brain.search(query, searchOptions.limit);
|
|
92
118
|
spinner.succeed(`Found ${results.length} results`);
|
|
93
119
|
if (!options.json) {
|
|
94
120
|
if (results.length === 0) {
|
|
@@ -100,8 +126,8 @@ export const coreCommands = {
|
|
|
100
126
|
if (result.score !== undefined) {
|
|
101
127
|
console.log(chalk.dim(` Similarity: ${(result.score * 100).toFixed(1)}%`));
|
|
102
128
|
}
|
|
103
|
-
if (result.metadata) {
|
|
104
|
-
console.log(chalk.dim(` Metadata: ${JSON.stringify(result.metadata)}`));
|
|
129
|
+
if (result.entity && result.entity.metadata) {
|
|
130
|
+
console.log(chalk.dim(` Metadata: ${JSON.stringify(result.entity.metadata)}`));
|
|
105
131
|
}
|
|
106
132
|
});
|
|
107
133
|
}
|
|
@@ -136,8 +162,8 @@ export const coreCommands = {
|
|
|
136
162
|
console.log(chalk.cyan('\nItem Details:'));
|
|
137
163
|
console.log(` ID: ${item.id}`);
|
|
138
164
|
console.log(` Content: ${item.content || 'N/A'}`);
|
|
139
|
-
if (item.metadata) {
|
|
140
|
-
console.log(` Metadata: ${JSON.stringify(item.metadata, null, 2)}`);
|
|
165
|
+
if (item.entity && item.entity.metadata) {
|
|
166
|
+
console.log(` Metadata: ${JSON.stringify(item.entity.metadata, null, 2)}`);
|
|
141
167
|
}
|
|
142
168
|
if (options.withConnections) {
|
|
143
169
|
// Get verbs/relationships
|
|
@@ -182,7 +208,12 @@ export const coreCommands = {
|
|
|
182
208
|
metadata.weight = parseFloat(options.weight);
|
|
183
209
|
}
|
|
184
210
|
// Create the relationship
|
|
185
|
-
const result = await brain.
|
|
211
|
+
const result = await brain.relate({
|
|
212
|
+
from: source,
|
|
213
|
+
to: target,
|
|
214
|
+
type: verb,
|
|
215
|
+
metadata
|
|
216
|
+
});
|
|
186
217
|
spinner.succeed('Relationship created');
|
|
187
218
|
if (!options.json) {
|
|
188
219
|
console.log(chalk.green(`✓ Created relationship with ID: ${result}`));
|
|
@@ -245,15 +276,28 @@ export const coreCommands = {
|
|
|
245
276
|
for (let i = 0; i < items.length; i += batchSize) {
|
|
246
277
|
const batch = items.slice(i, i + batchSize);
|
|
247
278
|
for (const item of batch) {
|
|
279
|
+
let content;
|
|
280
|
+
let metadata = {};
|
|
248
281
|
if (typeof item === 'string') {
|
|
249
|
-
|
|
282
|
+
content = item;
|
|
250
283
|
}
|
|
251
284
|
else if (item.content || item.text) {
|
|
252
|
-
|
|
285
|
+
content = item.content || item.text;
|
|
286
|
+
metadata = item.metadata || item;
|
|
253
287
|
}
|
|
254
288
|
else {
|
|
255
|
-
|
|
289
|
+
content = JSON.stringify(item);
|
|
290
|
+
metadata = { originalData: item };
|
|
256
291
|
}
|
|
292
|
+
// Use AI to detect type for each item
|
|
293
|
+
const suggestion = await BrainyTypes.suggestNoun(typeof content === 'string' ? { content, ...metadata } : content);
|
|
294
|
+
// Use suggested type or default to Content if low confidence
|
|
295
|
+
const nounType = suggestion.confidence >= 0.5 ? suggestion.type : NounType.Content;
|
|
296
|
+
await brain.add({
|
|
297
|
+
data: content,
|
|
298
|
+
type: nounType,
|
|
299
|
+
metadata
|
|
300
|
+
});
|
|
257
301
|
imported++;
|
|
258
302
|
}
|
|
259
303
|
spinner.text = `Imported ${imported}/${items.length} items...`;
|
|
@@ -283,7 +327,8 @@ export const coreCommands = {
|
|
|
283
327
|
const brain = await getBrainy();
|
|
284
328
|
const format = options.format || 'json';
|
|
285
329
|
// Export all data
|
|
286
|
-
const
|
|
330
|
+
const dataApi = await brain.data();
|
|
331
|
+
const data = await dataApi.export({ format: 'json' });
|
|
287
332
|
let output = '';
|
|
288
333
|
switch (format) {
|
|
289
334
|
case 'json':
|
|
@@ -345,4 +390,3 @@ export const coreCommands = {
|
|
|
345
390
|
}
|
|
346
391
|
}
|
|
347
392
|
};
|
|
348
|
-
//# sourceMappingURL=core.js.map
|