@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
package/bin/brainy.js
CHANGED
|
@@ -1,2340 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Brainy CLI
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* - 5 commands total (was 40+)
|
|
9
|
-
* - Clear, obvious naming
|
|
10
|
-
* - Interactive mode for beginners
|
|
4
|
+
* Brainy CLI Wrapper
|
|
5
|
+
*
|
|
6
|
+
* Imports the compiled TypeScript CLI from dist/cli/index.js
|
|
7
|
+
* This ensures TypeScript features work correctly
|
|
11
8
|
*/
|
|
12
9
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
import { readFileSync } from 'fs'
|
|
19
|
-
import { dirname, join } from 'path'
|
|
20
|
-
import { fileURLToPath } from 'url'
|
|
21
|
-
import { createInterface } from 'readline'
|
|
22
|
-
// @ts-ignore
|
|
23
|
-
import Table from 'cli-table3'
|
|
24
|
-
|
|
25
|
-
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
26
|
-
const packageJson = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf8'))
|
|
27
|
-
|
|
28
|
-
// Create single BrainyData instance (the ONE data orchestrator)
|
|
29
|
-
let brainy = null
|
|
30
|
-
const getBrainy = async () => {
|
|
31
|
-
if (!brainy) {
|
|
32
|
-
brainy = new BrainyData()
|
|
33
|
-
await brainy.init()
|
|
34
|
-
}
|
|
35
|
-
return brainy
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Beautiful colors matching brainy.png logo
|
|
39
|
-
const colors = {
|
|
40
|
-
primary: chalk.hex('#3A5F4A'), // Teal container (from logo)
|
|
41
|
-
success: chalk.hex('#2D4A3A'), // Deep teal frame (from logo)
|
|
42
|
-
info: chalk.hex('#4A6B5A'), // Medium teal
|
|
43
|
-
warning: chalk.hex('#D67441'), // Orange (from logo)
|
|
44
|
-
error: chalk.hex('#B85C35'), // Deep orange
|
|
45
|
-
brain: chalk.hex('#D67441'), // Brain orange (from logo)
|
|
46
|
-
cream: chalk.hex('#F5E6A3'), // Cream background (from logo)
|
|
47
|
-
dim: chalk.dim,
|
|
48
|
-
blue: chalk.blue,
|
|
49
|
-
green: chalk.green,
|
|
50
|
-
yellow: chalk.yellow,
|
|
51
|
-
cyan: chalk.cyan
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Helper functions
|
|
55
|
-
const exitProcess = (code = 0) => {
|
|
56
|
-
setTimeout(() => process.exit(code), 100)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Initialize Brainy instance
|
|
60
|
-
const initBrainy = async () => {
|
|
61
|
-
return new BrainyData()
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Enhanced result formatting using display augmentation
|
|
66
|
-
* @param {any} result - The result object from search/get/find
|
|
67
|
-
* @param {number} index - Result index for numbering
|
|
68
|
-
* @returns {Promise<string>} Formatted result string
|
|
69
|
-
*/
|
|
70
|
-
const formatResultWithDisplay = async (result, index) => {
|
|
71
|
-
try {
|
|
72
|
-
// Check if result has display capabilities (enhanced by display augmentation)
|
|
73
|
-
if (result.getDisplay && typeof result.getDisplay === 'function') {
|
|
74
|
-
const displayFields = await result.getDisplay()
|
|
75
|
-
|
|
76
|
-
// Format with enhanced display fields (clean, no icons)
|
|
77
|
-
let output = colors.primary(`\n${index + 1}. ${displayFields.title}`)
|
|
78
|
-
|
|
79
|
-
if (displayFields.type) {
|
|
80
|
-
output += colors.dim(` (${displayFields.type})`)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (result.score) {
|
|
84
|
-
output += colors.info(`\n šÆ Relevance: ${(result.score * 100).toFixed(1)}%`)
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
if (result.fusionScore) {
|
|
88
|
-
output += colors.info(`\n š§ AI Score: ${(result.fusionScore * 100).toFixed(1)}%`)
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (displayFields.description && displayFields.description !== displayFields.title) {
|
|
92
|
-
output += colors.info(`\n š ${displayFields.description}`)
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (displayFields.tags && displayFields.tags.length > 0) {
|
|
96
|
-
output += colors.cyan(`\n š·ļø ${displayFields.tags.join(', ')}`)
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Show relationship info for verbs
|
|
100
|
-
if (displayFields.relationship) {
|
|
101
|
-
output += colors.yellow(`\n š ${displayFields.relationship}`)
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Show metadata only if there's additional useful info
|
|
105
|
-
if (result.metadata && Object.keys(result.metadata).length > 0) {
|
|
106
|
-
const filteredMetadata = Object.fromEntries(
|
|
107
|
-
Object.entries(result.metadata).filter(([key]) =>
|
|
108
|
-
!key.startsWith('_') && !['type', 'title', 'description', 'icon'].includes(key)
|
|
109
|
-
)
|
|
110
|
-
)
|
|
111
|
-
if (Object.keys(filteredMetadata).length > 0) {
|
|
112
|
-
output += colors.dim(`\n š ${JSON.stringify(filteredMetadata)}`)
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return output
|
|
117
|
-
}
|
|
118
|
-
} catch (error) {
|
|
119
|
-
// Fallback silently to basic formatting if display augmentation fails
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Fallback: Basic formatting without display augmentation
|
|
123
|
-
let output = colors.primary(`\n${index + 1}. ${result.content || result.id}`)
|
|
124
|
-
|
|
125
|
-
if (result.score) {
|
|
126
|
-
output += colors.info(`\n Relevance: ${(result.score * 100).toFixed(1)}%`)
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
if (result.fusionScore) {
|
|
130
|
-
output += colors.info(`\n AI Score: ${(result.fusionScore * 100).toFixed(1)}%`)
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
if (result.type) {
|
|
134
|
-
output += colors.info(`\n Type: ${result.type}`)
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
if (result.metadata && Object.keys(result.metadata).length > 0) {
|
|
138
|
-
output += colors.dim(`\n Metadata: ${JSON.stringify(result.metadata)}`)
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
return output
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Enhanced single item formatting for get command
|
|
146
|
-
* @param {any} item - The item object
|
|
147
|
-
* @param {string} format - Output format (json, table, plain)
|
|
148
|
-
* @returns {Promise<string>} Formatted item string
|
|
149
|
-
*/
|
|
150
|
-
const formatItemWithDisplay = async (item, format = 'plain') => {
|
|
151
|
-
if (format === 'json') {
|
|
152
|
-
return JSON.stringify(item, null, 2)
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
try {
|
|
156
|
-
// Check if item has display capabilities
|
|
157
|
-
if (item.getDisplay && typeof item.getDisplay === 'function') {
|
|
158
|
-
const displayFields = await item.getDisplay()
|
|
159
|
-
|
|
160
|
-
if (format === 'table') {
|
|
161
|
-
const table = new Table({
|
|
162
|
-
head: [colors.brain('Property'), colors.brain('Value')],
|
|
163
|
-
style: { head: [], border: [] }
|
|
164
|
-
})
|
|
165
|
-
|
|
166
|
-
table.push(['ID', colors.primary(item.id)])
|
|
167
|
-
table.push(['Title', colors.primary(displayFields.title)])
|
|
168
|
-
table.push(['Type', colors.info(displayFields.type)])
|
|
169
|
-
table.push(['Description', colors.info(displayFields.description)])
|
|
170
|
-
|
|
171
|
-
if (displayFields.tags && displayFields.tags.length > 0) {
|
|
172
|
-
table.push(['Tags', colors.cyan(displayFields.tags.join(', '))])
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
if (displayFields.relationship) {
|
|
176
|
-
table.push(['Relationship', colors.yellow(displayFields.relationship)])
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
if (item.content && item.content !== displayFields.title) {
|
|
180
|
-
table.push(['Content', colors.dim(item.content)])
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// Add non-internal metadata
|
|
184
|
-
if (item.metadata) {
|
|
185
|
-
Object.entries(item.metadata).forEach(([key, value]) => {
|
|
186
|
-
if (!key.startsWith('_') && !['type', 'title', 'description', 'icon'].includes(key)) {
|
|
187
|
-
table.push([key, colors.dim(JSON.stringify(value))])
|
|
188
|
-
}
|
|
189
|
-
})
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
return table.toString()
|
|
193
|
-
} else {
|
|
194
|
-
// Plain format with display enhancement
|
|
195
|
-
let output = colors.primary(`ID: ${item.id}`)
|
|
196
|
-
output += colors.primary(`\nTitle: ${displayFields.title}`)
|
|
197
|
-
output += colors.info(`\nType: ${displayFields.type}`)
|
|
198
|
-
output += colors.info(`\nDescription: ${displayFields.description}`)
|
|
199
|
-
|
|
200
|
-
if (displayFields.tags && displayFields.tags.length > 0) {
|
|
201
|
-
output += colors.cyan(`\nTags: ${displayFields.tags.join(', ')}`)
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
if (displayFields.relationship) {
|
|
205
|
-
output += colors.yellow(`\nRelationship: ${displayFields.relationship}`)
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
if (item.content && item.content !== displayFields.title) {
|
|
209
|
-
output += colors.dim(`\nOriginal Content: ${item.content}`)
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// Show additional metadata
|
|
213
|
-
if (item.metadata) {
|
|
214
|
-
const additionalMetadata = Object.fromEntries(
|
|
215
|
-
Object.entries(item.metadata).filter(([key]) =>
|
|
216
|
-
!key.startsWith('_') && !['type', 'title', 'description', 'icon'].includes(key)
|
|
217
|
-
)
|
|
218
|
-
)
|
|
219
|
-
if (Object.keys(additionalMetadata).length > 0) {
|
|
220
|
-
output += colors.dim(`\nAdditional Metadata: ${JSON.stringify(additionalMetadata, null, 2)}`)
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
return output
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
} catch (error) {
|
|
228
|
-
// Fallback silently to basic formatting
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// Fallback: Basic formatting
|
|
232
|
-
if (format === 'table') {
|
|
233
|
-
const table = new Table({
|
|
234
|
-
head: [colors.brain('Property'), colors.brain('Value')],
|
|
235
|
-
style: { head: [], border: [] }
|
|
236
|
-
})
|
|
237
|
-
|
|
238
|
-
table.push(['ID', colors.primary(item.id)])
|
|
239
|
-
table.push(['Content', colors.info(item.content || 'N/A')])
|
|
240
|
-
if (item.metadata) {
|
|
241
|
-
Object.entries(item.metadata).forEach(([key, value]) => {
|
|
242
|
-
table.push([key, colors.dim(JSON.stringify(value))])
|
|
243
|
-
})
|
|
244
|
-
}
|
|
245
|
-
return table.toString()
|
|
246
|
-
} else {
|
|
247
|
-
let output = colors.primary(`ID: ${item.id}`)
|
|
248
|
-
if (item.content) {
|
|
249
|
-
output += colors.info(`\nContent: ${item.content}`)
|
|
250
|
-
}
|
|
251
|
-
if (item.metadata && Object.keys(item.metadata).length > 0) {
|
|
252
|
-
output += colors.info(`\nMetadata: ${JSON.stringify(item.metadata, null, 2)}`)
|
|
253
|
-
}
|
|
254
|
-
return output
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
const wrapAction = (fn) => {
|
|
259
|
-
return async (...args) => {
|
|
260
|
-
try {
|
|
261
|
-
await fn(...args)
|
|
262
|
-
exitProcess(0)
|
|
263
|
-
} catch (error) {
|
|
264
|
-
console.error(colors.error('Error:'), error.message)
|
|
265
|
-
exitProcess(1)
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
// AI Response Generation with multiple model support
|
|
271
|
-
async function generateAIResponse(message, brainy, options) {
|
|
272
|
-
const model = options.model || 'local'
|
|
273
|
-
|
|
274
|
-
// Get relevant context from user's data
|
|
275
|
-
const contextResults = await brainy.search(message, {
|
|
276
|
-
limit: 5,
|
|
277
|
-
includeContent: true,
|
|
278
|
-
scoreThreshold: 0.3
|
|
279
|
-
})
|
|
280
|
-
|
|
281
|
-
const context = contextResults.map(r => r.content).join('\n')
|
|
282
|
-
const prompt = `Based on the following context from the user's data, answer their question:
|
|
283
|
-
|
|
284
|
-
Context:
|
|
285
|
-
${context}
|
|
286
|
-
|
|
287
|
-
Question: ${message}
|
|
288
|
-
|
|
289
|
-
Answer:`
|
|
290
|
-
|
|
291
|
-
switch (model) {
|
|
292
|
-
case 'local':
|
|
293
|
-
case 'ollama':
|
|
294
|
-
return await callOllamaModel(prompt, options)
|
|
295
|
-
|
|
296
|
-
case 'openai':
|
|
297
|
-
case 'gpt-3.5-turbo':
|
|
298
|
-
case 'gpt-4':
|
|
299
|
-
return await callOpenAI(prompt, options)
|
|
300
|
-
|
|
301
|
-
case 'claude':
|
|
302
|
-
case 'claude-3':
|
|
303
|
-
return await callClaude(prompt, options)
|
|
304
|
-
|
|
305
|
-
default:
|
|
306
|
-
return await callOllamaModel(prompt, options)
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
// Ollama (local) integration
|
|
311
|
-
async function callOllamaModel(prompt, options) {
|
|
312
|
-
const baseUrl = options.baseUrl || 'http://localhost:11434'
|
|
313
|
-
const model = options.model === 'local' ? 'llama2' : options.model
|
|
314
|
-
|
|
315
|
-
try {
|
|
316
|
-
const response = await fetch(`${baseUrl}/api/generate`, {
|
|
317
|
-
method: 'POST',
|
|
318
|
-
headers: { 'Content-Type': 'application/json' },
|
|
319
|
-
body: JSON.stringify({
|
|
320
|
-
model: model,
|
|
321
|
-
prompt: prompt,
|
|
322
|
-
stream: false
|
|
323
|
-
})
|
|
324
|
-
})
|
|
325
|
-
|
|
326
|
-
if (!response.ok) {
|
|
327
|
-
throw new Error(`Ollama error: ${response.statusText}. Make sure Ollama is running: ollama serve`)
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
const data = await response.json()
|
|
331
|
-
return data.response || 'No response from local model'
|
|
332
|
-
|
|
333
|
-
} catch (error) {
|
|
334
|
-
throw new Error(`Local model error: ${error.message}. Try: ollama run llama2`)
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
// OpenAI integration
|
|
339
|
-
async function callOpenAI(prompt, options) {
|
|
340
|
-
if (!options.apiKey) {
|
|
341
|
-
throw new Error('OpenAI API key required. Use --api-key <key> or set OPENAI_API_KEY environment variable')
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
const model = options.model === 'openai' ? 'gpt-3.5-turbo' : options.model
|
|
345
|
-
|
|
346
|
-
try {
|
|
347
|
-
const response = await fetch('https://api.openai.com/v1/chat/completions', {
|
|
348
|
-
method: 'POST',
|
|
349
|
-
headers: {
|
|
350
|
-
'Authorization': `Bearer ${options.apiKey}`,
|
|
351
|
-
'Content-Type': 'application/json'
|
|
352
|
-
},
|
|
353
|
-
body: JSON.stringify({
|
|
354
|
-
model: model,
|
|
355
|
-
messages: [{ role: 'user', content: prompt }],
|
|
356
|
-
max_tokens: 500
|
|
357
|
-
})
|
|
358
|
-
})
|
|
359
|
-
|
|
360
|
-
if (!response.ok) {
|
|
361
|
-
throw new Error(`OpenAI error: ${response.statusText}`)
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
const data = await response.json()
|
|
365
|
-
return data.choices[0]?.message?.content || 'No response from OpenAI'
|
|
366
|
-
|
|
367
|
-
} catch (error) {
|
|
368
|
-
throw new Error(`OpenAI error: ${error.message}`)
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
// Claude integration
|
|
373
|
-
async function callClaude(prompt, options) {
|
|
374
|
-
if (!options.apiKey) {
|
|
375
|
-
throw new Error('Anthropic API key required. Use --api-key <key> or set ANTHROPIC_API_KEY environment variable')
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
try {
|
|
379
|
-
const response = await fetch('https://api.anthropic.com/v1/messages', {
|
|
380
|
-
method: 'POST',
|
|
381
|
-
headers: {
|
|
382
|
-
'x-api-key': options.apiKey,
|
|
383
|
-
'Content-Type': 'application/json',
|
|
384
|
-
'anthropic-version': '2023-06-01'
|
|
385
|
-
},
|
|
386
|
-
body: JSON.stringify({
|
|
387
|
-
model: 'claude-3-haiku-20240307',
|
|
388
|
-
max_tokens: 500,
|
|
389
|
-
messages: [{ role: 'user', content: prompt }]
|
|
390
|
-
})
|
|
391
|
-
})
|
|
392
|
-
|
|
393
|
-
if (!response.ok) {
|
|
394
|
-
throw new Error(`Claude error: ${response.statusText}`)
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
const data = await response.json()
|
|
398
|
-
return data.content[0]?.text || 'No response from Claude'
|
|
399
|
-
|
|
400
|
-
} catch (error) {
|
|
401
|
-
throw new Error(`Claude error: ${error.message}`)
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
// ========================================
|
|
406
|
-
// MAIN PROGRAM - CLEAN & SIMPLE
|
|
407
|
-
// ========================================
|
|
408
|
-
|
|
409
|
-
program
|
|
410
|
-
.name('brainy')
|
|
411
|
-
.description('š§ āļø Brainy - Your AI-Powered Second Brain')
|
|
412
|
-
.version(packageJson.version)
|
|
413
|
-
.option('-i, --interactive', 'Start interactive mode')
|
|
414
|
-
.addHelpText('after', `
|
|
415
|
-
${colors.dim('Examples:')}
|
|
416
|
-
${colors.success('brainy add "Meeting notes from today"')}
|
|
417
|
-
${colors.success('brainy search "project deadline"')}
|
|
418
|
-
${colors.success('brainy chat')} ${colors.dim('# Interactive AI chat')}
|
|
419
|
-
${colors.success('brainy -i')} ${colors.dim('# Interactive mode')}
|
|
420
|
-
|
|
421
|
-
${colors.dim('For more help:')}
|
|
422
|
-
${colors.info('brainy <command> --help')} ${colors.dim('# Command-specific help')}
|
|
423
|
-
${colors.info('https://github.com/TimeSoul/brainy')} ${colors.dim('# Documentation')}`)
|
|
424
|
-
|
|
425
|
-
// ========================================
|
|
426
|
-
// THE 5 COMMANDS (ONE WAY TO DO EVERYTHING)
|
|
427
|
-
// ========================================
|
|
428
|
-
|
|
429
|
-
// Command 0: INIT - Initialize brainy (essential setup)
|
|
430
|
-
program
|
|
431
|
-
.command('init')
|
|
432
|
-
.description('Initialize Brainy in current directory')
|
|
433
|
-
.option('-s, --storage <type>', 'Storage type (filesystem, memory, s3, r2, gcs)')
|
|
434
|
-
.option('-e, --encryption', 'Enable encryption for sensitive data')
|
|
435
|
-
.option('--s3-bucket <bucket>', 'S3 bucket name')
|
|
436
|
-
.option('--s3-region <region>', 'S3 region')
|
|
437
|
-
.option('--access-key <key>', 'Storage access key')
|
|
438
|
-
.option('--secret-key <key>', 'Storage secret key')
|
|
439
|
-
.action(wrapAction(async (options) => {
|
|
440
|
-
console.log(colors.primary('š§ Initializing Brainy'))
|
|
441
|
-
console.log()
|
|
442
|
-
|
|
443
|
-
const { BrainyData } = await import('../dist/brainyData.js')
|
|
444
|
-
|
|
445
|
-
const config = {
|
|
446
|
-
storage: options.storage || 'filesystem',
|
|
447
|
-
encryption: options.encryption || false
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
// Storage-specific configuration
|
|
451
|
-
if (options.storage === 's3' || options.storage === 'r2' || options.storage === 'gcs') {
|
|
452
|
-
if (!options.accessKey || !options.secretKey) {
|
|
453
|
-
console.log(colors.warning('ā ļø Cloud storage requires access credentials'))
|
|
454
|
-
console.log(colors.info('Use: --access-key <key> --secret-key <secret>'))
|
|
455
|
-
console.log(colors.info('Or set environment variables: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY'))
|
|
456
|
-
process.exit(1)
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
config.storageOptions = {
|
|
460
|
-
bucket: options.s3Bucket,
|
|
461
|
-
region: options.s3Region || 'us-east-1',
|
|
462
|
-
accessKeyId: options.accessKey,
|
|
463
|
-
secretAccessKey: options.secretKey
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
try {
|
|
468
|
-
const brainy = new BrainyData(config)
|
|
469
|
-
await brainy.init()
|
|
470
|
-
|
|
471
|
-
console.log(colors.success('ā
Brainy initialized successfully!'))
|
|
472
|
-
console.log(colors.info(`š Storage: ${config.storage}`))
|
|
473
|
-
console.log(colors.info(`š Encryption: ${config.encryption ? 'Enabled' : 'Disabled'}`))
|
|
474
|
-
|
|
475
|
-
if (config.encryption) {
|
|
476
|
-
console.log(colors.warning('š Encryption enabled - keep your keys secure!'))
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
console.log()
|
|
480
|
-
console.log(colors.success('š Ready to go! Try:'))
|
|
481
|
-
console.log(colors.info(' brainy add "Hello, World!"'))
|
|
482
|
-
console.log(colors.info(' brainy search "hello"'))
|
|
483
|
-
|
|
484
|
-
} catch (error) {
|
|
485
|
-
console.log(colors.error('ā Initialization failed:'))
|
|
486
|
-
console.log(colors.error(error.message))
|
|
487
|
-
process.exit(1)
|
|
488
|
-
}
|
|
489
|
-
}))
|
|
490
|
-
|
|
491
|
-
// Command 1: ADD - Add data (smart by default)
|
|
492
|
-
program
|
|
493
|
-
.command('add [data]')
|
|
494
|
-
.description('Add data to your brain (smart auto-detection)')
|
|
495
|
-
.option('-m, --metadata <json>', 'Metadata as JSON')
|
|
496
|
-
.option('-i, --id <id>', 'Custom ID')
|
|
497
|
-
.option('--literal', 'Skip AI processing (literal storage)')
|
|
498
|
-
.option('--encrypt', 'Encrypt this data (for sensitive information)')
|
|
499
|
-
.action(wrapAction(async (data, options) => {
|
|
500
|
-
if (!data) {
|
|
501
|
-
console.log(colors.info('š§ Interactive add mode'))
|
|
502
|
-
const rl = createInterface({
|
|
503
|
-
input: process.stdin,
|
|
504
|
-
output: process.stdout
|
|
505
|
-
})
|
|
506
|
-
|
|
507
|
-
data = await new Promise(resolve => {
|
|
508
|
-
rl.question(colors.primary('What would you like to add? '), (answer) => {
|
|
509
|
-
rl.close()
|
|
510
|
-
resolve(answer)
|
|
511
|
-
})
|
|
512
|
-
})
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
let metadata = {}
|
|
516
|
-
if (options.metadata) {
|
|
517
|
-
try {
|
|
518
|
-
metadata = JSON.parse(options.metadata)
|
|
519
|
-
} catch {
|
|
520
|
-
console.error(colors.error('Invalid JSON metadata'))
|
|
521
|
-
process.exit(1)
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
if (options.id) {
|
|
525
|
-
metadata.id = options.id
|
|
526
|
-
}
|
|
527
|
-
if (options.encrypt) {
|
|
528
|
-
metadata.encrypted = true
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
console.log(options.literal
|
|
532
|
-
? colors.info('š Literal storage')
|
|
533
|
-
: colors.success('š§ Smart mode (auto-detects types)')
|
|
534
|
-
)
|
|
535
|
-
|
|
536
|
-
if (options.encrypt) {
|
|
537
|
-
console.log(colors.warning('š Encrypting sensitive data...'))
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
const brainyInstance = await getBrainy()
|
|
541
|
-
|
|
542
|
-
// Handle encryption at data level if requested
|
|
543
|
-
let processedData = data
|
|
544
|
-
if (options.encrypt) {
|
|
545
|
-
processedData = await brainyInstance.encryptData(data)
|
|
546
|
-
metadata.encrypted = true
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
const id = await brainyInstance.add({ data: processedData, type: 'content', metadata })
|
|
550
|
-
console.log(colors.success(`ā
Added successfully! ID: ${id}`))
|
|
551
|
-
}))
|
|
552
|
-
|
|
553
|
-
// Command 2: CHAT - Talk to your data with AI
|
|
554
|
-
program
|
|
555
|
-
.command('chat [message]')
|
|
556
|
-
.description('AI chat with your brain data (supports local & cloud models)')
|
|
557
|
-
.option('-s, --session <id>', 'Use specific chat session')
|
|
558
|
-
.option('-n, --new', 'Start a new session')
|
|
559
|
-
.option('-l, --list', 'List all chat sessions')
|
|
560
|
-
.option('-h, --history [limit]', 'Show conversation history (default: 10)')
|
|
561
|
-
.option('--search <query>', 'Search all conversations')
|
|
562
|
-
.option('-m, --model <model>', 'LLM model (local/openai/claude/ollama)', 'local')
|
|
563
|
-
.option('--api-key <key>', 'API key for cloud models')
|
|
564
|
-
.option('--base-url <url>', 'Base URL for local models (default: http://localhost:11434)')
|
|
565
|
-
.action(wrapAction(async (message, options) => {
|
|
566
|
-
const { BrainyData } = await import('../dist/brainyData.js')
|
|
567
|
-
const { BrainyChat } = await import('../dist/chat/BrainyChat.js')
|
|
568
|
-
|
|
569
|
-
console.log(colors.primary('š§ š¬ Brainy Chat - AI-Powered Conversation with Your Data'))
|
|
570
|
-
console.log(colors.info('Talk to your brain using your data as context'))
|
|
571
|
-
console.log()
|
|
572
|
-
|
|
573
|
-
// Initialize brainy and chat
|
|
574
|
-
const brainy = new BrainyData()
|
|
575
|
-
await brainy.init()
|
|
576
|
-
const chat = new BrainyChat(brainy)
|
|
577
|
-
|
|
578
|
-
// Handle different options
|
|
579
|
-
if (options.list) {
|
|
580
|
-
console.log(colors.primary('š Chat Sessions'))
|
|
581
|
-
const sessions = await chat.getSessions(20)
|
|
582
|
-
if (sessions.length === 0) {
|
|
583
|
-
console.log(colors.warning('No chat sessions found. Start chatting to create your first session!'))
|
|
584
|
-
} else {
|
|
585
|
-
sessions.forEach((session, i) => {
|
|
586
|
-
console.log(colors.success(`${i + 1}. ${session.id}`))
|
|
587
|
-
if (session.title) console.log(colors.info(` Title: ${session.title}`))
|
|
588
|
-
console.log(colors.info(` Messages: ${session.messageCount}`))
|
|
589
|
-
console.log(colors.info(` Last active: ${session.lastMessageAt.toLocaleDateString()}`))
|
|
590
|
-
})
|
|
591
|
-
}
|
|
592
|
-
return
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
if (options.search) {
|
|
596
|
-
console.log(colors.primary(`š Searching conversations for: "${options.search}"`))
|
|
597
|
-
const results = await chat.searchMessages(options.search, { limit: 10 })
|
|
598
|
-
if (results.length === 0) {
|
|
599
|
-
console.log(colors.warning('No messages found'))
|
|
600
|
-
} else {
|
|
601
|
-
results.forEach((msg, i) => {
|
|
602
|
-
console.log(colors.success(`\n${i + 1}. [${msg.sessionId}] ${colors.info(msg.speaker)}:`))
|
|
603
|
-
console.log(` ${msg.content.substring(0, 200)}${msg.content.length > 200 ? '...' : ''}`)
|
|
604
|
-
})
|
|
605
|
-
}
|
|
606
|
-
return
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
if (options.history) {
|
|
610
|
-
const limit = parseInt(options.history) || 10
|
|
611
|
-
console.log(colors.primary(`š Recent Chat History (${limit} messages)`))
|
|
612
|
-
const history = await chat.getHistory(limit)
|
|
613
|
-
if (history.length === 0) {
|
|
614
|
-
console.log(colors.warning('No chat history found'))
|
|
615
|
-
} else {
|
|
616
|
-
history.forEach(msg => {
|
|
617
|
-
const speaker = msg.speaker === 'user' ? colors.success('You') : colors.info('AI')
|
|
618
|
-
console.log(`${speaker}: ${msg.content}`)
|
|
619
|
-
console.log(colors.info(` ${msg.timestamp.toLocaleString()}`))
|
|
620
|
-
console.log()
|
|
621
|
-
})
|
|
622
|
-
}
|
|
623
|
-
return
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
// Start interactive chat or process single message
|
|
627
|
-
if (!message) {
|
|
628
|
-
console.log(colors.success('šÆ Interactive mode - type messages or "exit" to quit'))
|
|
629
|
-
console.log(colors.info(`Model: ${options.model}`))
|
|
630
|
-
console.log()
|
|
631
|
-
|
|
632
|
-
// Auto-discover previous session
|
|
633
|
-
const session = options.new ? null : await chat.initialize()
|
|
634
|
-
if (session) {
|
|
635
|
-
console.log(colors.success(`š Resumed session: ${session.id}`))
|
|
636
|
-
console.log()
|
|
637
|
-
} else {
|
|
638
|
-
const newSession = await chat.startNewSession()
|
|
639
|
-
console.log(colors.success(`š Started new session: ${newSession.id}`))
|
|
640
|
-
console.log()
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
// Interactive chat loop
|
|
644
|
-
const rl = createInterface({
|
|
645
|
-
input: process.stdin,
|
|
646
|
-
output: process.stdout,
|
|
647
|
-
prompt: colors.primary('You: ')
|
|
648
|
-
})
|
|
649
|
-
|
|
650
|
-
rl.prompt()
|
|
651
|
-
|
|
652
|
-
rl.on('line', async (input) => {
|
|
653
|
-
if (input.trim().toLowerCase() === 'exit') {
|
|
654
|
-
console.log(colors.success('š Chat session saved to your brain!'))
|
|
655
|
-
rl.close()
|
|
656
|
-
return
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
if (input.trim()) {
|
|
660
|
-
// Store user message
|
|
661
|
-
await chat.addMessage(input.trim(), 'user')
|
|
662
|
-
|
|
663
|
-
// Generate AI response
|
|
664
|
-
try {
|
|
665
|
-
const response = await generateAIResponse(input.trim(), brainy, options)
|
|
666
|
-
console.log(colors.info('AI: ') + response)
|
|
667
|
-
|
|
668
|
-
// Store AI response
|
|
669
|
-
await chat.addMessage(response, 'assistant', { model: options.model })
|
|
670
|
-
console.log()
|
|
671
|
-
} catch (error) {
|
|
672
|
-
console.log(colors.error('AI Error: ') + error.message)
|
|
673
|
-
console.log(colors.warning('š” Tip: Try setting --model local or providing --api-key'))
|
|
674
|
-
console.log()
|
|
675
|
-
}
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
rl.prompt()
|
|
679
|
-
})
|
|
680
|
-
|
|
681
|
-
rl.on('close', () => {
|
|
682
|
-
exitProcess(0)
|
|
683
|
-
})
|
|
684
|
-
|
|
685
|
-
} else {
|
|
686
|
-
// Single message mode
|
|
687
|
-
console.log(colors.success('You: ') + message)
|
|
688
|
-
|
|
689
|
-
try {
|
|
690
|
-
const response = await generateAIResponse(message, brainy, options)
|
|
691
|
-
console.log(colors.info('AI: ') + response)
|
|
692
|
-
|
|
693
|
-
// Store conversation
|
|
694
|
-
await chat.addMessage(message, 'user')
|
|
695
|
-
await chat.addMessage(response, 'assistant', { model: options.model })
|
|
696
|
-
|
|
697
|
-
} catch (error) {
|
|
698
|
-
console.log(colors.error('Error: ') + error.message)
|
|
699
|
-
console.log(colors.info('š” Try: brainy chat --model local or provide --api-key'))
|
|
700
|
-
}
|
|
701
|
-
}
|
|
702
|
-
}))
|
|
703
|
-
|
|
704
|
-
// Command 3: IMPORT - Bulk/external data
|
|
705
|
-
program
|
|
706
|
-
.command('import [source]')
|
|
707
|
-
.description('Import bulk data from files, URLs, or streams')
|
|
708
|
-
.option('-t, --type <type>', 'Source type (file, url, stream)')
|
|
709
|
-
.option('-c, --chunk-size <size>', 'Chunk size for large imports', '1000')
|
|
710
|
-
.action(wrapAction(async (source, options) => {
|
|
711
|
-
|
|
712
|
-
// Interactive mode if no source provided
|
|
713
|
-
if (!source) {
|
|
714
|
-
console.log(colors.primary('š„ Interactive Import Mode'))
|
|
715
|
-
console.log(colors.dim('Import data from various sources\n'))
|
|
716
|
-
|
|
717
|
-
const rl = createInterface({
|
|
718
|
-
input: process.stdin,
|
|
719
|
-
output: process.stdout
|
|
720
|
-
})
|
|
721
|
-
|
|
722
|
-
// Ask for source type first
|
|
723
|
-
console.log(colors.cyan('Source types:'))
|
|
724
|
-
console.log(colors.info(' 1. Local file'))
|
|
725
|
-
console.log(colors.info(' 2. URL'))
|
|
726
|
-
console.log(colors.info(' 3. Direct input'))
|
|
727
|
-
console.log()
|
|
728
|
-
|
|
729
|
-
const sourceType = await new Promise(resolve => {
|
|
730
|
-
rl.question(colors.cyan('Select source type (1-3): '), (answer) => {
|
|
731
|
-
resolve(answer)
|
|
732
|
-
})
|
|
733
|
-
})
|
|
734
|
-
|
|
735
|
-
if (sourceType === '3') {
|
|
736
|
-
// Direct input mode
|
|
737
|
-
console.log(colors.info('\nEnter your data (type END on a new line when done):\n'))
|
|
738
|
-
let data = ''
|
|
739
|
-
let line = ''
|
|
740
|
-
|
|
741
|
-
while ((line = await new Promise(resolve => {
|
|
742
|
-
rl.question('', resolve)
|
|
743
|
-
})) !== 'END') {
|
|
744
|
-
data += line + '\n'
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
rl.close()
|
|
748
|
-
|
|
749
|
-
// Save to temp file
|
|
750
|
-
const fs = require('fs')
|
|
751
|
-
source = `/tmp/brainy-import-${Date.now()}.json`
|
|
752
|
-
fs.writeFileSync(source, data.trim())
|
|
753
|
-
console.log(colors.info(`\nSaved to temporary file: ${source}`))
|
|
754
|
-
} else {
|
|
755
|
-
// File or URL
|
|
756
|
-
source = await new Promise(resolve => {
|
|
757
|
-
const prompt = sourceType === '2' ? 'Enter URL: ' : 'Enter file path: '
|
|
758
|
-
rl.question(colors.cyan(prompt), (answer) => {
|
|
759
|
-
rl.close()
|
|
760
|
-
resolve(answer)
|
|
761
|
-
})
|
|
762
|
-
})
|
|
763
|
-
|
|
764
|
-
if (!source.trim()) {
|
|
765
|
-
console.log(colors.warning('No source provided'))
|
|
766
|
-
process.exit(1)
|
|
767
|
-
}
|
|
768
|
-
}
|
|
769
|
-
}
|
|
770
|
-
console.log(colors.info('š„ Starting neural import...'))
|
|
771
|
-
console.log(colors.info(`Source: ${source}`))
|
|
772
|
-
|
|
773
|
-
// Read and prepare data for import
|
|
774
|
-
const fs = require('fs')
|
|
775
|
-
let data
|
|
776
|
-
|
|
777
|
-
try {
|
|
778
|
-
if (source.startsWith('http')) {
|
|
779
|
-
// Handle URL import
|
|
780
|
-
const response = await fetch(source)
|
|
781
|
-
data = await response.text()
|
|
782
|
-
} else {
|
|
783
|
-
// Handle file import
|
|
784
|
-
data = fs.readFileSync(source, 'utf8')
|
|
785
|
-
}
|
|
786
|
-
|
|
787
|
-
// Parse data if JSON
|
|
788
|
-
try {
|
|
789
|
-
data = JSON.parse(data)
|
|
790
|
-
} catch {
|
|
791
|
-
// Keep as string if not JSON
|
|
792
|
-
}
|
|
793
|
-
} catch (error) {
|
|
794
|
-
console.log(colors.error(`Failed to read source: ${error.message}`))
|
|
795
|
-
process.exit(1)
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
const brainyInstance = await getBrainy()
|
|
799
|
-
const result = await brainyInstance.import(data, {
|
|
800
|
-
batchSize: parseInt(options.chunkSize) || 50
|
|
801
|
-
})
|
|
802
|
-
|
|
803
|
-
console.log(colors.success(`ā
Imported ${result.length} items`))
|
|
804
|
-
}))
|
|
805
|
-
|
|
806
|
-
// Command 3: FIND - Intelligent search using Triple Intelligence
|
|
807
|
-
program
|
|
808
|
-
.command('find [query]')
|
|
809
|
-
.description('Intelligent search using natural language and structured queries')
|
|
810
|
-
.option('-l, --limit <number>', 'Results limit', '10')
|
|
811
|
-
.option('-m, --mode <mode>', 'Search mode (auto, semantic, structured)', 'auto')
|
|
812
|
-
.option('--like <term>', 'Vector similarity search term')
|
|
813
|
-
.option('--where <json>', 'Metadata filters as JSON')
|
|
814
|
-
.action(wrapAction(async (query, options) => {
|
|
815
|
-
|
|
816
|
-
if (!query && !options.like) {
|
|
817
|
-
console.log(colors.primary('š§ Intelligent Find Mode'))
|
|
818
|
-
console.log(colors.dim('Use natural language or structured queries\n'))
|
|
819
|
-
|
|
820
|
-
const rl = createInterface({
|
|
821
|
-
input: process.stdin,
|
|
822
|
-
output: process.stdout
|
|
823
|
-
})
|
|
824
|
-
|
|
825
|
-
query = await new Promise(resolve => {
|
|
826
|
-
rl.question(colors.cyan('What would you like to find? '), (answer) => {
|
|
827
|
-
rl.close()
|
|
828
|
-
resolve(answer)
|
|
829
|
-
})
|
|
830
|
-
})
|
|
831
|
-
|
|
832
|
-
if (!query.trim()) {
|
|
833
|
-
console.log(colors.warning('No query provided'))
|
|
834
|
-
process.exit(1)
|
|
835
|
-
}
|
|
836
|
-
}
|
|
837
|
-
|
|
838
|
-
console.log(colors.info(`š§ Finding: "${query || options.like}"`))
|
|
839
|
-
|
|
840
|
-
const brainyInstance = await getBrainy()
|
|
841
|
-
|
|
842
|
-
// Build query object for find() API
|
|
843
|
-
let findQuery = query
|
|
844
|
-
|
|
845
|
-
// Handle structured queries
|
|
846
|
-
if (options.like || options.where) {
|
|
847
|
-
findQuery = {}
|
|
848
|
-
if (options.like) findQuery.like = options.like
|
|
849
|
-
if (options.where) {
|
|
850
|
-
try {
|
|
851
|
-
findQuery.where = JSON.parse(options.where)
|
|
852
|
-
} catch {
|
|
853
|
-
console.error(colors.error('Invalid JSON in --where option'))
|
|
854
|
-
process.exit(1)
|
|
855
|
-
}
|
|
856
|
-
}
|
|
857
|
-
}
|
|
858
|
-
|
|
859
|
-
const findOptions = {
|
|
860
|
-
limit: parseInt(options.limit),
|
|
861
|
-
mode: options.mode
|
|
862
|
-
}
|
|
863
|
-
|
|
864
|
-
const results = await brainyInstance.find(findQuery, findOptions)
|
|
865
|
-
|
|
866
|
-
if (results.length === 0) {
|
|
867
|
-
console.log(colors.warning('No results found'))
|
|
868
|
-
return
|
|
869
|
-
}
|
|
870
|
-
|
|
871
|
-
console.log(colors.success(`ā
Found ${results.length} intelligent results:`))
|
|
872
|
-
|
|
873
|
-
// Use enhanced formatting with display augmentation
|
|
874
|
-
for (let i = 0; i < results.length; i++) {
|
|
875
|
-
const formattedResult = await formatResultWithDisplay(results[i], i)
|
|
876
|
-
console.log(formattedResult)
|
|
877
|
-
}
|
|
878
|
-
}))
|
|
879
|
-
|
|
880
|
-
// Command 4: SEARCH - Triple-power search
|
|
881
|
-
program
|
|
882
|
-
.command('search [query]')
|
|
883
|
-
.description('Search your brain (vector + graph + facets)')
|
|
884
|
-
.option('-l, --limit <number>', 'Results limit', '10')
|
|
885
|
-
.option('-f, --filter <json>', 'Metadata filters (see "brainy fields" for available fields)')
|
|
886
|
-
.option('-d, --depth <number>', 'Relationship depth', '2')
|
|
887
|
-
.option('--fields', 'Show available filter fields and exit')
|
|
888
|
-
.action(wrapAction(async (query, options) => {
|
|
889
|
-
|
|
890
|
-
// Interactive mode if no query provided
|
|
891
|
-
if (!query) {
|
|
892
|
-
console.log(colors.primary('š Interactive Search Mode'))
|
|
893
|
-
console.log(colors.dim('Search your neural database with natural language\n'))
|
|
894
|
-
|
|
895
|
-
const rl = createInterface({
|
|
896
|
-
input: process.stdin,
|
|
897
|
-
output: process.stdout
|
|
898
|
-
})
|
|
899
|
-
|
|
900
|
-
query = await new Promise(resolve => {
|
|
901
|
-
rl.question(colors.cyan('What would you like to search for? '), (answer) => {
|
|
902
|
-
rl.close()
|
|
903
|
-
resolve(answer)
|
|
904
|
-
})
|
|
905
|
-
})
|
|
906
|
-
|
|
907
|
-
if (!query.trim()) {
|
|
908
|
-
console.log(colors.warning('No search query provided'))
|
|
909
|
-
process.exit(1)
|
|
910
|
-
}
|
|
911
|
-
}
|
|
912
|
-
|
|
913
|
-
// Handle --fields option
|
|
914
|
-
if (options.fields) {
|
|
915
|
-
console.log(colors.primary('š Available Filter Fields'))
|
|
916
|
-
console.log(colors.primary('=' .repeat(30)))
|
|
917
|
-
|
|
918
|
-
try {
|
|
919
|
-
const { BrainyData } = await import('../dist/brainyData.js')
|
|
920
|
-
const brainy = new BrainyData()
|
|
921
|
-
await brainy.init()
|
|
922
|
-
|
|
923
|
-
const filterFields = await brainy.getFilterFields()
|
|
924
|
-
if (filterFields.length > 0) {
|
|
925
|
-
console.log(colors.success('Available fields for --filter option:'))
|
|
926
|
-
filterFields.forEach(field => {
|
|
927
|
-
console.log(colors.info(` ${field}`))
|
|
928
|
-
})
|
|
929
|
-
console.log()
|
|
930
|
-
console.log(colors.primary('Usage Examples:'))
|
|
931
|
-
console.log(colors.info(` brainy search "query" --filter '{"type":"person"}'`))
|
|
932
|
-
console.log(colors.info(` brainy search "query" --filter '{"category":"work","status":"active"}'`))
|
|
933
|
-
} else {
|
|
934
|
-
console.log(colors.warning('No indexed fields available yet.'))
|
|
935
|
-
console.log(colors.info('Add some data with metadata to see available fields.'))
|
|
936
|
-
}
|
|
937
|
-
|
|
938
|
-
} catch (error) {
|
|
939
|
-
console.log(colors.error(`Error: ${error.message}`))
|
|
940
|
-
}
|
|
941
|
-
return
|
|
942
|
-
}
|
|
943
|
-
console.log(colors.info(`š Searching: "${query}"`))
|
|
944
|
-
|
|
945
|
-
const searchOptions = {
|
|
946
|
-
limit: parseInt(options.limit),
|
|
947
|
-
depth: parseInt(options.depth)
|
|
948
|
-
}
|
|
949
|
-
|
|
950
|
-
if (options.filter) {
|
|
951
|
-
try {
|
|
952
|
-
searchOptions.filter = JSON.parse(options.filter)
|
|
953
|
-
} catch {
|
|
954
|
-
console.error(colors.error('Invalid filter JSON'))
|
|
955
|
-
process.exit(1)
|
|
956
|
-
}
|
|
957
|
-
}
|
|
958
|
-
|
|
959
|
-
const brainyInstance = await getBrainy()
|
|
960
|
-
const results = await brainyInstance.search(query, searchOptions)
|
|
961
|
-
|
|
962
|
-
if (results.length === 0) {
|
|
963
|
-
console.log(colors.warning('No results found'))
|
|
964
|
-
return
|
|
965
|
-
}
|
|
966
|
-
|
|
967
|
-
console.log(colors.success(`ā
Found ${results.length} results:`))
|
|
968
|
-
|
|
969
|
-
// Use enhanced formatting with display augmentation
|
|
970
|
-
for (let i = 0; i < results.length; i++) {
|
|
971
|
-
const formattedResult = await formatResultWithDisplay(results[i], i)
|
|
972
|
-
console.log(formattedResult)
|
|
973
|
-
}
|
|
974
|
-
}))
|
|
975
|
-
|
|
976
|
-
// Command 4: GET - Retrieve specific data by ID
|
|
977
|
-
program
|
|
978
|
-
.command('get [id]')
|
|
979
|
-
.description('Get a specific item by ID')
|
|
980
|
-
.option('-f, --format <format>', 'Output format (json, table, plain)', 'plain')
|
|
981
|
-
.option('--display-debug', 'Show debug information about display augmentation')
|
|
982
|
-
.action(wrapAction(async (id, options) => {
|
|
983
|
-
if (!id) {
|
|
984
|
-
console.log(colors.primary('š Interactive Get Mode'))
|
|
985
|
-
console.log(colors.dim('Retrieve a specific item by ID\n'))
|
|
986
|
-
|
|
987
|
-
const rl = createInterface({
|
|
988
|
-
input: process.stdin,
|
|
989
|
-
output: process.stdout
|
|
990
|
-
})
|
|
991
|
-
|
|
992
|
-
id = await new Promise(resolve => {
|
|
993
|
-
rl.question(colors.cyan('Enter item ID: '), (answer) => {
|
|
994
|
-
rl.close()
|
|
995
|
-
resolve(answer)
|
|
996
|
-
})
|
|
997
|
-
})
|
|
998
|
-
|
|
999
|
-
if (!id.trim()) {
|
|
1000
|
-
console.log(colors.warning('No ID provided'))
|
|
1001
|
-
process.exit(1)
|
|
1002
|
-
}
|
|
1003
|
-
}
|
|
1004
|
-
|
|
1005
|
-
console.log(colors.info(`š Getting item: "${id}"`))
|
|
1006
|
-
|
|
1007
|
-
const brainyInstance = await getBrainy()
|
|
1008
|
-
const item = await brainyInstance.getNoun(id)
|
|
1009
|
-
|
|
1010
|
-
if (!item) {
|
|
1011
|
-
console.log(colors.warning('Item not found'))
|
|
1012
|
-
return
|
|
1013
|
-
}
|
|
1014
|
-
|
|
1015
|
-
// Show display debug information if requested
|
|
1016
|
-
if (options.displayDebug) {
|
|
1017
|
-
console.log(colors.primary('š Display Augmentation Debug Information'))
|
|
1018
|
-
console.log('=' .repeat(50))
|
|
1019
|
-
|
|
1020
|
-
try {
|
|
1021
|
-
if (item.getDisplay && typeof item.getDisplay === 'function') {
|
|
1022
|
-
console.log(colors.success('ā
Display augmentation active'))
|
|
1023
|
-
|
|
1024
|
-
const displayFields = await item.getDisplay()
|
|
1025
|
-
console.log(colors.info('\nšØ Computed Display Fields:'))
|
|
1026
|
-
Object.entries(displayFields).forEach(([key, value]) => {
|
|
1027
|
-
console.log(colors.cyan(` ${key}: ${JSON.stringify(value)}`))
|
|
1028
|
-
})
|
|
1029
|
-
|
|
1030
|
-
// Show available fields
|
|
1031
|
-
if (item.getAvailableFields && typeof item.getAvailableFields === 'function') {
|
|
1032
|
-
const availableFields = item.getAvailableFields('display')
|
|
1033
|
-
console.log(colors.info('\nš Available Display Fields:'))
|
|
1034
|
-
availableFields.forEach(field => {
|
|
1035
|
-
console.log(colors.dim(` - ${field}`))
|
|
1036
|
-
})
|
|
1037
|
-
}
|
|
1038
|
-
|
|
1039
|
-
// Show augmentation info
|
|
1040
|
-
if (item.getAvailableAugmentations && typeof item.getAvailableAugmentations === 'function') {
|
|
1041
|
-
const augs = item.getAvailableAugmentations()
|
|
1042
|
-
console.log(colors.info('\nš Available Augmentations:'))
|
|
1043
|
-
augs.forEach(aug => {
|
|
1044
|
-
console.log(colors.dim(` - ${aug}`))
|
|
1045
|
-
})
|
|
1046
|
-
}
|
|
1047
|
-
} else {
|
|
1048
|
-
console.log(colors.warning('ā ļø Display augmentation not active or not enhanced'))
|
|
1049
|
-
console.log(colors.dim(' Item does not have getDisplay() method'))
|
|
1050
|
-
}
|
|
1051
|
-
} catch (error) {
|
|
1052
|
-
console.log(colors.error(`ā Display debug error: ${error.message}`))
|
|
1053
|
-
}
|
|
1054
|
-
|
|
1055
|
-
console.log('\n' + '=' .repeat(50))
|
|
1056
|
-
}
|
|
1057
|
-
|
|
1058
|
-
// Use enhanced formatting with display augmentation
|
|
1059
|
-
const formattedItem = await formatItemWithDisplay(item, options.format)
|
|
1060
|
-
console.log(formattedItem)
|
|
1061
|
-
}))
|
|
1062
|
-
|
|
1063
|
-
// Command 5: UPDATE - Update existing data
|
|
1064
|
-
program
|
|
1065
|
-
.command('update [id]')
|
|
1066
|
-
.description('Update existing data with new content or metadata')
|
|
1067
|
-
.option('-d, --data <data>', 'New data content')
|
|
1068
|
-
.option('-m, --metadata <json>', 'New metadata as JSON')
|
|
1069
|
-
.option('--no-merge', 'Replace metadata instead of merging')
|
|
1070
|
-
.option('--no-reindex', 'Skip reindexing (faster but less accurate search)')
|
|
1071
|
-
.option('--cascade', 'Update related verbs')
|
|
1072
|
-
.action(wrapAction(async (id, options) => {
|
|
1073
|
-
|
|
1074
|
-
// Interactive mode if no ID provided
|
|
1075
|
-
if (!id) {
|
|
1076
|
-
console.log(colors.primary('š Interactive Update Mode'))
|
|
1077
|
-
console.log(colors.dim('Select an item to update\n'))
|
|
1078
|
-
|
|
1079
|
-
// Show recent items
|
|
1080
|
-
const brainyInstance = await getBrainy()
|
|
1081
|
-
const recent = await brainyInstance.search('*', { limit: 10, sortBy: 'timestamp' })
|
|
1082
|
-
|
|
1083
|
-
if (recent.length > 0) {
|
|
1084
|
-
console.log(colors.cyan('Recent items:'))
|
|
1085
|
-
|
|
1086
|
-
// Enhanced display for recent items
|
|
1087
|
-
for (let i = 0; i < Math.min(recent.length, 10); i++) {
|
|
1088
|
-
const item = recent[i]
|
|
1089
|
-
try {
|
|
1090
|
-
if (item.getDisplay && typeof item.getDisplay === 'function') {
|
|
1091
|
-
const displayFields = await item.getDisplay()
|
|
1092
|
-
console.log(colors.info(` ${i + 1}. ${item.id} - ${displayFields.title}`))
|
|
1093
|
-
} else {
|
|
1094
|
-
console.log(colors.info(` ${i + 1}. ${item.id} - ${item.content?.substring(0, 50)}...`))
|
|
1095
|
-
}
|
|
1096
|
-
} catch {
|
|
1097
|
-
console.log(colors.info(` ${i + 1}. ${item.id} - ${item.content?.substring(0, 50)}...`))
|
|
1098
|
-
}
|
|
1099
|
-
}
|
|
1100
|
-
console.log()
|
|
1101
|
-
}
|
|
1102
|
-
|
|
1103
|
-
const rl = createInterface({
|
|
1104
|
-
input: process.stdin,
|
|
1105
|
-
output: process.stdout
|
|
1106
|
-
})
|
|
1107
|
-
|
|
1108
|
-
id = await new Promise(resolve => {
|
|
1109
|
-
rl.question(colors.cyan('Enter ID to update: '), (answer) => {
|
|
1110
|
-
rl.close()
|
|
1111
|
-
resolve(answer)
|
|
1112
|
-
})
|
|
1113
|
-
})
|
|
1114
|
-
|
|
1115
|
-
if (!id.trim()) {
|
|
1116
|
-
console.log(colors.warning('No ID provided'))
|
|
1117
|
-
process.exit(1)
|
|
1118
|
-
}
|
|
1119
|
-
}
|
|
1120
|
-
console.log(colors.info(`š Updating: "${id}"`))
|
|
1121
|
-
|
|
1122
|
-
if (!options.data && !options.metadata) {
|
|
1123
|
-
console.error(colors.error('Error: Must provide --data or --metadata'))
|
|
1124
|
-
process.exit(1)
|
|
1125
|
-
}
|
|
1126
|
-
|
|
1127
|
-
let metadata = undefined
|
|
1128
|
-
if (options.metadata) {
|
|
1129
|
-
try {
|
|
1130
|
-
metadata = JSON.parse(options.metadata)
|
|
1131
|
-
} catch {
|
|
1132
|
-
console.error(colors.error('Invalid JSON metadata'))
|
|
1133
|
-
process.exit(1)
|
|
1134
|
-
}
|
|
1135
|
-
}
|
|
1136
|
-
|
|
1137
|
-
const brainyInstance = await getBrainy()
|
|
1138
|
-
|
|
1139
|
-
const success = await brainyInstance.updateNoun(id, options.data, metadata, {
|
|
1140
|
-
merge: options.merge !== false, // Default true unless --no-merge
|
|
1141
|
-
reindex: options.reindex !== false, // Default true unless --no-reindex
|
|
1142
|
-
cascade: options.cascade || false
|
|
1143
|
-
})
|
|
1144
|
-
|
|
1145
|
-
if (success) {
|
|
1146
|
-
console.log(colors.success('ā
Updated successfully!'))
|
|
1147
|
-
if (options.cascade) {
|
|
1148
|
-
console.log(colors.info('š Related verbs updated'))
|
|
1149
|
-
}
|
|
1150
|
-
} else {
|
|
1151
|
-
console.log(colors.error('ā Update failed'))
|
|
1152
|
-
}
|
|
1153
|
-
}))
|
|
1154
|
-
|
|
1155
|
-
// Command 5: DELETE - Remove data (soft delete by default)
|
|
1156
|
-
program
|
|
1157
|
-
.command('delete [id]')
|
|
1158
|
-
.description('Delete data (soft delete by default, preserves indexes)')
|
|
1159
|
-
.option('--hard', 'Permanent deletion (removes from indexes)')
|
|
1160
|
-
.option('--cascade', 'Delete related verbs')
|
|
1161
|
-
.option('--force', 'Force delete even if has relationships')
|
|
1162
|
-
.action(wrapAction(async (id, options) => {
|
|
1163
|
-
|
|
1164
|
-
// Interactive mode if no ID provided
|
|
1165
|
-
if (!id) {
|
|
1166
|
-
console.log(colors.warning('šļø Interactive Delete Mode'))
|
|
1167
|
-
console.log(colors.dim('Select an item to delete\n'))
|
|
1168
|
-
|
|
1169
|
-
// Show recent items for selection
|
|
1170
|
-
const brainyInstance = await getBrainy()
|
|
1171
|
-
const recent = await brainyInstance.search('*', { limit: 10, sortBy: 'timestamp' })
|
|
1172
|
-
|
|
1173
|
-
if (recent.length > 0) {
|
|
1174
|
-
console.log(colors.cyan('Recent items:'))
|
|
1175
|
-
|
|
1176
|
-
// Enhanced display for recent items
|
|
1177
|
-
for (let i = 0; i < Math.min(recent.length, 10); i++) {
|
|
1178
|
-
const item = recent[i]
|
|
1179
|
-
try {
|
|
1180
|
-
if (item.getDisplay && typeof item.getDisplay === 'function') {
|
|
1181
|
-
const displayFields = await item.getDisplay()
|
|
1182
|
-
console.log(colors.info(` ${i + 1}. ${item.id} - ${displayFields.title}`))
|
|
1183
|
-
} else {
|
|
1184
|
-
console.log(colors.info(` ${i + 1}. ${item.id} - ${item.content?.substring(0, 50)}...`))
|
|
1185
|
-
}
|
|
1186
|
-
} catch {
|
|
1187
|
-
console.log(colors.info(` ${i + 1}. ${item.id} - ${item.content?.substring(0, 50)}...`))
|
|
1188
|
-
}
|
|
1189
|
-
}
|
|
1190
|
-
console.log()
|
|
1191
|
-
}
|
|
1192
|
-
|
|
1193
|
-
const rl = createInterface({
|
|
1194
|
-
input: process.stdin,
|
|
1195
|
-
output: process.stdout
|
|
1196
|
-
})
|
|
1197
|
-
|
|
1198
|
-
id = await new Promise(resolve => {
|
|
1199
|
-
rl.question(colors.warning('Enter ID to delete (or "cancel"): '), (answer) => {
|
|
1200
|
-
rl.close()
|
|
1201
|
-
resolve(answer)
|
|
1202
|
-
})
|
|
1203
|
-
})
|
|
1204
|
-
|
|
1205
|
-
if (!id.trim() || id.toLowerCase() === 'cancel') {
|
|
1206
|
-
console.log(colors.info('Delete cancelled'))
|
|
1207
|
-
process.exit(0)
|
|
1208
|
-
}
|
|
1209
|
-
|
|
1210
|
-
// Confirm deletion in interactive mode
|
|
1211
|
-
const confirmRl = createInterface({
|
|
1212
|
-
input: process.stdin,
|
|
1213
|
-
output: process.stdout
|
|
1214
|
-
})
|
|
1215
|
-
|
|
1216
|
-
const confirm = await new Promise(resolve => {
|
|
1217
|
-
const deleteType = options.hard ? 'permanently delete' : 'soft delete'
|
|
1218
|
-
confirmRl.question(colors.warning(`Are you sure you want to ${deleteType} "${id}"? (yes/no): `), (answer) => {
|
|
1219
|
-
confirmRl.close()
|
|
1220
|
-
resolve(answer.toLowerCase() === 'yes' || answer.toLowerCase() === 'y')
|
|
1221
|
-
})
|
|
1222
|
-
})
|
|
1223
|
-
|
|
1224
|
-
if (!confirm) {
|
|
1225
|
-
console.log(colors.info('Delete cancelled'))
|
|
1226
|
-
process.exit(0)
|
|
1227
|
-
}
|
|
1228
|
-
}
|
|
1229
|
-
console.log(colors.info(`šļø Deleting: "${id}"`))
|
|
1230
|
-
|
|
1231
|
-
if (options.hard) {
|
|
1232
|
-
console.log(colors.warning('ā ļø Hard delete - data will be permanently removed'))
|
|
1233
|
-
} else {
|
|
1234
|
-
console.log(colors.info('š Soft delete - data marked as deleted but preserved'))
|
|
1235
|
-
}
|
|
1236
|
-
|
|
1237
|
-
const brainyInstance = await getBrainy()
|
|
1238
|
-
|
|
1239
|
-
try {
|
|
1240
|
-
const success = await brainyInstance.deleteNoun(id, {
|
|
1241
|
-
soft: !options.hard, // Soft delete unless --hard specified
|
|
1242
|
-
cascade: options.cascade || false,
|
|
1243
|
-
force: options.force || false
|
|
1244
|
-
})
|
|
1245
|
-
|
|
1246
|
-
if (success) {
|
|
1247
|
-
console.log(colors.success('ā
Deleted successfully!'))
|
|
1248
|
-
if (options.cascade) {
|
|
1249
|
-
console.log(colors.info('š Related verbs also deleted'))
|
|
1250
|
-
}
|
|
1251
|
-
} else {
|
|
1252
|
-
console.log(colors.error('ā Delete failed'))
|
|
1253
|
-
}
|
|
1254
|
-
} catch (error) {
|
|
1255
|
-
console.error(colors.error(`ā Delete failed: ${error.message}`))
|
|
1256
|
-
if (error.message.includes('has relationships')) {
|
|
1257
|
-
console.log(colors.info('š” Try: --cascade to delete relationships or --force to ignore them'))
|
|
1258
|
-
}
|
|
1259
|
-
}
|
|
1260
|
-
}))
|
|
1261
|
-
|
|
1262
|
-
// Command 6A: ADD-NOUN - Create typed entities (Method #4)
|
|
1263
|
-
program
|
|
1264
|
-
.command('add-noun [name]')
|
|
1265
|
-
.description('Add a typed entity to your knowledge graph')
|
|
1266
|
-
.option('-t, --type <type>', 'Noun type (Person, Organization, Project, Event, Concept, Location, Product)', 'Concept')
|
|
1267
|
-
.option('-m, --metadata <json>', 'Metadata as JSON')
|
|
1268
|
-
.option('--encrypt', 'Encrypt this entity')
|
|
1269
|
-
.action(wrapAction(async (name, options) => {
|
|
1270
|
-
|
|
1271
|
-
// Interactive mode if no name provided
|
|
1272
|
-
if (!name) {
|
|
1273
|
-
console.log(colors.primary('š¤ Interactive Entity Creation'))
|
|
1274
|
-
console.log(colors.dim('Create a typed entity in your knowledge graph\n'))
|
|
1275
|
-
|
|
1276
|
-
const rl = createInterface({
|
|
1277
|
-
input: process.stdin,
|
|
1278
|
-
output: process.stdout
|
|
1279
|
-
})
|
|
1280
|
-
|
|
1281
|
-
name = await new Promise(resolve => {
|
|
1282
|
-
rl.question(colors.cyan('Enter entity name: '), (answer) => {
|
|
1283
|
-
resolve(answer)
|
|
1284
|
-
})
|
|
1285
|
-
})
|
|
1286
|
-
|
|
1287
|
-
if (!name.trim()) {
|
|
1288
|
-
rl.close()
|
|
1289
|
-
console.log(colors.warning('No name provided'))
|
|
1290
|
-
process.exit(1)
|
|
1291
|
-
}
|
|
1292
|
-
|
|
1293
|
-
// Interactive type selection if not provided
|
|
1294
|
-
if (!options.type || options.type === 'Concept') {
|
|
1295
|
-
console.log(colors.cyan('\nSelect entity type:'))
|
|
1296
|
-
const types = ['Person', 'Organization', 'Project', 'Event', 'Concept', 'Location', 'Product']
|
|
1297
|
-
types.forEach((t, i) => {
|
|
1298
|
-
console.log(colors.info(` ${i + 1}. ${t}`))
|
|
1299
|
-
})
|
|
1300
|
-
console.log()
|
|
1301
|
-
|
|
1302
|
-
const typeIndex = await new Promise(resolve => {
|
|
1303
|
-
rl.question(colors.cyan('Select type (1-7): '), (answer) => {
|
|
1304
|
-
resolve(parseInt(answer) - 1)
|
|
1305
|
-
})
|
|
1306
|
-
})
|
|
1307
|
-
|
|
1308
|
-
if (typeIndex >= 0 && typeIndex < types.length) {
|
|
1309
|
-
options.type = types[typeIndex]
|
|
1310
|
-
}
|
|
1311
|
-
}
|
|
1312
|
-
|
|
1313
|
-
rl.close()
|
|
1314
|
-
}
|
|
1315
|
-
const brainy = await getBrainy()
|
|
1316
|
-
|
|
1317
|
-
// Validate noun type
|
|
1318
|
-
const validTypes = ['Person', 'Organization', 'Project', 'Event', 'Concept', 'Location', 'Product']
|
|
1319
|
-
if (!validTypes.includes(options.type)) {
|
|
1320
|
-
console.log(colors.error(`ā Invalid noun type: ${options.type}`))
|
|
1321
|
-
console.log(colors.info(`Valid types: ${validTypes.join(', ')}`))
|
|
1322
|
-
process.exit(1)
|
|
1323
|
-
}
|
|
1324
|
-
|
|
1325
|
-
let metadata = {}
|
|
1326
|
-
if (options.metadata) {
|
|
1327
|
-
try {
|
|
1328
|
-
metadata = JSON.parse(options.metadata)
|
|
1329
|
-
} catch {
|
|
1330
|
-
console.error(colors.error('ā Invalid JSON metadata'))
|
|
1331
|
-
process.exit(1)
|
|
1332
|
-
}
|
|
1333
|
-
}
|
|
1334
|
-
|
|
1335
|
-
if (options.encrypt) {
|
|
1336
|
-
metadata.encrypted = true
|
|
1337
|
-
}
|
|
1338
|
-
|
|
1339
|
-
try {
|
|
1340
|
-
// Use modern 3.0 API with parameter object
|
|
1341
|
-
const id = await brainy.add({ data: name, type: options.type, metadata })
|
|
1342
|
-
|
|
1343
|
-
console.log(colors.success('ā
Noun added successfully!'))
|
|
1344
|
-
console.log(colors.info(`š ID: ${id}`))
|
|
1345
|
-
console.log(colors.info(`š¤ Name: ${name}`))
|
|
1346
|
-
console.log(colors.info(`š·ļø Type: ${options.type}`))
|
|
1347
|
-
if (Object.keys(metadata).length > 0) {
|
|
1348
|
-
console.log(colors.info(`š Metadata: ${JSON.stringify(metadata, null, 2)}`))
|
|
1349
|
-
}
|
|
1350
|
-
} catch (error) {
|
|
1351
|
-
console.log(colors.error('ā Failed to add noun:'))
|
|
1352
|
-
console.log(colors.error(error.message))
|
|
1353
|
-
process.exit(1)
|
|
1354
|
-
}
|
|
1355
|
-
}))
|
|
1356
|
-
|
|
1357
|
-
// Command 6B: ADD-VERB - Create relationships (Method #5)
|
|
1358
|
-
program
|
|
1359
|
-
.command('add-verb [source] [target]')
|
|
1360
|
-
.description('Create a relationship between two entities')
|
|
1361
|
-
.option('-t, --type <type>', 'Verb type (WorksFor, Knows, CreatedBy, BelongsTo, Uses, etc.)', 'RelatedTo')
|
|
1362
|
-
.option('-m, --metadata <json>', 'Relationship metadata as JSON')
|
|
1363
|
-
.option('--encrypt', 'Encrypt this relationship')
|
|
1364
|
-
.action(wrapAction(async (source, target, options) => {
|
|
1365
|
-
|
|
1366
|
-
// Interactive mode if parameters missing
|
|
1367
|
-
if (!source || !target) {
|
|
1368
|
-
console.log(colors.primary('š Interactive Relationship Builder'))
|
|
1369
|
-
console.log(colors.dim('Connect two entities with a semantic relationship\n'))
|
|
1370
|
-
|
|
1371
|
-
const brainyInstance = await getBrainy()
|
|
1372
|
-
const rl = createInterface({
|
|
1373
|
-
input: process.stdin,
|
|
1374
|
-
output: process.stdout
|
|
1375
|
-
})
|
|
1376
|
-
|
|
1377
|
-
// Get source if not provided
|
|
1378
|
-
if (!source) {
|
|
1379
|
-
// Show recent items
|
|
1380
|
-
const recent = await brainyInstance.search('*', { limit: 10, sortBy: 'timestamp' })
|
|
1381
|
-
if (recent.length > 0) {
|
|
1382
|
-
console.log(colors.cyan('Recent items (source):'))
|
|
1383
|
-
|
|
1384
|
-
// Enhanced display for recent items
|
|
1385
|
-
for (let i = 0; i < Math.min(recent.length, 10); i++) {
|
|
1386
|
-
const item = recent[i]
|
|
1387
|
-
try {
|
|
1388
|
-
if (item.getDisplay && typeof item.getDisplay === 'function') {
|
|
1389
|
-
const displayFields = await item.getDisplay()
|
|
1390
|
-
console.log(colors.info(` ${i + 1}. ${displayFields.icon} ${item.id} - ${displayFields.title}`))
|
|
1391
|
-
} else {
|
|
1392
|
-
console.log(colors.info(` ${i + 1}. ${item.id} - ${item.content?.substring(0, 40)}...`))
|
|
1393
|
-
}
|
|
1394
|
-
} catch {
|
|
1395
|
-
console.log(colors.info(` ${i + 1}. ${item.id} - ${item.content?.substring(0, 40)}...`))
|
|
1396
|
-
}
|
|
1397
|
-
}
|
|
1398
|
-
console.log()
|
|
1399
|
-
}
|
|
1400
|
-
|
|
1401
|
-
source = await new Promise(resolve => {
|
|
1402
|
-
rl.question(colors.cyan('Enter source entity ID: '), (answer) => {
|
|
1403
|
-
resolve(answer)
|
|
1404
|
-
})
|
|
1405
|
-
})
|
|
1406
|
-
|
|
1407
|
-
if (!source.trim()) {
|
|
1408
|
-
rl.close()
|
|
1409
|
-
console.log(colors.warning('No source provided'))
|
|
1410
|
-
process.exit(1)
|
|
1411
|
-
}
|
|
1412
|
-
}
|
|
1413
|
-
|
|
1414
|
-
// Interactive verb type selection
|
|
1415
|
-
if (!options.type || options.type === 'RelatedTo') {
|
|
1416
|
-
console.log(colors.cyan('\nSelect relationship type:'))
|
|
1417
|
-
const verbs = ['WorksFor', 'Knows', 'CreatedBy', 'BelongsTo', 'Uses', 'Manages', 'LocatedIn', 'RelatedTo', 'Custom...']
|
|
1418
|
-
verbs.forEach((v, i) => {
|
|
1419
|
-
console.log(colors.info(` ${i + 1}. ${v}`))
|
|
1420
|
-
})
|
|
1421
|
-
console.log()
|
|
1422
|
-
|
|
1423
|
-
const verbIndex = await new Promise(resolve => {
|
|
1424
|
-
rl.question(colors.cyan('Select type (1-9): '), (answer) => {
|
|
1425
|
-
resolve(parseInt(answer) - 1)
|
|
1426
|
-
})
|
|
1427
|
-
})
|
|
1428
|
-
|
|
1429
|
-
if (verbIndex >= 0 && verbIndex < verbs.length - 1) {
|
|
1430
|
-
options.type = verbs[verbIndex]
|
|
1431
|
-
} else if (verbIndex === verbs.length - 1) {
|
|
1432
|
-
// Custom verb
|
|
1433
|
-
options.type = await new Promise(resolve => {
|
|
1434
|
-
rl.question(colors.cyan('Enter custom relationship: '), (answer) => {
|
|
1435
|
-
resolve(answer)
|
|
1436
|
-
})
|
|
1437
|
-
})
|
|
1438
|
-
}
|
|
1439
|
-
}
|
|
1440
|
-
|
|
1441
|
-
// Get target if not provided
|
|
1442
|
-
if (!target) {
|
|
1443
|
-
// Show recent items again
|
|
1444
|
-
const recent = await brainyInstance.search('*', { limit: 10, sortBy: 'timestamp' })
|
|
1445
|
-
if (recent.length > 0) {
|
|
1446
|
-
console.log(colors.cyan('\nRecent items (target):'))
|
|
1447
|
-
|
|
1448
|
-
// Enhanced display for recent items
|
|
1449
|
-
for (let i = 0; i < Math.min(recent.length, 10); i++) {
|
|
1450
|
-
const item = recent[i]
|
|
1451
|
-
try {
|
|
1452
|
-
if (item.getDisplay && typeof item.getDisplay === 'function') {
|
|
1453
|
-
const displayFields = await item.getDisplay()
|
|
1454
|
-
console.log(colors.info(` ${i + 1}. ${displayFields.icon} ${item.id} - ${displayFields.title}`))
|
|
1455
|
-
} else {
|
|
1456
|
-
console.log(colors.info(` ${i + 1}. ${item.id} - ${item.content?.substring(0, 40)}...`))
|
|
1457
|
-
}
|
|
1458
|
-
} catch {
|
|
1459
|
-
console.log(colors.info(` ${i + 1}. ${item.id} - ${item.content?.substring(0, 40)}...`))
|
|
1460
|
-
}
|
|
1461
|
-
}
|
|
1462
|
-
console.log()
|
|
1463
|
-
}
|
|
1464
|
-
|
|
1465
|
-
target = await new Promise(resolve => {
|
|
1466
|
-
rl.question(colors.cyan('Enter target entity ID: '), (answer) => {
|
|
1467
|
-
resolve(answer)
|
|
1468
|
-
})
|
|
1469
|
-
})
|
|
1470
|
-
|
|
1471
|
-
if (!target.trim()) {
|
|
1472
|
-
rl.close()
|
|
1473
|
-
console.log(colors.warning('No target provided'))
|
|
1474
|
-
process.exit(1)
|
|
1475
|
-
}
|
|
1476
|
-
}
|
|
1477
|
-
|
|
1478
|
-
rl.close()
|
|
1479
|
-
}
|
|
1480
|
-
const brainy = await getBrainy()
|
|
1481
|
-
|
|
1482
|
-
// Common verb types for validation
|
|
1483
|
-
const commonTypes = ['WorksFor', 'Knows', 'CreatedBy', 'BelongsTo', 'Uses', 'LeadsProject', 'MemberOf', 'RelatedTo', 'InteractedWith']
|
|
1484
|
-
if (!commonTypes.includes(options.type)) {
|
|
1485
|
-
console.log(colors.warning(`ā ļø Uncommon verb type: ${options.type}`))
|
|
1486
|
-
console.log(colors.info(`Common types: ${commonTypes.join(', ')}`))
|
|
1487
|
-
}
|
|
1488
|
-
|
|
1489
|
-
let metadata = {}
|
|
1490
|
-
if (options.metadata) {
|
|
1491
|
-
try {
|
|
1492
|
-
metadata = JSON.parse(options.metadata)
|
|
1493
|
-
} catch {
|
|
1494
|
-
console.error(colors.error('ā Invalid JSON metadata'))
|
|
1495
|
-
process.exit(1)
|
|
1496
|
-
}
|
|
1497
|
-
}
|
|
1498
|
-
|
|
1499
|
-
if (options.encrypt) {
|
|
1500
|
-
metadata.encrypted = true
|
|
1501
|
-
}
|
|
1502
|
-
|
|
1503
|
-
try {
|
|
1504
|
-
const { VerbType } = await import('../dist/types/graphTypes.js')
|
|
1505
|
-
|
|
1506
|
-
// Use the provided type or fall back to RelatedTo
|
|
1507
|
-
const verbType = VerbType[options.type] || options.type
|
|
1508
|
-
const id = await brainy.relate({ from: source, to: target, type: verbType, metadata })
|
|
1509
|
-
|
|
1510
|
-
console.log(colors.success('ā
Relationship added successfully!'))
|
|
1511
|
-
console.log(colors.info(`š ID: ${id}`))
|
|
1512
|
-
console.log(colors.info(`š ${source} --[${options.type}]--> ${target}`))
|
|
1513
|
-
if (Object.keys(metadata).length > 0) {
|
|
1514
|
-
console.log(colors.info(`š Metadata: ${JSON.stringify(metadata, null, 2)}`))
|
|
1515
|
-
}
|
|
1516
|
-
} catch (error) {
|
|
1517
|
-
console.log(colors.error('ā Failed to add relationship:'))
|
|
1518
|
-
console.log(colors.error(error.message))
|
|
1519
|
-
process.exit(1)
|
|
1520
|
-
}
|
|
1521
|
-
}))
|
|
1522
|
-
|
|
1523
|
-
// Command 7: STATUS - Database health & info
|
|
1524
|
-
program
|
|
1525
|
-
.command('status')
|
|
1526
|
-
.description('Show brain status and comprehensive statistics')
|
|
1527
|
-
.option('-v, --verbose', 'Show raw JSON statistics')
|
|
1528
|
-
.option('-s, --simple', 'Show only basic info')
|
|
1529
|
-
.action(wrapAction(async (options) => {
|
|
1530
|
-
console.log(colors.primary('š§ Brain Status & Statistics'))
|
|
1531
|
-
console.log(colors.primary('=' .repeat(50)))
|
|
1532
|
-
|
|
1533
|
-
try {
|
|
1534
|
-
const { BrainyData } = await import('../dist/brainyData.js')
|
|
1535
|
-
const brainy = new BrainyData()
|
|
1536
|
-
await brainy.init()
|
|
1537
|
-
|
|
1538
|
-
// Get comprehensive stats
|
|
1539
|
-
const stats = await brainy.getStatistics()
|
|
1540
|
-
const memUsage = process.memoryUsage()
|
|
1541
|
-
|
|
1542
|
-
// Basic Health Status
|
|
1543
|
-
console.log(colors.success('š Status: Healthy'))
|
|
1544
|
-
console.log(colors.info(`š Version: ${packageJson.version}`))
|
|
1545
|
-
console.log()
|
|
1546
|
-
|
|
1547
|
-
if (options.simple) {
|
|
1548
|
-
console.log(colors.info(`š Total Items: ${stats.total || 0}`))
|
|
1549
|
-
console.log(colors.info(`š§ Memory: ${(memUsage.heapUsed / 1024 / 1024).toFixed(1)} MB`))
|
|
1550
|
-
return
|
|
1551
|
-
}
|
|
1552
|
-
|
|
1553
|
-
// Core Statistics
|
|
1554
|
-
console.log(colors.primary('š Core Database Statistics'))
|
|
1555
|
-
console.log(colors.info(` Total Items: ${colors.success(stats.total || 0)}`))
|
|
1556
|
-
console.log(colors.info(` Nouns: ${colors.success(stats.nounCount || 0)}`))
|
|
1557
|
-
console.log(colors.info(` Verbs (Relationships): ${colors.success(stats.verbCount || 0)}`))
|
|
1558
|
-
console.log(colors.info(` Metadata Records: ${colors.success(stats.metadataCount || 0)}`))
|
|
1559
|
-
console.log()
|
|
1560
|
-
|
|
1561
|
-
// Per-Service Breakdown (if available)
|
|
1562
|
-
if (stats.serviceBreakdown && Object.keys(stats.serviceBreakdown).length > 0) {
|
|
1563
|
-
console.log(colors.primary('š§ Per-Service Breakdown'))
|
|
1564
|
-
Object.entries(stats.serviceBreakdown).forEach(([service, serviceStats]) => {
|
|
1565
|
-
console.log(colors.info(` ${colors.success(service)}:`))
|
|
1566
|
-
console.log(colors.info(` Nouns: ${serviceStats.nounCount}`))
|
|
1567
|
-
console.log(colors.info(` Verbs: ${serviceStats.verbCount}`))
|
|
1568
|
-
console.log(colors.info(` Metadata: ${serviceStats.metadataCount}`))
|
|
1569
|
-
})
|
|
1570
|
-
console.log()
|
|
1571
|
-
}
|
|
1572
|
-
|
|
1573
|
-
// Storage Information
|
|
1574
|
-
if (stats.storage) {
|
|
1575
|
-
console.log(colors.primary('š¾ Storage Information'))
|
|
1576
|
-
console.log(colors.info(` Type: ${colors.success(stats.storage.type || 'Unknown')}`))
|
|
1577
|
-
if (stats.storage.size) {
|
|
1578
|
-
const sizeInMB = (stats.storage.size / 1024 / 1024).toFixed(2)
|
|
1579
|
-
console.log(colors.info(` Size: ${colors.success(sizeInMB)} MB`))
|
|
1580
|
-
}
|
|
1581
|
-
if (stats.storage.location) {
|
|
1582
|
-
console.log(colors.info(` Location: ${colors.success(stats.storage.location)}`))
|
|
1583
|
-
}
|
|
1584
|
-
console.log()
|
|
1585
|
-
}
|
|
1586
|
-
|
|
1587
|
-
// Performance Metrics
|
|
1588
|
-
if (stats.performance) {
|
|
1589
|
-
console.log(colors.primary('ā” Performance Metrics'))
|
|
1590
|
-
if (stats.performance.avgQueryTime) {
|
|
1591
|
-
console.log(colors.info(` Avg Query Time: ${colors.success(stats.performance.avgQueryTime.toFixed(2))} ms`))
|
|
1592
|
-
}
|
|
1593
|
-
if (stats.performance.totalQueries) {
|
|
1594
|
-
console.log(colors.info(` Total Queries: ${colors.success(stats.performance.totalQueries)}`))
|
|
1595
|
-
}
|
|
1596
|
-
if (stats.performance.cacheHitRate) {
|
|
1597
|
-
console.log(colors.info(` Cache Hit Rate: ${colors.success((stats.performance.cacheHitRate * 100).toFixed(1))}%`))
|
|
1598
|
-
}
|
|
1599
|
-
console.log()
|
|
1600
|
-
}
|
|
1601
|
-
|
|
1602
|
-
// Vector Index Information
|
|
1603
|
-
if (stats.index) {
|
|
1604
|
-
console.log(colors.primary('šÆ Vector Index'))
|
|
1605
|
-
console.log(colors.info(` Dimensions: ${colors.success(stats.index.dimensions || 'N/A')}`))
|
|
1606
|
-
console.log(colors.info(` Indexed Vectors: ${colors.success(stats.index.vectorCount || 0)}`))
|
|
1607
|
-
if (stats.index.indexSize) {
|
|
1608
|
-
console.log(colors.info(` Index Size: ${colors.success((stats.index.indexSize / 1024 / 1024).toFixed(2))} MB`))
|
|
1609
|
-
}
|
|
1610
|
-
console.log()
|
|
1611
|
-
}
|
|
1612
|
-
|
|
1613
|
-
// Memory Usage Breakdown
|
|
1614
|
-
console.log(colors.primary('š§ Memory Usage'))
|
|
1615
|
-
console.log(colors.info(` Heap Used: ${colors.success((memUsage.heapUsed / 1024 / 1024).toFixed(1))} MB`))
|
|
1616
|
-
console.log(colors.info(` Heap Total: ${colors.success((memUsage.heapTotal / 1024 / 1024).toFixed(1))} MB`))
|
|
1617
|
-
console.log(colors.info(` RSS: ${colors.success((memUsage.rss / 1024 / 1024).toFixed(1))} MB`))
|
|
1618
|
-
console.log()
|
|
1619
|
-
|
|
1620
|
-
// Active Augmentations
|
|
1621
|
-
console.log(colors.primary('š Active Augmentations'))
|
|
1622
|
-
try {
|
|
1623
|
-
// Check for display augmentation specifically
|
|
1624
|
-
const displayAugmentation = (brainy as any).augmentations?.get('display')
|
|
1625
|
-
if (displayAugmentation) {
|
|
1626
|
-
console.log(colors.success(` ā
display - Universal Display Augmentation`))
|
|
1627
|
-
console.log(colors.info(` šØ AI-powered titles and descriptions`))
|
|
1628
|
-
|
|
1629
|
-
// Get display augmentation stats if available
|
|
1630
|
-
if (displayAugmentation.getStats) {
|
|
1631
|
-
const stats = displayAugmentation.getStats()
|
|
1632
|
-
if (stats.totalComputations > 0) {
|
|
1633
|
-
console.log(colors.dim(` š ${stats.totalComputations} computations, ${(stats.cacheHitRatio * 100).toFixed(1)}% cache hit rate`))
|
|
1634
|
-
}
|
|
1635
|
-
}
|
|
1636
|
-
}
|
|
1637
|
-
|
|
1638
|
-
// Show other augmentations
|
|
1639
|
-
const otherAugs = (brainy as any).augmentations ?
|
|
1640
|
-
Array.from((brainy as any).augmentations.values()).filter((aug: any) => aug.name !== 'display') :
|
|
1641
|
-
[]
|
|
1642
|
-
|
|
1643
|
-
otherAugs.forEach((aug: any) => {
|
|
1644
|
-
console.log(colors.success(` ā
${aug.name}`))
|
|
1645
|
-
if (aug.version) {
|
|
1646
|
-
console.log(colors.info(` v${aug.version} - ${aug.description || 'No description'}`))
|
|
1647
|
-
}
|
|
1648
|
-
})
|
|
1649
|
-
|
|
1650
|
-
if (!displayAugmentation && otherAugs.length === 0) {
|
|
1651
|
-
console.log(colors.warning(' No augmentations currently active'))
|
|
1652
|
-
}
|
|
1653
|
-
} catch (error) {
|
|
1654
|
-
console.log(colors.warning(' Augmentation status unavailable'))
|
|
1655
|
-
}
|
|
1656
|
-
console.log()
|
|
1657
|
-
|
|
1658
|
-
// Configuration Summary
|
|
1659
|
-
if (stats.config) {
|
|
1660
|
-
console.log(colors.primary('āļø Configuration'))
|
|
1661
|
-
Object.entries(stats.config).forEach(([key, value]) => {
|
|
1662
|
-
// Don't show sensitive values
|
|
1663
|
-
if (key.toLowerCase().includes('key') || key.toLowerCase().includes('secret')) {
|
|
1664
|
-
console.log(colors.info(` ${key}: ${colors.warning('[HIDDEN]')}`))
|
|
1665
|
-
} else {
|
|
1666
|
-
console.log(colors.info(` ${key}: ${colors.success(value)}`))
|
|
1667
|
-
}
|
|
1668
|
-
})
|
|
1669
|
-
console.log()
|
|
1670
|
-
}
|
|
1671
|
-
|
|
1672
|
-
// Available Fields for Advanced Search
|
|
1673
|
-
console.log(colors.primary('š Available Search Fields'))
|
|
1674
|
-
try {
|
|
1675
|
-
const filterFields = await brainy.getFilterFields()
|
|
1676
|
-
if (filterFields.length > 0) {
|
|
1677
|
-
console.log(colors.info(' Use these fields for advanced filtering:'))
|
|
1678
|
-
filterFields.forEach(field => {
|
|
1679
|
-
console.log(colors.success(` ${field}`))
|
|
1680
|
-
})
|
|
1681
|
-
console.log(colors.info('\n Example: brainy search "query" --filter \'{"type":"person"}\''))
|
|
1682
|
-
} else {
|
|
1683
|
-
console.log(colors.warning(' No indexed fields available yet'))
|
|
1684
|
-
console.log(colors.info(' Add some data to see available fields'))
|
|
1685
|
-
}
|
|
1686
|
-
} catch (error) {
|
|
1687
|
-
console.log(colors.warning(' Field discovery not available'))
|
|
1688
|
-
}
|
|
1689
|
-
console.log()
|
|
1690
|
-
|
|
1691
|
-
// Show raw JSON if verbose
|
|
1692
|
-
if (options.verbose) {
|
|
1693
|
-
console.log(colors.primary('š Raw Statistics (JSON)'))
|
|
1694
|
-
console.log(colors.info(JSON.stringify(stats, null, 2)))
|
|
1695
|
-
}
|
|
1696
|
-
|
|
1697
|
-
} catch (error) {
|
|
1698
|
-
console.log(colors.error('ā Status: Error'))
|
|
1699
|
-
console.log(colors.error(`Error: ${error.message}`))
|
|
1700
|
-
if (options.verbose) {
|
|
1701
|
-
console.log(colors.error('Stack trace:'))
|
|
1702
|
-
console.log(error.stack)
|
|
1703
|
-
}
|
|
1704
|
-
}
|
|
1705
|
-
}))
|
|
1706
|
-
|
|
1707
|
-
// Command 5: CONFIG - Essential configuration
|
|
1708
|
-
program
|
|
1709
|
-
.command('config <action> [key] [value]')
|
|
1710
|
-
.description('Configure brainy (get, set, list)')
|
|
1711
|
-
.action(wrapAction(async (action, key, value) => {
|
|
1712
|
-
const configActions = {
|
|
1713
|
-
get: async () => {
|
|
1714
|
-
if (!key) {
|
|
1715
|
-
console.error(colors.error('Please specify a key: brainy config get <key>'))
|
|
1716
|
-
process.exit(1)
|
|
1717
|
-
}
|
|
1718
|
-
const result = await cortex.configGet(key)
|
|
1719
|
-
console.log(colors.success(`${key}: ${result || 'not set'}`))
|
|
1720
|
-
},
|
|
1721
|
-
set: async () => {
|
|
1722
|
-
if (!key || !value) {
|
|
1723
|
-
console.error(colors.error('Usage: brainy config set <key> <value>'))
|
|
1724
|
-
process.exit(1)
|
|
1725
|
-
}
|
|
1726
|
-
await cortex.configSet(key, value)
|
|
1727
|
-
console.log(colors.success(`ā
Set ${key} = ${value}`))
|
|
1728
|
-
},
|
|
1729
|
-
list: async () => {
|
|
1730
|
-
const config = await cortex.configList()
|
|
1731
|
-
console.log(colors.primary('š§ Current Configuration:'))
|
|
1732
|
-
Object.entries(config).forEach(([k, v]) => {
|
|
1733
|
-
console.log(colors.info(` ${k}: ${v}`))
|
|
1734
|
-
})
|
|
1735
|
-
}
|
|
1736
|
-
}
|
|
1737
|
-
|
|
1738
|
-
if (configActions[action]) {
|
|
1739
|
-
await configActions[action]()
|
|
1740
|
-
} else {
|
|
1741
|
-
console.error(colors.error('Valid actions: get, set, list'))
|
|
1742
|
-
process.exit(1)
|
|
1743
|
-
}
|
|
1744
|
-
}))
|
|
1745
|
-
|
|
1746
|
-
// Command 6: AUGMENT - Manage augmentations (The 8th Unified Method!)
|
|
1747
|
-
program
|
|
1748
|
-
.command('augment <action>')
|
|
1749
|
-
.description('Manage augmentations to extend Brainy\'s capabilities')
|
|
1750
|
-
.option('-n, --name <name>', 'Augmentation name')
|
|
1751
|
-
.option('-t, --type <type>', 'Augmentation type (sense, conduit, cognition, memory)')
|
|
1752
|
-
.option('-p, --path <path>', 'Path to augmentation module')
|
|
1753
|
-
.option('-l, --list', 'List all augmentations')
|
|
1754
|
-
.action(wrapAction(async (action, options) => {
|
|
1755
|
-
const brainy = await initBrainy()
|
|
1756
|
-
console.log(colors.brain('š§© Augmentation Management'))
|
|
1757
|
-
|
|
1758
|
-
const actions = {
|
|
1759
|
-
list: async () => {
|
|
1760
|
-
try {
|
|
1761
|
-
// Use soulcraft.com registry API
|
|
1762
|
-
const REGISTRY_URL = 'https://api.soulcraft.com/v1/augmentations'
|
|
1763
|
-
const response = await fetch(REGISTRY_URL)
|
|
1764
|
-
|
|
1765
|
-
if (response && response.ok) {
|
|
1766
|
-
console.log(colors.brain('š¢ SOULCRAFT PROFESSIONAL SUITE\n'))
|
|
1767
|
-
|
|
1768
|
-
const data = await response.json()
|
|
1769
|
-
const augmentations = data.data || [] // NEW: data is in .data array
|
|
1770
|
-
|
|
1771
|
-
// Get local augmentations to check what's installed
|
|
1772
|
-
const localAugmentations = brainy.listAugmentations()
|
|
1773
|
-
const localPackageNames = localAugmentations.map(aug => aug.package || aug.name).filter(Boolean)
|
|
1774
|
-
|
|
1775
|
-
// Find installed registry augmentations
|
|
1776
|
-
const installed = augmentations.filter(aug =>
|
|
1777
|
-
aug.package && localPackageNames.includes(aug.package)
|
|
1778
|
-
)
|
|
1779
|
-
|
|
1780
|
-
// Display installed augmentations first
|
|
1781
|
-
if (installed.length > 0) {
|
|
1782
|
-
console.log(colors.success('ā
INSTALLED AUGMENTATIONS'))
|
|
1783
|
-
installed.forEach(aug => {
|
|
1784
|
-
const pricing = aug.price
|
|
1785
|
-
? `$${aug.price.monthly}/mo`
|
|
1786
|
-
: (aug.tier === 'free' ? 'FREE' : 'TBD')
|
|
1787
|
-
const pricingColor = aug.tier === 'free' ? colors.success(pricing) : colors.yellow(pricing)
|
|
1788
|
-
|
|
1789
|
-
console.log(` ${aug.name.padEnd(20)} ${pricingColor.padEnd(15)} ${colors.success('ā
ACTIVE')}`)
|
|
1790
|
-
console.log(` ${colors.dim(aug.description)}`)
|
|
1791
|
-
console.log('')
|
|
1792
|
-
})
|
|
1793
|
-
console.log('') // Extra space before available augmentations
|
|
1794
|
-
}
|
|
1795
|
-
|
|
1796
|
-
// Filter out installed ones from the available lists
|
|
1797
|
-
const availableAugmentations = augmentations.filter(aug =>
|
|
1798
|
-
!installed.find(inst => inst.id === aug.id)
|
|
1799
|
-
)
|
|
1800
|
-
|
|
1801
|
-
// NEW: Use new tier names - "premium" instead of "professional"
|
|
1802
|
-
const premium = availableAugmentations.filter(a => a.tier === 'premium')
|
|
1803
|
-
const free = availableAugmentations.filter(a => a.tier === 'free')
|
|
1804
|
-
const community = availableAugmentations.filter(a => a.tier === 'community')
|
|
1805
|
-
const comingSoon = availableAugmentations.filter(a => a.status === 'coming_soon')
|
|
1806
|
-
|
|
1807
|
-
// Display premium augmentations
|
|
1808
|
-
if (premium.length > 0) {
|
|
1809
|
-
console.log(colors.primary('š PREMIUM AUGMENTATIONS'))
|
|
1810
|
-
premium.forEach(aug => {
|
|
1811
|
-
// NEW: price object format
|
|
1812
|
-
const pricing = aug.price
|
|
1813
|
-
? `$${aug.price.monthly}/mo`
|
|
1814
|
-
: (aug.tier === 'free' ? 'FREE' : 'TBD')
|
|
1815
|
-
const pricingColor = aug.tier === 'free' ? colors.success(pricing) : colors.yellow(pricing)
|
|
1816
|
-
|
|
1817
|
-
// NEW: status instead of verified
|
|
1818
|
-
const status = aug.status === 'available' ? colors.blue('ā') :
|
|
1819
|
-
aug.status === 'coming_soon' ? colors.yellow('ā³') :
|
|
1820
|
-
colors.dim('ā¢')
|
|
1821
|
-
|
|
1822
|
-
console.log(` ${aug.name.padEnd(20)} ${pricingColor.padEnd(15)} ${status}`)
|
|
1823
|
-
console.log(` ${colors.dim(aug.description)}`)
|
|
1824
|
-
|
|
1825
|
-
if (aug.status === 'coming_soon' && aug.eta) {
|
|
1826
|
-
console.log(` ${colors.cyan('ā Coming ' + aug.eta)}`)
|
|
1827
|
-
}
|
|
1828
|
-
|
|
1829
|
-
if (aug.features && aug.features.length > 0) {
|
|
1830
|
-
console.log(` ${colors.cyan('ā ' + aug.features.join(', '))}`)
|
|
1831
|
-
}
|
|
1832
|
-
console.log('')
|
|
1833
|
-
})
|
|
1834
|
-
}
|
|
1835
|
-
|
|
1836
|
-
// Display free augmentations
|
|
1837
|
-
if (free.length > 0) {
|
|
1838
|
-
console.log(colors.primary('š FREE AUGMENTATIONS'))
|
|
1839
|
-
free.forEach(aug => {
|
|
1840
|
-
const status = aug.status === 'available' ? colors.blue('ā') :
|
|
1841
|
-
aug.status === 'coming_soon' ? colors.yellow('ā³') :
|
|
1842
|
-
colors.dim('ā¢')
|
|
1843
|
-
|
|
1844
|
-
console.log(` ${aug.name.padEnd(20)} ${colors.success('FREE').padEnd(15)} ${status}`)
|
|
1845
|
-
console.log(` ${colors.dim(aug.description)}`)
|
|
1846
|
-
|
|
1847
|
-
if (aug.status === 'coming_soon' && aug.eta) {
|
|
1848
|
-
console.log(` ${colors.cyan('ā Coming ' + aug.eta)}`)
|
|
1849
|
-
}
|
|
1850
|
-
console.log('')
|
|
1851
|
-
})
|
|
1852
|
-
}
|
|
1853
|
-
|
|
1854
|
-
// Display community augmentations
|
|
1855
|
-
if (community.length > 0) {
|
|
1856
|
-
console.log(colors.primary('š„ COMMUNITY AUGMENTATIONS'))
|
|
1857
|
-
community.forEach(aug => {
|
|
1858
|
-
const status = aug.status === 'available' ? colors.blue('ā') :
|
|
1859
|
-
aug.status === 'coming_soon' ? colors.yellow('ā³') :
|
|
1860
|
-
colors.dim('ā¢')
|
|
1861
|
-
|
|
1862
|
-
console.log(` ${aug.name.padEnd(20)} ${colors.success('COMMUNITY').padEnd(15)} ${status}`)
|
|
1863
|
-
console.log(` ${colors.dim(aug.description)}`)
|
|
1864
|
-
console.log('')
|
|
1865
|
-
})
|
|
1866
|
-
}
|
|
1867
|
-
|
|
1868
|
-
// Display truly local (non-registry) augmentations
|
|
1869
|
-
const localOnly = localAugmentations.filter(aug =>
|
|
1870
|
-
!aug.package || !augmentations.find(regAug => regAug.package === aug.package)
|
|
1871
|
-
)
|
|
1872
|
-
|
|
1873
|
-
if (localOnly.length > 0) {
|
|
1874
|
-
console.log(colors.primary('š¦ CUSTOM AUGMENTATIONS'))
|
|
1875
|
-
localOnly.forEach(aug => {
|
|
1876
|
-
const status = aug.enabled ? colors.success('ā
Enabled') : colors.dim('āŖ Disabled')
|
|
1877
|
-
console.log(` ${aug.name.padEnd(20)} ${status}`)
|
|
1878
|
-
console.log(` ${colors.dim(aug.description || 'Custom augmentation')}`)
|
|
1879
|
-
console.log('')
|
|
1880
|
-
})
|
|
1881
|
-
}
|
|
1882
|
-
|
|
1883
|
-
console.log(colors.cyan('šÆ GET STARTED'))
|
|
1884
|
-
console.log(' brainy install <name> Install augmentation')
|
|
1885
|
-
console.log(' brainy cloud Access Brain Cloud features')
|
|
1886
|
-
console.log(` ${colors.blue('Learn more:')} https://soulcraft.com/augmentations`)
|
|
1887
|
-
|
|
1888
|
-
} else {
|
|
1889
|
-
throw new Error('Registry unavailable')
|
|
1890
|
-
}
|
|
1891
|
-
} catch (error) {
|
|
1892
|
-
// Fallback to local augmentations only
|
|
1893
|
-
console.log(colors.warning('ā Professional catalog unavailable, showing local augmentations'))
|
|
1894
|
-
const augmentations = brainy.listAugmentations()
|
|
1895
|
-
if (augmentations.length === 0) {
|
|
1896
|
-
console.log(colors.warning('No augmentations registered'))
|
|
1897
|
-
return
|
|
1898
|
-
}
|
|
1899
|
-
|
|
1900
|
-
const table = new Table({
|
|
1901
|
-
head: [colors.brain('Name'), colors.brain('Type'), colors.brain('Status'), colors.brain('Description')],
|
|
1902
|
-
style: { head: [], border: [] }
|
|
1903
|
-
})
|
|
1904
|
-
|
|
1905
|
-
augmentations.forEach(aug => {
|
|
1906
|
-
table.push([
|
|
1907
|
-
colors.primary(aug.name),
|
|
1908
|
-
colors.info(aug.type),
|
|
1909
|
-
aug.enabled ? colors.success('ā
Enabled') : colors.dim('āŖ Disabled'),
|
|
1910
|
-
colors.dim(aug.description || '')
|
|
1911
|
-
])
|
|
1912
|
-
})
|
|
1913
|
-
|
|
1914
|
-
console.log(table.toString())
|
|
1915
|
-
console.log(colors.info(`\nTotal: ${augmentations.length} augmentations`))
|
|
1916
|
-
}
|
|
1917
|
-
},
|
|
1918
|
-
|
|
1919
|
-
enable: async () => {
|
|
1920
|
-
if (!options.name) {
|
|
1921
|
-
console.log(colors.error('Name required: --name <augmentation-name>'))
|
|
1922
|
-
return
|
|
1923
|
-
}
|
|
1924
|
-
const success = brainy.enableAugmentation(options.name)
|
|
1925
|
-
if (success) {
|
|
1926
|
-
console.log(colors.success(`ā
Enabled augmentation: ${options.name}`))
|
|
1927
|
-
} else {
|
|
1928
|
-
console.log(colors.error(`Failed to enable: ${options.name} (not found)`))
|
|
1929
|
-
}
|
|
1930
|
-
},
|
|
1931
|
-
|
|
1932
|
-
disable: async () => {
|
|
1933
|
-
if (!options.name) {
|
|
1934
|
-
console.log(colors.error('Name required: --name <augmentation-name>'))
|
|
1935
|
-
return
|
|
1936
|
-
}
|
|
1937
|
-
const success = brainy.disableAugmentation(options.name)
|
|
1938
|
-
if (success) {
|
|
1939
|
-
console.log(colors.warning(`āŖ Disabled augmentation: ${options.name}`))
|
|
1940
|
-
} else {
|
|
1941
|
-
console.log(colors.error(`Failed to disable: ${options.name} (not found)`))
|
|
1942
|
-
}
|
|
1943
|
-
},
|
|
1944
|
-
|
|
1945
|
-
register: async () => {
|
|
1946
|
-
if (!options.path) {
|
|
1947
|
-
console.log(colors.error('Path required: --path <augmentation-module>'))
|
|
1948
|
-
return
|
|
1949
|
-
}
|
|
1950
|
-
|
|
1951
|
-
try {
|
|
1952
|
-
// Dynamic import of custom augmentation
|
|
1953
|
-
const customModule = await import(options.path)
|
|
1954
|
-
const AugmentationClass = customModule.default || customModule[Object.keys(customModule)[0]]
|
|
1955
|
-
|
|
1956
|
-
if (!AugmentationClass) {
|
|
1957
|
-
console.log(colors.error('No augmentation class found in module'))
|
|
1958
|
-
return
|
|
1959
|
-
}
|
|
1960
|
-
|
|
1961
|
-
const augmentation = new AugmentationClass()
|
|
1962
|
-
brainy.register(augmentation)
|
|
1963
|
-
console.log(colors.success(`ā
Registered augmentation: ${augmentation.name}`))
|
|
1964
|
-
console.log(colors.info(`Type: ${augmentation.type}`))
|
|
1965
|
-
if (augmentation.description) {
|
|
1966
|
-
console.log(colors.dim(`Description: ${augmentation.description}`))
|
|
1967
|
-
}
|
|
1968
|
-
} catch (error) {
|
|
1969
|
-
console.log(colors.error(`Failed to register augmentation: ${error.message}`))
|
|
1970
|
-
}
|
|
1971
|
-
},
|
|
1972
|
-
|
|
1973
|
-
unregister: async () => {
|
|
1974
|
-
if (!options.name) {
|
|
1975
|
-
console.log(colors.error('Name required: --name <augmentation-name>'))
|
|
1976
|
-
return
|
|
1977
|
-
}
|
|
1978
|
-
|
|
1979
|
-
brainy.unregister(options.name)
|
|
1980
|
-
console.log(colors.warning(`šļø Unregistered augmentation: ${options.name}`))
|
|
1981
|
-
},
|
|
1982
|
-
|
|
1983
|
-
'enable-type': async () => {
|
|
1984
|
-
if (!options.type) {
|
|
1985
|
-
console.log(colors.error('Type required: --type <augmentation-type>'))
|
|
1986
|
-
console.log(colors.info('Valid types: sense, conduit, cognition, memory, perception, dialog, activation'))
|
|
1987
|
-
return
|
|
1988
|
-
}
|
|
1989
|
-
|
|
1990
|
-
const count = brainy.enableAugmentationType(options.type)
|
|
1991
|
-
console.log(colors.success(`ā
Enabled ${count} ${options.type} augmentations`))
|
|
1992
|
-
},
|
|
1993
|
-
|
|
1994
|
-
'disable-type': async () => {
|
|
1995
|
-
if (!options.type) {
|
|
1996
|
-
console.log(colors.error('Type required: --type <augmentation-type>'))
|
|
1997
|
-
console.log(colors.info('Valid types: sense, conduit, cognition, memory, perception, dialog, activation'))
|
|
1998
|
-
return
|
|
1999
|
-
}
|
|
2000
|
-
|
|
2001
|
-
const count = brainy.disableAugmentationType(options.type)
|
|
2002
|
-
console.log(colors.warning(`āŖ Disabled ${count} ${options.type} augmentations`))
|
|
2003
|
-
}
|
|
2004
|
-
}
|
|
2005
|
-
|
|
2006
|
-
if (actions[action]) {
|
|
2007
|
-
await actions[action]()
|
|
2008
|
-
} else {
|
|
2009
|
-
console.log(colors.error('Valid actions: list, enable, disable, register, unregister, enable-type, disable-type'))
|
|
2010
|
-
console.log(colors.info('\nExamples:'))
|
|
2011
|
-
console.log(colors.dim(' brainy augment list # List all augmentations'))
|
|
2012
|
-
console.log(colors.dim(' brainy augment enable --name neural-import # Enable an augmentation'))
|
|
2013
|
-
console.log(colors.dim(' brainy augment register --path ./my-augmentation.js # Register custom augmentation'))
|
|
2014
|
-
console.log(colors.dim(' brainy augment enable-type --type sense # Enable all sense augmentations'))
|
|
2015
|
-
}
|
|
2016
|
-
}))
|
|
2017
|
-
|
|
2018
|
-
// Command 7: CLEAR - Clear all data
|
|
2019
|
-
program
|
|
2020
|
-
.command('clear')
|
|
2021
|
-
.description('Clear all data from your brain (with safety prompt)')
|
|
2022
|
-
.option('--force', 'Force clear without confirmation')
|
|
2023
|
-
.option('--backup', 'Create backup before clearing')
|
|
2024
|
-
.action(wrapAction(async (options) => {
|
|
2025
|
-
if (!options.force) {
|
|
2026
|
-
console.log(colors.warning('šØ This will delete ALL data in your brain!'))
|
|
2027
|
-
|
|
2028
|
-
const rl = createInterface({
|
|
2029
|
-
input: process.stdin,
|
|
2030
|
-
output: process.stdout
|
|
2031
|
-
})
|
|
2032
|
-
|
|
2033
|
-
const confirmed = await new Promise(resolve => {
|
|
2034
|
-
rl.question(colors.warning('Type "DELETE EVERYTHING" to confirm: '), (answer) => {
|
|
2035
|
-
rl.close()
|
|
2036
|
-
resolve(answer === 'DELETE EVERYTHING')
|
|
2037
|
-
})
|
|
2038
|
-
})
|
|
2039
|
-
|
|
2040
|
-
if (!confirmed) {
|
|
2041
|
-
console.log(colors.info('Clear operation cancelled'))
|
|
2042
|
-
return
|
|
2043
|
-
}
|
|
2044
|
-
}
|
|
2045
|
-
|
|
2046
|
-
const brainyInstance = await getBrainy()
|
|
2047
|
-
|
|
2048
|
-
if (options.backup) {
|
|
2049
|
-
console.log(colors.info('š¾ Creating backup...'))
|
|
2050
|
-
// Future: implement backup functionality
|
|
2051
|
-
console.log(colors.success('ā
Backup created'))
|
|
2052
|
-
}
|
|
2053
|
-
|
|
2054
|
-
console.log(colors.info('šļø Clearing all data...'))
|
|
2055
|
-
await brainyInstance.clear({ force: true })
|
|
2056
|
-
console.log(colors.success('ā
All data cleared successfully'))
|
|
2057
|
-
}))
|
|
2058
|
-
|
|
2059
|
-
// Command 8: EXPORT - Export your data
|
|
2060
|
-
program
|
|
2061
|
-
.command('export')
|
|
2062
|
-
.description('Export your brain data in various formats')
|
|
2063
|
-
.option('-f, --format <format>', 'Export format (json, csv, graph, embeddings)', 'json')
|
|
2064
|
-
.option('-o, --output <file>', 'Output file path')
|
|
2065
|
-
.option('--vectors', 'Include vector embeddings')
|
|
2066
|
-
.option('--no-metadata', 'Exclude metadata')
|
|
2067
|
-
.option('--no-relationships', 'Exclude relationships')
|
|
2068
|
-
.option('--filter <json>', 'Filter by metadata')
|
|
2069
|
-
.option('-l, --limit <number>', 'Limit number of items')
|
|
2070
|
-
.action(wrapAction(async (options) => {
|
|
2071
|
-
const brainy = await initBrainy()
|
|
2072
|
-
console.log(colors.brain('š¤ Exporting Brain Data'))
|
|
2073
|
-
|
|
2074
|
-
const spinner = ora('Exporting data...').start()
|
|
2075
|
-
|
|
2076
|
-
try {
|
|
2077
|
-
const exportOptions = {
|
|
2078
|
-
format: options.format,
|
|
2079
|
-
includeVectors: options.vectors || false,
|
|
2080
|
-
includeMetadata: options.metadata !== false,
|
|
2081
|
-
includeRelationships: options.relationships !== false,
|
|
2082
|
-
filter: options.filter ? JSON.parse(options.filter) : {},
|
|
2083
|
-
limit: options.limit ? parseInt(options.limit) : undefined
|
|
2084
|
-
}
|
|
2085
|
-
|
|
2086
|
-
const data = await brainy.export(exportOptions)
|
|
2087
|
-
|
|
2088
|
-
spinner.succeed('Export complete')
|
|
2089
|
-
|
|
2090
|
-
if (options.output) {
|
|
2091
|
-
// Write to file
|
|
2092
|
-
const fs = require('fs')
|
|
2093
|
-
const content = typeof data === 'string' ? data : JSON.stringify(data, null, 2)
|
|
2094
|
-
fs.writeFileSync(options.output, content)
|
|
2095
|
-
console.log(colors.success(`ā
Exported to: ${options.output}`))
|
|
2096
|
-
|
|
2097
|
-
// Show summary
|
|
2098
|
-
const items = Array.isArray(data) ? data.length : (data.nodes ? data.nodes.length : 1)
|
|
2099
|
-
console.log(colors.info(`š Format: ${options.format}`))
|
|
2100
|
-
console.log(colors.info(`š Items: ${items}`))
|
|
2101
|
-
if (options.vectors) {
|
|
2102
|
-
console.log(colors.info(`š¢ Vectors: Included`))
|
|
2103
|
-
}
|
|
2104
|
-
} else {
|
|
2105
|
-
// Output to console
|
|
2106
|
-
if (typeof data === 'string') {
|
|
2107
|
-
console.log(data)
|
|
2108
|
-
} else {
|
|
2109
|
-
console.log(JSON.stringify(data, null, 2))
|
|
2110
|
-
}
|
|
2111
|
-
}
|
|
2112
|
-
} catch (error) {
|
|
2113
|
-
spinner.fail('Export failed')
|
|
2114
|
-
console.error(colors.error(error.message))
|
|
2115
|
-
process.exit(1)
|
|
2116
|
-
}
|
|
2117
|
-
}))
|
|
2118
|
-
|
|
2119
|
-
// Command 8: CLOUD - Premium features connection
|
|
2120
|
-
program
|
|
2121
|
-
.command('cloud <action>')
|
|
2122
|
-
.description('āļø Brain Cloud - AI Memory, Team Sync, Enterprise Connectors (FREE TRIAL!)')
|
|
2123
|
-
.option('-i, --instance <id>', 'Brain Cloud instance ID')
|
|
2124
|
-
.option('-e, --email <email>', 'Your email for signup')
|
|
2125
|
-
.action(wrapAction(async (action, options) => {
|
|
2126
|
-
console.log(boxen(
|
|
2127
|
-
colors.brain('āļø BRAIN CLOUD - SUPERCHARGE YOUR BRAIN! š\n\n') +
|
|
2128
|
-
colors.success('⨠FREE TRIAL: First 100GB FREE!\n') +
|
|
2129
|
-
colors.info('š° Then just $9/month (individuals) or $49/month (teams)\n\n') +
|
|
2130
|
-
colors.primary('Features:\n') +
|
|
2131
|
-
colors.dim(' ⢠AI Memory that persists across sessions\n') +
|
|
2132
|
-
colors.dim(' ⢠Multi-agent coordination\n') +
|
|
2133
|
-
colors.dim(' ⢠Automatic backups & sync\n') +
|
|
2134
|
-
colors.dim(' ⢠Premium connectors (Notion, Slack, etc.)'),
|
|
2135
|
-
{ padding: 1, borderStyle: 'round', borderColor: 'cyan' }
|
|
2136
|
-
))
|
|
2137
|
-
|
|
2138
|
-
const cloudActions = {
|
|
2139
|
-
setup: async () => {
|
|
2140
|
-
console.log(colors.brain('\nš Quick Setup - 30 seconds to superpowers!\n'))
|
|
2141
|
-
|
|
2142
|
-
if (!options.email) {
|
|
2143
|
-
const { email } = await prompts({
|
|
2144
|
-
type: 'text',
|
|
2145
|
-
name: 'email',
|
|
2146
|
-
message: 'Enter your email for FREE trial:',
|
|
2147
|
-
validate: (value) => value.includes('@') || 'Please enter a valid email'
|
|
2148
|
-
})
|
|
2149
|
-
options.email = email
|
|
2150
|
-
}
|
|
2151
|
-
|
|
2152
|
-
console.log(colors.success(`\nā
Setting up Brain Cloud for: ${options.email}`))
|
|
2153
|
-
console.log(colors.info('\nš§ Check your email for activation link!'))
|
|
2154
|
-
console.log(colors.dim('\nOr visit: https://app.soulcraft.com/activate\n'))
|
|
2155
|
-
|
|
2156
|
-
// Cloud features planned for future release
|
|
2157
|
-
console.log(colors.brain('š Your Brain Cloud trial is ready!'))
|
|
2158
|
-
console.log(colors.success('\nNext steps:'))
|
|
2159
|
-
console.log(colors.dim(' 1. Check your email for API key'))
|
|
2160
|
-
console.log(colors.dim(' 2. Run: brainy cloud connect --key YOUR_KEY'))
|
|
2161
|
-
console.log(colors.dim(' 3. Start using persistent AI memory!'))
|
|
2162
|
-
},
|
|
2163
|
-
connect: async () => {
|
|
2164
|
-
console.log(colors.info('š Connecting to Brain Cloud...'))
|
|
2165
|
-
// Dynamic import to avoid loading premium code unnecessarily
|
|
2166
|
-
console.log(colors.info('š Cloud features coming soon...'))
|
|
2167
|
-
console.log(colors.info('Brainy works offline by default'))
|
|
2168
|
-
},
|
|
2169
|
-
status: async () => {
|
|
2170
|
-
console.log(colors.info('āļø Cloud Status: Available in future release'))
|
|
2171
|
-
console.log(colors.info('Current version works offline'))
|
|
2172
|
-
},
|
|
2173
|
-
augmentations: async () => {
|
|
2174
|
-
console.log(colors.info('š§© Cloud augmentations coming in future release'))
|
|
2175
|
-
console.log(colors.info('Local augmentations available now'))
|
|
2176
|
-
}
|
|
2177
|
-
}
|
|
2178
|
-
|
|
2179
|
-
if (cloudActions[action]) {
|
|
2180
|
-
await cloudActions[action]()
|
|
2181
|
-
} else {
|
|
2182
|
-
console.log(colors.error('Valid actions: connect, status, augmentations'))
|
|
2183
|
-
console.log(colors.info('Example: brainy cloud connect --instance demo-test-auto'))
|
|
2184
|
-
}
|
|
2185
|
-
}))
|
|
2186
|
-
|
|
2187
|
-
// Command 7: MIGRATE - Migration tools
|
|
2188
|
-
program
|
|
2189
|
-
.command('migrate <action>')
|
|
2190
|
-
.description('Migration tools for upgrades')
|
|
2191
|
-
.option('-f, --from <version>', 'Migrate from version')
|
|
2192
|
-
.option('-b, --backup', 'Create backup before migration')
|
|
2193
|
-
.action(wrapAction(async (action, options) => {
|
|
2194
|
-
console.log(colors.primary('š Brainy Migration Tools'))
|
|
2195
|
-
|
|
2196
|
-
const migrateActions = {
|
|
2197
|
-
check: async () => {
|
|
2198
|
-
console.log(colors.info('š Checking for migration needs...'))
|
|
2199
|
-
// Check for deprecated methods, old config, etc.
|
|
2200
|
-
const issues = []
|
|
2201
|
-
|
|
2202
|
-
try {
|
|
2203
|
-
const { BrainyData } = await import('../dist/brainyData.js')
|
|
2204
|
-
const brainy = new BrainyData()
|
|
2205
|
-
|
|
2206
|
-
// Check for old API usage
|
|
2207
|
-
console.log(colors.success('ā
No migration issues found'))
|
|
2208
|
-
} catch (error) {
|
|
2209
|
-
console.log(colors.warning(`ā ļø Found issues: ${error.message}`))
|
|
2210
|
-
}
|
|
2211
|
-
},
|
|
2212
|
-
backup: async () => {
|
|
2213
|
-
console.log(colors.info('š¾ Creating backup...'))
|
|
2214
|
-
const { BrainyData } = await import('../dist/brainyData.js')
|
|
2215
|
-
const brainy = new BrainyData()
|
|
2216
|
-
const backup = await brainy.createBackup()
|
|
2217
|
-
console.log(colors.success(`ā
Backup created: ${backup.path}`))
|
|
2218
|
-
},
|
|
2219
|
-
restore: async () => {
|
|
2220
|
-
if (!options.from) {
|
|
2221
|
-
console.error(colors.error('Please specify backup file: --from <path>'))
|
|
2222
|
-
process.exit(1)
|
|
2223
|
-
}
|
|
2224
|
-
console.log(colors.info(`š„ Restoring from: ${options.from}`))
|
|
2225
|
-
const { BrainyData } = await import('../dist/brainyData.js')
|
|
2226
|
-
const brainy = new BrainyData()
|
|
2227
|
-
await brainy.restoreBackup(options.from)
|
|
2228
|
-
console.log(colors.success('ā
Restore complete'))
|
|
2229
|
-
}
|
|
2230
|
-
}
|
|
2231
|
-
|
|
2232
|
-
if (migrateActions[action]) {
|
|
2233
|
-
await migrateActions[action]()
|
|
2234
|
-
} else {
|
|
2235
|
-
console.log(colors.error('Valid actions: check, backup, restore'))
|
|
2236
|
-
console.log(colors.info('Example: brainy migrate check'))
|
|
2237
|
-
}
|
|
2238
|
-
}))
|
|
2239
|
-
|
|
2240
|
-
// Command 8: HELP - Interactive guidance
|
|
2241
|
-
program
|
|
2242
|
-
.command('help [command]')
|
|
2243
|
-
.description('Get help or enter interactive mode')
|
|
2244
|
-
.action(wrapAction(async (command) => {
|
|
2245
|
-
if (command) {
|
|
2246
|
-
program.help()
|
|
2247
|
-
return
|
|
2248
|
-
}
|
|
2249
|
-
|
|
2250
|
-
// Interactive mode for beginners
|
|
2251
|
-
console.log(colors.primary('š§ āļø Welcome to Brainy!'))
|
|
2252
|
-
console.log(colors.info('Your AI-powered second brain'))
|
|
2253
|
-
console.log()
|
|
2254
|
-
|
|
2255
|
-
const rl = createInterface({
|
|
2256
|
-
input: process.stdin,
|
|
2257
|
-
output: process.stdout
|
|
2258
|
-
})
|
|
2259
|
-
|
|
2260
|
-
console.log(colors.primary('What would you like to do?'))
|
|
2261
|
-
console.log(colors.info('1. Add some data'))
|
|
2262
|
-
console.log(colors.info('2. Chat with AI using your data'))
|
|
2263
|
-
console.log(colors.info('3. Search your brain'))
|
|
2264
|
-
console.log(colors.info('4. Update existing data'))
|
|
2265
|
-
console.log(colors.info('5. Delete data'))
|
|
2266
|
-
console.log(colors.info('6. Import a file'))
|
|
2267
|
-
console.log(colors.info('7. Check status'))
|
|
2268
|
-
console.log(colors.info('8. Connect to Brain Cloud'))
|
|
2269
|
-
console.log(colors.info('9. Configuration'))
|
|
2270
|
-
console.log(colors.info('10. Show all commands'))
|
|
2271
|
-
console.log()
|
|
2272
|
-
|
|
2273
|
-
const choice = await new Promise(resolve => {
|
|
2274
|
-
rl.question(colors.primary('Enter your choice (1-10): '), (answer) => {
|
|
2275
|
-
rl.close()
|
|
2276
|
-
resolve(answer)
|
|
2277
|
-
})
|
|
2278
|
-
})
|
|
2279
|
-
|
|
2280
|
-
switch (choice) {
|
|
2281
|
-
case '1':
|
|
2282
|
-
console.log(colors.success('\nš§ Use: brainy add "your data here"'))
|
|
2283
|
-
console.log(colors.info('Example: brainy add "John works at Google"'))
|
|
2284
|
-
break
|
|
2285
|
-
case '2':
|
|
2286
|
-
console.log(colors.success('\nš¬ Use: brainy chat "your question"'))
|
|
2287
|
-
console.log(colors.info('Example: brainy chat "Tell me about my data"'))
|
|
2288
|
-
console.log(colors.info('Supports: local (Ollama), OpenAI, Claude'))
|
|
2289
|
-
break
|
|
2290
|
-
case '3':
|
|
2291
|
-
console.log(colors.success('\nš Use: brainy search "your query"'))
|
|
2292
|
-
console.log(colors.info('Example: brainy search "Google employees"'))
|
|
2293
|
-
break
|
|
2294
|
-
case '4':
|
|
2295
|
-
console.log(colors.success('\nš„ Use: brainy import <file-or-url>'))
|
|
2296
|
-
console.log(colors.info('Example: brainy import data.txt'))
|
|
2297
|
-
break
|
|
2298
|
-
case '5':
|
|
2299
|
-
console.log(colors.success('\nš Use: brainy status'))
|
|
2300
|
-
console.log(colors.info('Shows comprehensive brain statistics'))
|
|
2301
|
-
console.log(colors.info('Options: --simple (quick) or --verbose (detailed)'))
|
|
2302
|
-
break
|
|
2303
|
-
case '6':
|
|
2304
|
-
console.log(colors.success('\nāļø Use: brainy cloud connect'))
|
|
2305
|
-
console.log(colors.info('Example: brainy cloud connect --instance demo-test-auto'))
|
|
2306
|
-
break
|
|
2307
|
-
case '7':
|
|
2308
|
-
console.log(colors.success('\nš§ Use: brainy config <action>'))
|
|
2309
|
-
console.log(colors.info('Example: brainy config list'))
|
|
2310
|
-
break
|
|
2311
|
-
case '8':
|
|
2312
|
-
program.help()
|
|
2313
|
-
break
|
|
2314
|
-
default:
|
|
2315
|
-
console.log(colors.warning('Invalid choice. Use "brainy --help" for all commands.'))
|
|
2316
|
-
}
|
|
2317
|
-
}))
|
|
2318
|
-
|
|
2319
|
-
// ========================================
|
|
2320
|
-
// FALLBACK - Show interactive help if no command
|
|
2321
|
-
// ========================================
|
|
2322
|
-
|
|
2323
|
-
// Handle --interactive flag
|
|
2324
|
-
if (process.argv.includes('-i') || process.argv.includes('--interactive')) {
|
|
2325
|
-
// Start full interactive mode
|
|
2326
|
-
console.log(colors.primary('š§ Starting Interactive Mode...'))
|
|
2327
|
-
import('./brainy-interactive.js').then(module => {
|
|
2328
|
-
module.startInteractiveMode()
|
|
2329
|
-
}).catch(error => {
|
|
2330
|
-
console.error(colors.error('Failed to start interactive mode:'), error.message)
|
|
2331
|
-
// Fallback to simple interactive prompt
|
|
2332
|
-
program.parse(['node', 'brainy', 'help'])
|
|
2333
|
-
})
|
|
2334
|
-
} else if (process.argv.length === 2) {
|
|
2335
|
-
// No arguments - show interactive help
|
|
2336
|
-
program.parse(['node', 'brainy', 'help'])
|
|
2337
|
-
} else {
|
|
2338
|
-
// Parse normally
|
|
2339
|
-
program.parse(process.argv)
|
|
2340
|
-
}
|
|
10
|
+
import('../dist/cli/index.js').catch((error) => {
|
|
11
|
+
console.error('Failed to load Brainy CLI:', error.message)
|
|
12
|
+
console.error('Make sure you have built the project: npm run build')
|
|
13
|
+
process.exit(1)
|
|
14
|
+
})
|