@soulcraft/brainy 0.63.0 β†’ 1.0.0-rc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2463 +0,0 @@
1
- /**
2
- * Cortex - Beautiful CLI Command Center for Brainy
3
- *
4
- * Configuration, data management, search, and chat - all in one place!
5
- */
6
- import { BrainyData } from '../brainyData.js';
7
- import { BrainyChat } from '../chat/brainyChat.js';
8
- import { PerformanceMonitor } from './performanceMonitor.js';
9
- import { HealthCheck } from './healthCheck.js';
10
- // Licensing system moved to quantum-vault
11
- import * as readline from 'readline';
12
- import * as fs from 'fs/promises';
13
- import * as path from 'path';
14
- import * as crypto from 'crypto';
15
- // @ts-ignore - CLI packages
16
- import chalk from 'chalk';
17
- // @ts-ignore - CLI packages
18
- import ora from 'ora';
19
- // @ts-ignore - CLI packages
20
- import boxen from 'boxen';
21
- // @ts-ignore - CLI packages
22
- import Table from 'cli-table3';
23
- // @ts-ignore - CLI packages
24
- import prompts from 'prompts';
25
- // Brainy-branded terminal colors matching the logo
26
- const colors = {
27
- primary: chalk.hex('#3A5F4A'), // Deep teal from brain jar
28
- success: chalk.hex('#2D4A3A'), // Darker teal for success states
29
- warning: chalk.hex('#D67441'), // Warm orange from logo rays
30
- error: chalk.hex('#B85C35'), // Darker orange for errors
31
- info: chalk.hex('#4A6B5A'), // Muted green background color
32
- dim: chalk.hex('#8A9B8A'), // Muted gray-green
33
- bold: chalk.bold,
34
- highlight: chalk.hex('#E88B5A'), // Coral brain color for highlights
35
- accent: chalk.hex('#F5E6D3'), // Cream accent color
36
- retro: chalk.hex('#D67441'), // Main retro orange
37
- brain: chalk.hex('#E88B5A') // Brain coral color
38
- };
39
- // 1950s Retro Sci-Fi emojis matching Brainy's atomic age aesthetic
40
- const emojis = {
41
- brain: '🧠', // Perfect brain in a jar!
42
- tube: 'πŸ§ͺ', // Laboratory test tube for data
43
- atom: 'βš›οΈ', // Atomic symbol - pure 50s sci-fi
44
- lock: 'πŸ”’', // Vault-style security
45
- key: 'πŸ—οΈ', // Vintage brass key
46
- shield: 'πŸ›‘οΈ', // Protective force field
47
- check: 'βœ…', // Success indicator
48
- cross: '❌', // Error state
49
- warning: '⚠️', // Alert system
50
- info: 'ℹ️', // Information display
51
- search: 'πŸ”', // Laboratory magnifier
52
- chat: 'πŸ’­', // Thought transmission
53
- data: 'πŸŽ›οΈ', // Control panel/dashboard
54
- config: 'βš™οΈ', // Mechanical gear system
55
- magic: '⚑', // Electrical energy/power
56
- party: 'πŸŽ†', // Atomic celebration
57
- robot: 'πŸ€–', // Mechanical automaton
58
- cloud: '☁️', // Atmospheric storage
59
- disk: 'πŸ’½', // Retro storage disc
60
- package: 'πŸ“¦', // Laboratory specimen box
61
- lab: 'πŸ”¬', // Scientific instrument
62
- network: 'πŸ“‘', // Communications array
63
- sync: 'πŸ”„', // Cyclical process
64
- backup: 'πŸ’Ύ', // Archive storage
65
- health: 'πŸ”‹', // Power/energy levels
66
- stats: 'πŸ“Š', // Data analysis charts
67
- explore: 'πŸ—ΊοΈ', // Territory mapping
68
- import: 'πŸ“₯', // Input channel
69
- export: 'πŸ“€', // Output transmission
70
- sparkle: '✨', // Energy discharge
71
- rocket: 'πŸš€', // Space age propulsion
72
- repair: 'πŸ”§', // Repair tools
73
- lightning: '⚑' // Lightning bolt
74
- };
75
- export class Cortex {
76
- constructor() {
77
- // UI properties for terminal output
78
- this.emojis = {
79
- check: 'βœ…',
80
- cross: '❌',
81
- info: 'ℹ️',
82
- warning: '⚠️',
83
- rocket: 'πŸš€',
84
- brain: '🧠',
85
- atom: 'βš›οΈ',
86
- lock: 'πŸ”’',
87
- key: 'πŸ”‘',
88
- package: 'πŸ“¦',
89
- chart: 'πŸ“Š',
90
- sparkles: '✨',
91
- fire: 'πŸ”₯',
92
- zap: '⚑',
93
- gear: 'βš™οΈ',
94
- robot: 'πŸ€–',
95
- shield: 'πŸ›‘οΈ',
96
- wrench: 'πŸ”§',
97
- clipboard: 'πŸ“‹',
98
- folder: 'πŸ“',
99
- database: 'πŸ—„οΈ',
100
- lightning: '⚑',
101
- checkmark: 'βœ…',
102
- repair: 'πŸ”§',
103
- health: 'πŸ₯'
104
- };
105
- this.colors = {
106
- reset: '\x1b[0m',
107
- bright: '\x1b[1m',
108
- // Helper methods
109
- dim: (text) => `\x1b[2m${text}\x1b[0m`,
110
- red: (text) => `\x1b[31m${text}\x1b[0m`,
111
- green: (text) => `\x1b[32m${text}\x1b[0m`,
112
- yellow: (text) => `\x1b[33m${text}\x1b[0m`,
113
- blue: (text) => `\x1b[34m${text}\x1b[0m`,
114
- magenta: (text) => `\x1b[35m${text}\x1b[0m`,
115
- cyan: (text) => `\x1b[36m${text}\x1b[0m`,
116
- white: (text) => `\x1b[37m${text}\x1b[0m`,
117
- gray: (text) => `\x1b[90m${text}\x1b[0m`,
118
- retro: (text) => `\x1b[36m${text}\x1b[0m`,
119
- success: (text) => `\x1b[32m${text}\x1b[0m`,
120
- warning: (text) => `\x1b[33m${text}\x1b[0m`,
121
- error: (text) => `\x1b[31m${text}\x1b[0m`,
122
- info: (text) => `\x1b[34m${text}\x1b[0m`,
123
- brain: (text) => `\x1b[35m${text}\x1b[0m`,
124
- accent: (text) => `\x1b[36m${text}\x1b[0m`,
125
- premium: (text) => `\x1b[33m${text}\x1b[0m`,
126
- highlight: (text) => `\x1b[1m${text}\x1b[0m`
127
- };
128
- this.customSecretPatterns = [];
129
- this.configPath = path.join(process.cwd(), '.cortex', 'config.json');
130
- this.config = {};
131
- }
132
- /**
133
- * Load configuration
134
- */
135
- async loadConfig() {
136
- try {
137
- await fs.mkdir(path.dirname(this.configPath), { recursive: true });
138
- const configData = await fs.readFile(this.configPath, 'utf-8');
139
- this.config = JSON.parse(configData);
140
- return this.config;
141
- }
142
- catch {
143
- // Config doesn't exist yet, return empty config
144
- this.config = {};
145
- return this.config;
146
- }
147
- }
148
- /**
149
- * Ensure Brainy is initialized
150
- */
151
- async ensureBrainy() {
152
- if (!this.brainy) {
153
- const config = await this.loadConfig();
154
- this.brainy = new BrainyData(config.brainyOptions || {});
155
- await this.brainy.init();
156
- }
157
- }
158
- /**
159
- * Master Key Management - Atomic Age Security Protocols
160
- */
161
- async initializeMasterKey() {
162
- // Try environment variable first
163
- const envKey = process.env.CORTEX_MASTER_KEY;
164
- if (envKey && envKey.length >= 32) {
165
- this.encryptionKey = Buffer.from(envKey.substring(0, 32));
166
- this.masterKeySource = 'env';
167
- return;
168
- }
169
- // Check for existing stored key
170
- const keyPath = path.join(path.dirname(this.configPath), '.master_key');
171
- try {
172
- const storedKey = await fs.readFile(keyPath);
173
- this.encryptionKey = storedKey;
174
- this.masterKeySource = 'generated';
175
- return;
176
- }
177
- catch {
178
- // Key doesn't exist, need to create one
179
- }
180
- // Prompt for passphrase or generate new key
181
- const { method } = await prompts({
182
- type: 'select',
183
- name: 'method',
184
- message: `${emojis.key} ${colors.retro('Select encryption key method:')}`,
185
- choices: [
186
- { title: `${emojis.brain} Generate secure key (recommended)`, value: 'generate' },
187
- { title: `${emojis.lock} Create from passphrase`, value: 'passphrase' },
188
- { title: `${emojis.warning} Skip encryption (not secure)`, value: 'skip' }
189
- ]
190
- });
191
- if (method === 'skip') {
192
- console.log(colors.warning(`${emojis.warning} Encryption disabled - secrets will be stored in plain text!`));
193
- return;
194
- }
195
- if (method === 'generate') {
196
- this.encryptionKey = crypto.randomBytes(32);
197
- this.masterKeySource = 'generated';
198
- // Store the key securely
199
- await fs.writeFile(keyPath, this.encryptionKey, { mode: 0o600 });
200
- console.log(colors.success(`${emojis.check} Secure master key generated and stored`));
201
- }
202
- else if (method === 'passphrase') {
203
- const { passphrase } = await prompts({
204
- type: 'password',
205
- name: 'passphrase',
206
- message: `${emojis.key} Enter master passphrase (min 8 characters):`
207
- });
208
- if (!passphrase || passphrase.length < 8) {
209
- throw new Error('Passphrase must be at least 8 characters');
210
- }
211
- // Derive key from passphrase using PBKDF2
212
- const salt = crypto.randomBytes(16);
213
- this.encryptionKey = crypto.pbkdf2Sync(passphrase, salt, 100000, 32, 'sha256');
214
- this.masterKeySource = 'passphrase';
215
- // Store salt for future key derivation
216
- const keyData = Buffer.concat([salt, this.encryptionKey]);
217
- await fs.writeFile(keyPath, keyData, { mode: 0o600 });
218
- console.log(colors.success(`${emojis.check} Master key derived from passphrase`));
219
- }
220
- }
221
- /**
222
- * Load master key from stored salt + passphrase
223
- */
224
- async loadPassphraseKey() {
225
- const keyPath = path.join(path.dirname(this.configPath), '.master_key');
226
- const keyData = await fs.readFile(keyPath);
227
- if (keyData.length === 32) {
228
- // Simple generated key
229
- this.encryptionKey = keyData;
230
- return;
231
- }
232
- // Extract salt and ask for passphrase
233
- const salt = keyData.subarray(0, 16);
234
- const { passphrase } = await prompts({
235
- type: 'password',
236
- name: 'passphrase',
237
- message: `${emojis.key} Enter master passphrase:`
238
- });
239
- if (!passphrase) {
240
- throw new Error('Passphrase required for encrypted configuration');
241
- }
242
- this.encryptionKey = crypto.pbkdf2Sync(passphrase, salt, 100000, 32, 'sha256');
243
- }
244
- /**
245
- * Reset master key - for key rotation
246
- */
247
- async resetMasterKey() {
248
- console.log(boxen(`${emojis.warning} ${colors.retro('SECURITY PROTOCOL: KEY ROTATION')}\n\n` +
249
- `${colors.accent('β—†')} ${colors.dim('This will re-encrypt all stored secrets')}\n` +
250
- `${colors.accent('β—†')} ${colors.dim('Ensure you have backups before proceeding')}`, { padding: 1, borderStyle: 'round', borderColor: '#D67441' }));
251
- const { confirm } = await prompts({
252
- type: 'confirm',
253
- name: 'confirm',
254
- message: 'Proceed with key rotation?',
255
- initial: false
256
- });
257
- if (!confirm) {
258
- console.log(colors.dim('Key rotation cancelled'));
259
- return;
260
- }
261
- // Get current decrypted values
262
- const currentSecrets = await this.getAllSecrets();
263
- // Remove old key
264
- const keyPath = path.join(path.dirname(this.configPath), '.master_key');
265
- try {
266
- await fs.unlink(keyPath);
267
- }
268
- catch { }
269
- // Initialize new key
270
- await this.initializeMasterKey();
271
- // Re-encrypt all secrets with new key
272
- const spinner = ora('Re-encrypting secrets with new key...').start();
273
- for (const [key, value] of Object.entries(currentSecrets)) {
274
- await this.configSet(key, value, { encrypt: true });
275
- }
276
- spinner.succeed(colors.success(`${emojis.check} Key rotation complete! ${Object.keys(currentSecrets).length} secrets re-encrypted`));
277
- }
278
- /**
279
- * Get all decrypted secrets (for key rotation)
280
- */
281
- async getAllSecrets() {
282
- const secrets = {};
283
- const configMetaPath = path.join(path.dirname(this.configPath), 'config_metadata.json');
284
- try {
285
- const metadata = JSON.parse(await fs.readFile(configMetaPath, 'utf8'));
286
- for (const key of Object.keys(metadata)) {
287
- if (metadata[key].encrypted) {
288
- const value = await this.configGet(key);
289
- if (value)
290
- secrets[key] = value;
291
- }
292
- }
293
- }
294
- catch { }
295
- return secrets;
296
- }
297
- /**
298
- * Initialize Cortex with beautiful prompts
299
- */
300
- async init(options = {}) {
301
- const spinner = ora('Initializing Cortex...').start();
302
- try {
303
- // Check if already initialized
304
- if (await this.isInitialized()) {
305
- spinner.warn('Cortex is already initialized!');
306
- const { reinit } = await prompts({
307
- type: 'confirm',
308
- name: 'reinit',
309
- message: 'Do you want to reinitialize?',
310
- initial: false
311
- });
312
- if (!reinit) {
313
- spinner.stop();
314
- return;
315
- }
316
- }
317
- spinner.text = 'Setting up configuration...';
318
- // Interactive setup
319
- const responses = await prompts([
320
- {
321
- type: 'select',
322
- name: 'storage',
323
- message: `${emojis.disk} Choose your storage type:`,
324
- choices: [
325
- { title: `${emojis.disk} Local Filesystem`, value: 'filesystem' },
326
- { title: `${emojis.cloud} AWS S3`, value: 's3' },
327
- { title: `${emojis.cloud} Cloudflare R2`, value: 'r2' },
328
- { title: `${emojis.cloud} Google Cloud Storage`, value: 'gcs' },
329
- { title: `${emojis.brain} Memory (testing)`, value: 'memory' }
330
- ]
331
- },
332
- {
333
- type: (prev) => prev === 's3' ? 'text' : null,
334
- name: 's3Bucket',
335
- message: 'Enter S3 bucket name:'
336
- },
337
- {
338
- type: (prev) => prev === 'r2' ? 'text' : null,
339
- name: 'r2Bucket',
340
- message: 'Enter Cloudflare R2 bucket name:'
341
- },
342
- {
343
- type: (prev) => prev === 'gcs' ? 'text' : null,
344
- name: 'gcsBucket',
345
- message: 'Enter GCS bucket name:'
346
- },
347
- {
348
- type: 'confirm',
349
- name: 'encryption',
350
- message: `${emojis.lock} Enable encryption for secrets?`,
351
- initial: true
352
- },
353
- {
354
- type: 'confirm',
355
- name: 'chat',
356
- message: `${emojis.chat} Enable Brainy Chat?`,
357
- initial: true
358
- },
359
- {
360
- type: (prev) => prev ? 'select' : null,
361
- name: 'llm',
362
- message: `${emojis.robot} Choose LLM provider (optional):`,
363
- choices: [
364
- { title: 'None (template-based)', value: null },
365
- { title: 'Claude (Anthropic)', value: 'claude-3-5-sonnet' },
366
- { title: 'GPT-4 (OpenAI)', value: 'gpt-4' },
367
- { title: 'Local Model (Hugging Face)', value: 'Xenova/LaMini-Flan-T5-77M' }
368
- ]
369
- }
370
- ]);
371
- // Create config
372
- this.config = {
373
- storage: responses.storage,
374
- encryption: responses.encryption,
375
- chat: responses.chat,
376
- llm: responses.llm,
377
- s3Bucket: responses.s3Bucket,
378
- r2Bucket: responses.r2Bucket,
379
- gcsBucket: responses.gcsBucket,
380
- initialized: true,
381
- createdAt: new Date().toISOString()
382
- };
383
- // Setup encryption
384
- if (responses.encryption) {
385
- await this.initializeMasterKey();
386
- this.config.encryptionEnabled = true;
387
- }
388
- // Save configuration
389
- await this.saveConfig();
390
- // Initialize Brainy
391
- spinner.text = 'Initializing Brainy database...';
392
- await this.initBrainy();
393
- spinner.succeed(colors.success(`${emojis.party} Cortex initialized successfully!`));
394
- // Show welcome message
395
- this.showWelcome();
396
- }
397
- catch (error) {
398
- spinner.fail(colors.error('Failed to initialize Cortex'));
399
- console.error(error);
400
- process.exit(1);
401
- }
402
- }
403
- /**
404
- * Beautiful welcome message
405
- */
406
- showWelcome() {
407
- const welcome = boxen(`${emojis.brain} ${colors.brain('CORTEX')} ${emojis.atom} ${colors.bold('COMMAND CENTER')}\n\n` +
408
- `${colors.accent('β—†')} ${colors.dim('Laboratory systems online and ready for operation')}\n\n` +
409
- `${emojis.rocket} ${colors.retro('QUICK START PROTOCOLS:')}\n` +
410
- ` ${colors.primary('cortex chat')} ${emojis.chat} Neural interface mode\n` +
411
- ` ${colors.primary('cortex add')} ${emojis.data} Specimen collection\n` +
412
- ` ${colors.primary('cortex search')} ${emojis.search} Data analysis\n` +
413
- ` ${colors.primary('cortex config')} ${emojis.config} System parameters\n` +
414
- ` ${colors.primary('cortex help')} ${emojis.info} Operations manual`, {
415
- padding: 1,
416
- margin: 1,
417
- borderStyle: 'round',
418
- borderColor: '#D67441' // Retro orange border
419
- });
420
- console.log(welcome);
421
- }
422
- /**
423
- * Chat with your data - beautiful interactive mode
424
- */
425
- async chat(question) {
426
- await this.ensureInitialized();
427
- if (!this.chatInstance) {
428
- this.chatInstance = new BrainyChat(this.brainy, {
429
- llm: this.config.llm,
430
- sources: true
431
- });
432
- }
433
- // Single question mode
434
- if (question) {
435
- const spinner = ora('Thinking...').start();
436
- try {
437
- const answer = await this.chatInstance.ask(question);
438
- spinner.stop();
439
- console.log(`\n${emojis.robot} ${colors.bold('Answer:')}\n${answer}\n`);
440
- }
441
- catch (error) {
442
- spinner.fail('Failed to get answer');
443
- console.error(error);
444
- }
445
- return;
446
- }
447
- // Interactive chat mode
448
- console.log(boxen(`${emojis.brain} ${colors.brain('NEURAL INTERFACE')} ${emojis.magic}\n\n` +
449
- `${colors.accent('β—†')} ${colors.dim('Thought-to-data transmission active')}\n` +
450
- `${colors.accent('β—†')} ${colors.dim('Query processing protocols engaged')}\n\n` +
451
- `${colors.retro('Type "exit" to disengage neural link')}`, { padding: 1, borderStyle: 'round', borderColor: '#E88B5A' }));
452
- const rl = readline.createInterface({
453
- input: process.stdin,
454
- output: process.stdout,
455
- prompt: colors.primary('You> ')
456
- });
457
- rl.prompt();
458
- rl.on('line', async (line) => {
459
- const input = line.trim();
460
- if (input.toLowerCase() === 'exit' || input.toLowerCase() === 'quit') {
461
- console.log(`\n${emojis.atom} ${colors.retro('Neural link disengaged')} ${emojis.sparkle}\n`);
462
- rl.close();
463
- return;
464
- }
465
- if (input) {
466
- const spinner = ora('Thinking...').start();
467
- try {
468
- const answer = await this.chatInstance.ask(input);
469
- spinner.stop();
470
- console.log(`\n${emojis.robot} ${colors.success(answer)}\n`);
471
- }
472
- catch (error) {
473
- spinner.fail('Error processing question');
474
- console.error(error);
475
- }
476
- }
477
- rl.prompt();
478
- });
479
- // Ensure process exits when readline closes
480
- rl.on('close', () => {
481
- console.log('\n');
482
- process.exit(0);
483
- });
484
- }
485
- /**
486
- * Add data with beautiful prompts
487
- */
488
- async add(data, metadata) {
489
- await this.ensureInitialized();
490
- // Interactive mode if no data provided
491
- if (!data) {
492
- const responses = await prompts([
493
- {
494
- type: 'text',
495
- name: 'data',
496
- message: `${emojis.data} Enter data to add:`
497
- },
498
- {
499
- type: 'text',
500
- name: 'id',
501
- message: 'ID (optional, press enter to auto-generate):'
502
- },
503
- {
504
- type: 'confirm',
505
- name: 'hasMetadata',
506
- message: 'Add metadata?',
507
- initial: false
508
- },
509
- {
510
- type: (prev) => prev ? 'text' : null,
511
- name: 'metadata',
512
- message: 'Enter metadata (JSON format):'
513
- }
514
- ]);
515
- data = responses.data;
516
- if (responses.metadata) {
517
- try {
518
- metadata = JSON.parse(responses.metadata);
519
- }
520
- catch {
521
- console.log(colors.warning('Invalid JSON, skipping metadata'));
522
- }
523
- }
524
- if (responses.id) {
525
- metadata = { ...metadata, id: responses.id };
526
- }
527
- }
528
- const spinner = ora('Adding data...').start();
529
- try {
530
- const id = await this.brainy.add(data, metadata);
531
- spinner.succeed(colors.success(`${emojis.check} Added with ID: ${id}`));
532
- }
533
- catch (error) {
534
- spinner.fail('Failed to add data');
535
- console.error(error);
536
- }
537
- }
538
- /**
539
- * Search with beautiful results display and advanced options
540
- */
541
- async search(query, options = {}) {
542
- await this.ensureInitialized();
543
- const limit = options.limit || 10;
544
- const spinner = ora(`Searching...`).start();
545
- try {
546
- // Build search options with MongoDB-style filters
547
- const searchOptions = {};
548
- // Add metadata filters if provided
549
- if (options.filter) {
550
- searchOptions.metadata = options.filter;
551
- }
552
- // Add graph traversal options
553
- if (options.verbs) {
554
- searchOptions.includeVerbs = true;
555
- searchOptions.verbTypes = options.verbs;
556
- }
557
- if (options.depth) {
558
- searchOptions.traversalDepth = options.depth;
559
- }
560
- const results = await this.brainy.search(query, limit, searchOptions);
561
- spinner.stop();
562
- if (results.length === 0) {
563
- console.log(colors.warning(`${emojis.warning} No results found`));
564
- return;
565
- }
566
- // Create beautiful table with dynamic columns
567
- const hasVerbs = results.some((r) => r.verbs && r.verbs.length > 0);
568
- const head = [
569
- colors.bold('Rank'),
570
- colors.bold('ID'),
571
- colors.bold('Score')
572
- ];
573
- if (hasVerbs) {
574
- head.push(colors.bold('Connections'));
575
- }
576
- head.push(colors.bold('Metadata'));
577
- const table = new Table({
578
- head,
579
- style: { head: ['cyan'] }
580
- });
581
- results.forEach((result, i) => {
582
- const row = [
583
- colors.dim(`#${i + 1}`),
584
- colors.primary(result.id.slice(0, 25) + (result.id.length > 25 ? '...' : '')),
585
- colors.success(`${(result.score * 100).toFixed(1)}%`)
586
- ];
587
- if (hasVerbs && result.verbs) {
588
- const verbs = result.verbs.slice(0, 2).map((v) => `${colors.warning(v.type)}: ${v.object.slice(0, 15)}...`).join('\n');
589
- row.push(verbs || '-');
590
- }
591
- row.push(colors.dim(JSON.stringify(result.metadata || {}).slice(0, 40) + '...'));
592
- table.push(row);
593
- });
594
- console.log(`\n${emojis.search} ${colors.bold(`Found ${results.length} results:`)}\n`);
595
- // Show applied filters
596
- if (options.filter) {
597
- console.log(colors.dim(` Filters: ${JSON.stringify(options.filter)}`));
598
- }
599
- if (options.verbs) {
600
- console.log(colors.dim(` Graph traversal: ${options.verbs.join(', ')}`));
601
- }
602
- console.log();
603
- console.log(table.toString());
604
- }
605
- catch (error) {
606
- spinner.fail('Search failed');
607
- console.error(error);
608
- }
609
- }
610
- /**
611
- * Advanced search with interactive prompts
612
- */
613
- async advancedSearch() {
614
- await this.ensureInitialized();
615
- const responses = await prompts([
616
- {
617
- type: 'text',
618
- name: 'query',
619
- message: `${emojis.search} Enter search query:`
620
- },
621
- {
622
- type: 'number',
623
- name: 'limit',
624
- message: 'Number of results:',
625
- initial: 10
626
- },
627
- {
628
- type: 'confirm',
629
- name: 'useFilters',
630
- message: 'Add metadata filters (MongoDB-style)?',
631
- initial: false
632
- },
633
- {
634
- type: (prev) => prev ? 'text' : null,
635
- name: 'filters',
636
- message: 'Enter filters (JSON with $gt, $gte, $lt, $lte, $eq, $ne, $in, $nin):\nExample: {"age": {"$gte": 18}, "status": {"$in": ["active", "pending"]}}'
637
- },
638
- {
639
- type: 'confirm',
640
- name: 'useGraph',
641
- message: `${emojis.magic} Traverse graph relationships?`,
642
- initial: false
643
- },
644
- {
645
- type: (prev) => prev ? 'text' : null,
646
- name: 'verbs',
647
- message: 'Enter verb types (comma-separated):\nExample: owns, likes, follows'
648
- },
649
- {
650
- type: (prev, values) => values.useGraph ? 'number' : null,
651
- name: 'depth',
652
- message: 'Traversal depth:',
653
- initial: 1
654
- }
655
- ]);
656
- const options = { limit: responses.limit };
657
- if (responses.filters) {
658
- try {
659
- options.filter = JSON.parse(responses.filters);
660
- }
661
- catch {
662
- console.log(colors.warning('Invalid filter JSON, skipping filters'));
663
- }
664
- }
665
- if (responses.verbs) {
666
- options.verbs = responses.verbs.split(',').map((v) => v.trim());
667
- options.depth = responses.depth;
668
- }
669
- await this.search(responses.query, options);
670
- }
671
- /**
672
- * Add or update graph connections (verbs)
673
- */
674
- async addVerb(subject, verb, object, metadata) {
675
- await this.ensureInitialized();
676
- const spinner = ora('Adding relationship...').start();
677
- try {
678
- // For now, we'll add it as a special metadata entry
679
- await this.brainy.add(`${subject} ${verb} ${object}`, {
680
- type: 'relationship',
681
- subject,
682
- verb,
683
- object,
684
- ...metadata
685
- });
686
- spinner.succeed(colors.success(`${emojis.check} Added: ${subject} --[${verb}]--> ${object}`));
687
- }
688
- catch (error) {
689
- spinner.fail('Failed to add relationship');
690
- console.error(error);
691
- }
692
- }
693
- /**
694
- * Interactive graph exploration
695
- */
696
- async explore(startId) {
697
- await this.ensureInitialized();
698
- if (!startId) {
699
- const { id } = await prompts({
700
- type: 'text',
701
- name: 'id',
702
- message: `${emojis.search} Enter starting node ID:`
703
- });
704
- startId = id;
705
- }
706
- const spinner = ora('Loading graph...').start();
707
- try {
708
- // Get node and its connections
709
- const results = await this.brainy.search(startId, 1, { includeVerbs: true });
710
- if (results.length === 0) {
711
- spinner.fail('Node not found');
712
- return;
713
- }
714
- spinner.stop();
715
- const node = results[0];
716
- // Display node info in a beautiful box
717
- const nodeInfo = boxen(`${emojis.data} ${colors.bold('Node: ' + node.id)}\n\n` +
718
- `${colors.dim('Metadata:')}\n${JSON.stringify(node.metadata || {}, null, 2)}\n\n` +
719
- `${colors.dim('Connections:')}\n${node.verbs && node.verbs.length > 0
720
- ? node.verbs.map((v) => ` ${colors.warning(v.type)} β†’ ${colors.primary(v.object)}`).join('\n')
721
- : ' No connections'}`, {
722
- padding: 1,
723
- borderStyle: 'round',
724
- borderColor: 'magenta'
725
- });
726
- console.log(nodeInfo);
727
- // Interactive exploration menu
728
- if (node.verbs && node.verbs.length > 0) {
729
- const { action } = await prompts({
730
- type: 'select',
731
- name: 'action',
732
- message: 'What would you like to do?',
733
- choices: [
734
- { title: 'Explore a connected node', value: 'explore' },
735
- { title: 'Add new connection', value: 'add' },
736
- { title: 'Search similar nodes', value: 'similar' },
737
- { title: 'Exit', value: 'exit' }
738
- ]
739
- });
740
- if (action === 'explore') {
741
- const { next } = await prompts({
742
- type: 'select',
743
- name: 'next',
744
- message: 'Choose node to explore:',
745
- choices: node.verbs.map((v) => ({
746
- title: `${v.object} (via ${v.type})`,
747
- value: v.object
748
- }))
749
- });
750
- await this.explore(next);
751
- }
752
- else if (action === 'add') {
753
- const newVerb = await prompts([
754
- {
755
- type: 'text',
756
- name: 'verb',
757
- message: 'Relationship type:'
758
- },
759
- {
760
- type: 'text',
761
- name: 'object',
762
- message: 'Target node ID:'
763
- }
764
- ]);
765
- await this.addVerb(startId, newVerb.verb, newVerb.object);
766
- await this.explore(startId);
767
- }
768
- else if (action === 'similar') {
769
- await this.search(startId, { limit: 5 });
770
- }
771
- }
772
- }
773
- catch (error) {
774
- spinner.fail('Failed to explore graph');
775
- console.error(error);
776
- }
777
- }
778
- /**
779
- * Configuration management with encryption
780
- */
781
- async configSet(key, value, options = {}) {
782
- await this.ensureInitialized();
783
- const isSecret = options.encrypt || this.isSecret(key);
784
- if (isSecret && this.encryptionKey) {
785
- // Encrypt the value
786
- const iv = crypto.randomBytes(16);
787
- const cipher = crypto.createCipheriv('aes-256-gcm', this.encryptionKey, iv);
788
- let encrypted = cipher.update(value, 'utf8', 'hex');
789
- encrypted += cipher.final('hex');
790
- const authTag = cipher.getAuthTag();
791
- value = `ENCRYPTED:${iv.toString('hex')}:${authTag.toString('hex')}:${encrypted}`;
792
- console.log(colors.success(`${emojis.lock} Stored encrypted: ${key}`));
793
- }
794
- else {
795
- console.log(colors.success(`${emojis.check} Stored: ${key}`));
796
- }
797
- // Store in Brainy
798
- await this.brainy.add(value, {
799
- type: 'config',
800
- key,
801
- encrypted: isSecret,
802
- timestamp: new Date().toISOString()
803
- });
804
- }
805
- /**
806
- * Get configuration value
807
- */
808
- async configGet(key) {
809
- await this.ensureInitialized();
810
- const results = await this.brainy.search(key, 1, {
811
- metadata: { type: 'config', key }
812
- });
813
- if (results.length === 0) {
814
- return null;
815
- }
816
- let value = results[0].id;
817
- // Decrypt if needed
818
- if (value.startsWith('ENCRYPTED:') && this.encryptionKey) {
819
- const [, iv, authTag, encrypted] = value.split(':');
820
- const decipher = crypto.createDecipheriv('aes-256-gcm', this.encryptionKey, Buffer.from(iv, 'hex'));
821
- decipher.setAuthTag(Buffer.from(authTag, 'hex'));
822
- let decrypted = decipher.update(encrypted, 'hex', 'utf8');
823
- decrypted += decipher.final('utf8');
824
- value = decrypted;
825
- }
826
- return value;
827
- }
828
- /**
829
- * List all configuration
830
- */
831
- async configList() {
832
- await this.ensureInitialized();
833
- const spinner = ora('Loading configuration...').start();
834
- try {
835
- const results = await this.brainy.search('', 100, {
836
- metadata: { type: 'config' }
837
- });
838
- spinner.stop();
839
- if (results.length === 0) {
840
- console.log(colors.warning('No configuration found'));
841
- return;
842
- }
843
- const table = new Table({
844
- head: [colors.bold('Key'), colors.bold('Encrypted'), colors.bold('Timestamp')],
845
- style: { head: ['cyan'] }
846
- });
847
- results.forEach(result => {
848
- const meta = result.metadata;
849
- table.push([
850
- colors.primary(meta.key),
851
- meta.encrypted ? `${emojis.lock} Yes` : 'No',
852
- colors.dim(new Date(meta.timestamp).toLocaleString())
853
- ]);
854
- });
855
- console.log(`\n${emojis.config} ${colors.bold('Configuration:')}\n`);
856
- console.log(table.toString());
857
- }
858
- catch (error) {
859
- spinner.fail('Failed to list configuration');
860
- console.error(error);
861
- }
862
- }
863
- /**
864
- * Storage migration with beautiful progress
865
- */
866
- async migrate(options) {
867
- await this.ensureInitialized();
868
- console.log(boxen(`${emojis.package} ${colors.bold('Storage Migration')}\n` +
869
- `From: ${colors.dim(this.config.storage)}\n` +
870
- `To: ${colors.primary(options.to)}`, { padding: 1, borderStyle: 'round', borderColor: 'yellow' }));
871
- const { confirm } = await prompts({
872
- type: 'confirm',
873
- name: 'confirm',
874
- message: 'Start migration?',
875
- initial: true
876
- });
877
- if (!confirm) {
878
- console.log(colors.dim('Migration cancelled'));
879
- return;
880
- }
881
- const spinner = ora('Starting migration...').start();
882
- try {
883
- // Create new Brainy instance with target storage
884
- let targetConfig = {};
885
- if (options.to === 'filesystem') {
886
- targetConfig.storage = { forceFileSystemStorage: true };
887
- }
888
- else if (options.to === 's3' && options.bucket) {
889
- targetConfig.storage = {
890
- s3Storage: {
891
- bucketName: options.bucket
892
- }
893
- };
894
- }
895
- else if (options.to === 'gcs' && options.bucket) {
896
- targetConfig.storage = {
897
- gcsStorage: {
898
- bucketName: options.bucket
899
- }
900
- };
901
- }
902
- else if (options.to === 'memory') {
903
- targetConfig.storage = { forceMemoryStorage: true };
904
- }
905
- const targetBrainy = new BrainyData(targetConfig);
906
- await targetBrainy.init();
907
- spinner.text = 'Counting items...';
908
- // For now, we'll search for all items
909
- const allData = await this.brainy.search('', 1000);
910
- const total = allData.length;
911
- spinner.text = `Migrating ${total} items...`;
912
- for (let i = 0; i < allData.length; i++) {
913
- const item = allData[i];
914
- // Re-add the data to the new storage
915
- await targetBrainy.add(item.id, item.metadata || {});
916
- if (i % 10 === 0) {
917
- spinner.text = `Migrating... ${i + 1}/${total} (${((i + 1) / total * 100).toFixed(0)}%)`;
918
- }
919
- }
920
- spinner.succeed(colors.success(`${emojis.party} Migration complete! ${total} items migrated.`));
921
- // Update config
922
- this.config.storage = options.to;
923
- if (options.bucket) {
924
- if (options.to === 's3')
925
- this.config.s3Bucket = options.bucket;
926
- if (options.to === 'gcs')
927
- this.config.gcsBucket = options.bucket;
928
- }
929
- await this.saveConfig();
930
- }
931
- catch (error) {
932
- spinner.fail('Migration failed');
933
- console.error(error);
934
- process.exit(1);
935
- }
936
- }
937
- /**
938
- * Show comprehensive statistics and database info
939
- */
940
- async stats(detailed = false) {
941
- await this.ensureInitialized();
942
- const spinner = ora('Gathering statistics...').start();
943
- try {
944
- // Gather comprehensive stats
945
- const allItems = await this.brainy.search('', 1000);
946
- const itemsWithVerbs = allItems.filter((item) => item.verbs && item.verbs.length > 0);
947
- // Count unique field names
948
- const fieldCounts = new Map();
949
- const fieldTypes = new Map();
950
- allItems.forEach((item) => {
951
- if (item.metadata) {
952
- Object.entries(item.metadata).forEach(([key, value]) => {
953
- fieldCounts.set(key, (fieldCounts.get(key) || 0) + 1);
954
- if (!fieldTypes.has(key)) {
955
- fieldTypes.set(key, new Set());
956
- }
957
- fieldTypes.get(key).add(typeof value);
958
- });
959
- }
960
- });
961
- // Calculate storage size (approximate)
962
- const storageSize = JSON.stringify(allItems).length;
963
- const stats = {
964
- totalItems: allItems.length,
965
- itemsWithMetadata: allItems.filter((i) => i.metadata).length,
966
- itemsWithConnections: itemsWithVerbs.length,
967
- totalConnections: itemsWithVerbs.reduce((sum, item) => sum + item.verbs.length, 0),
968
- avgConnections: itemsWithVerbs.length > 0
969
- ? itemsWithVerbs.reduce((sum, item) => sum + item.verbs.length, 0) / itemsWithVerbs.length
970
- : 0,
971
- uniqueFields: fieldCounts.size,
972
- storageSize,
973
- dimensions: 384,
974
- embeddingModel: 'all-MiniLM-L6-v2'
975
- };
976
- spinner.stop();
977
- // Atomic age statistics display
978
- const statsBox = boxen(`${emojis.atom} ${colors.brain('LABORATORY STATUS')} ${emojis.data}\n\n` +
979
- `${colors.retro('β—† Specimen Count:')} ${colors.highlight(stats.totalItems)}\n` +
980
- `${colors.retro('β—† Catalogued:')} ${colors.highlight(stats.itemsWithMetadata)} ${colors.accent('(' + (stats.itemsWithMetadata / stats.totalItems * 100).toFixed(1) + '%)')}\n` +
981
- `${colors.retro('β—† Neural Links:')} ${colors.highlight(stats.itemsWithConnections)}\n` +
982
- `${colors.retro('β—† Total Connections:')} ${colors.highlight(stats.totalConnections)}\n` +
983
- `${colors.retro('β—† Avg Network Density:')} ${colors.highlight(stats.avgConnections.toFixed(2))}\n` +
984
- `${colors.retro('β—† Data Dimensions:')} ${colors.highlight(stats.uniqueFields)}\n` +
985
- `${colors.retro('β—† Storage Matrix:')} ${colors.accent((stats.storageSize / 1024).toFixed(2) + ' KB')}\n` +
986
- `${colors.retro('β—† Archive Type:')} ${colors.primary(this.config.storage)}\n` +
987
- `${colors.retro('β—† Neural Model:')} ${colors.info(stats.embeddingModel)} ${colors.dim('(' + stats.dimensions + 'd)')}`, {
988
- padding: 1,
989
- borderStyle: 'round',
990
- borderColor: '#D67441' // Retro orange border
991
- });
992
- console.log(statsBox);
993
- // Detailed field statistics if requested
994
- if (detailed && fieldCounts.size > 0) {
995
- const fieldTable = new Table({
996
- head: [
997
- colors.bold('Field Name'),
998
- colors.bold('Count'),
999
- colors.bold('Coverage'),
1000
- colors.bold('Types')
1001
- ],
1002
- style: { head: ['cyan'] }
1003
- });
1004
- Array.from(fieldCounts.entries())
1005
- .sort((a, b) => b[1] - a[1])
1006
- .slice(0, 15)
1007
- .forEach(([field, count]) => {
1008
- fieldTable.push([
1009
- colors.primary(field),
1010
- count.toString(),
1011
- `${(count / stats.totalItems * 100).toFixed(1)}%`,
1012
- Array.from(fieldTypes.get(field) || []).join(', ')
1013
- ]);
1014
- });
1015
- console.log(`\n${colors.bold('Top Fields:')}\n`);
1016
- console.log(fieldTable.toString());
1017
- }
1018
- }
1019
- catch (error) {
1020
- spinner.fail('Failed to get statistics');
1021
- console.error(error);
1022
- }
1023
- }
1024
- /**
1025
- * List all searchable fields with statistics
1026
- */
1027
- async listFields() {
1028
- await this.ensureInitialized();
1029
- const spinner = ora('Analyzing fields...').start();
1030
- try {
1031
- const allItems = await this.brainy.search('', 1000);
1032
- const fieldInfo = new Map();
1033
- // Analyze all fields
1034
- allItems.forEach((item) => {
1035
- if (item.metadata) {
1036
- Object.entries(item.metadata).forEach(([key, value]) => {
1037
- if (!fieldInfo.has(key)) {
1038
- fieldInfo.set(key, { count: 0, types: new Set(), samples: [] });
1039
- }
1040
- const info = fieldInfo.get(key);
1041
- info.count++;
1042
- info.types.add(typeof value);
1043
- if (info.samples.length < 3 && value !== null && value !== undefined) {
1044
- info.samples.push(value);
1045
- }
1046
- });
1047
- }
1048
- });
1049
- spinner.stop();
1050
- if (fieldInfo.size === 0) {
1051
- console.log(colors.warning('No fields found in metadata'));
1052
- return;
1053
- }
1054
- const table = new Table({
1055
- head: [
1056
- colors.bold('Field'),
1057
- colors.bold('Type(s)'),
1058
- colors.bold('Count'),
1059
- colors.bold('Sample Values')
1060
- ],
1061
- style: { head: ['cyan'] },
1062
- colWidths: [20, 15, 10, 40]
1063
- });
1064
- Array.from(fieldInfo.entries())
1065
- .sort((a, b) => b[1].count - a[1].count)
1066
- .forEach(([field, info]) => {
1067
- const samples = info.samples
1068
- .slice(0, 2)
1069
- .map(s => JSON.stringify(s).slice(0, 20))
1070
- .join(', ');
1071
- table.push([
1072
- colors.primary(field),
1073
- Array.from(info.types).join(', '),
1074
- info.count.toString(),
1075
- colors.dim(samples + (info.samples.length > 2 ? '...' : ''))
1076
- ]);
1077
- });
1078
- console.log(`\n${emojis.search} ${colors.bold('Searchable Fields:')}\n`);
1079
- console.log(table.toString());
1080
- console.log(`\n${colors.dim('Use these fields in searches:')}`);
1081
- console.log(colors.dim(`cortex search "query" --filter '{"${Array.from(fieldInfo.keys())[0]}": "value"}'`));
1082
- }
1083
- catch (error) {
1084
- spinner.fail('Failed to analyze fields');
1085
- console.error(error);
1086
- }
1087
- }
1088
- /**
1089
- * Setup LLM progressively with auto-download
1090
- */
1091
- async setupLLM(provider) {
1092
- await this.ensureInitialized();
1093
- console.log(boxen(`${emojis.robot} ${colors.bold('LLM Setup Assistant')}\n` +
1094
- `${colors.dim('Configure AI models for enhanced chat')}`, { padding: 1, borderStyle: 'round', borderColor: 'magenta' }));
1095
- const choices = [
1096
- {
1097
- title: `${emojis.brain} Local Model (No API key needed)`,
1098
- value: 'local',
1099
- description: 'Download and run models locally'
1100
- },
1101
- {
1102
- title: `${emojis.cloud} Claude (Anthropic)`,
1103
- value: 'claude',
1104
- description: 'Most capable, requires API key'
1105
- },
1106
- {
1107
- title: `${emojis.cloud} GPT-4 (OpenAI)`,
1108
- value: 'openai',
1109
- description: 'Powerful, requires API key'
1110
- },
1111
- {
1112
- title: `${emojis.sparkle} Ollama (Local server)`,
1113
- value: 'ollama',
1114
- description: 'Connect to local Ollama instance'
1115
- },
1116
- {
1117
- title: `${emojis.magic} Claude Desktop`,
1118
- value: 'claude-desktop',
1119
- description: 'Use Claude app on your computer'
1120
- }
1121
- ];
1122
- const { llmType } = await prompts({
1123
- type: 'select',
1124
- name: 'llmType',
1125
- message: 'Choose LLM provider:',
1126
- choices: provider ? choices.filter(c => c.value === provider) : choices
1127
- });
1128
- switch (llmType) {
1129
- case 'local':
1130
- await this.setupLocalLLM();
1131
- break;
1132
- case 'claude':
1133
- await this.setupClaudeLLM();
1134
- break;
1135
- case 'openai':
1136
- await this.setupOpenAILLM();
1137
- break;
1138
- case 'ollama':
1139
- await this.setupOllamaLLM();
1140
- break;
1141
- case 'claude-desktop':
1142
- await this.setupClaudeDesktop();
1143
- break;
1144
- }
1145
- }
1146
- async setupLocalLLM() {
1147
- const { model } = await prompts({
1148
- type: 'select',
1149
- name: 'model',
1150
- message: 'Choose a local model:',
1151
- choices: [
1152
- { title: 'LaMini-Flan-T5 (77M, fast)', value: 'Xenova/LaMini-Flan-T5-77M' },
1153
- { title: 'Phi-2 (2.7B, balanced)', value: 'microsoft/phi-2' },
1154
- { title: 'CodeLlama (7B, for code)', value: 'codellama/CodeLlama-7b-hf' },
1155
- { title: 'Custom Hugging Face model', value: 'custom' }
1156
- ]
1157
- });
1158
- let modelName = model;
1159
- if (model === 'custom') {
1160
- const { customModel } = await prompts({
1161
- type: 'text',
1162
- name: 'customModel',
1163
- message: 'Enter Hugging Face model ID (e.g., microsoft/DialoGPT-medium):'
1164
- });
1165
- modelName = customModel;
1166
- }
1167
- const spinner = ora(`Downloading ${modelName}...`).start();
1168
- try {
1169
- // Save configuration
1170
- await this.configSet('LLM_PROVIDER', 'local');
1171
- await this.configSet('LLM_MODEL', modelName);
1172
- // Test the model
1173
- this.config.llm = modelName;
1174
- this.chatInstance = new BrainyChat(this.brainy, { llm: modelName });
1175
- spinner.succeed(colors.success(`${emojis.check} Local model configured: ${modelName}`));
1176
- console.log(colors.dim('\nModel will download on first use. This may take a few minutes.'));
1177
- }
1178
- catch (error) {
1179
- spinner.fail('Failed to setup local model');
1180
- console.error(error);
1181
- }
1182
- }
1183
- async setupClaudeLLM() {
1184
- const { apiKey } = await prompts({
1185
- type: 'password',
1186
- name: 'apiKey',
1187
- message: 'Enter your Anthropic API key:'
1188
- });
1189
- if (apiKey) {
1190
- await this.configSet('ANTHROPIC_API_KEY', apiKey, { encrypt: true });
1191
- await this.configSet('LLM_PROVIDER', 'claude');
1192
- await this.configSet('LLM_MODEL', 'claude-3-5-sonnet-20241022');
1193
- this.config.llm = 'claude-3-5-sonnet';
1194
- console.log(colors.success(`${emojis.check} Claude configured successfully!`));
1195
- }
1196
- }
1197
- async setupOpenAILLM() {
1198
- const { apiKey } = await prompts({
1199
- type: 'password',
1200
- name: 'apiKey',
1201
- message: 'Enter your OpenAI API key:'
1202
- });
1203
- if (apiKey) {
1204
- await this.configSet('OPENAI_API_KEY', apiKey, { encrypt: true });
1205
- await this.configSet('LLM_PROVIDER', 'openai');
1206
- await this.configSet('LLM_MODEL', 'gpt-4o-mini');
1207
- this.config.llm = 'gpt-4o-mini';
1208
- console.log(colors.success(`${emojis.check} OpenAI configured successfully!`));
1209
- }
1210
- }
1211
- async setupOllamaLLM() {
1212
- const { url, model } = await prompts([
1213
- {
1214
- type: 'text',
1215
- name: 'url',
1216
- message: 'Ollama server URL:',
1217
- initial: 'http://localhost:11434'
1218
- },
1219
- {
1220
- type: 'text',
1221
- name: 'model',
1222
- message: 'Model name:',
1223
- initial: 'llama2'
1224
- }
1225
- ]);
1226
- await this.configSet('OLLAMA_URL', url);
1227
- await this.configSet('OLLAMA_MODEL', model);
1228
- await this.configSet('LLM_PROVIDER', 'ollama');
1229
- console.log(colors.success(`${emojis.check} Ollama configured!`));
1230
- console.log(colors.dim(`Make sure Ollama is running: ollama run ${model}`));
1231
- }
1232
- async setupClaudeDesktop() {
1233
- console.log(colors.info(`${emojis.info} Claude Desktop integration coming soon!`));
1234
- console.log(colors.dim('This will allow using Claude app as your LLM provider'));
1235
- }
1236
- /**
1237
- * Use the embedding model for other tasks
1238
- */
1239
- async embed(text) {
1240
- await this.ensureInitialized();
1241
- const spinner = ora('Generating embedding...').start();
1242
- try {
1243
- // Use Brainy's built-in embedding
1244
- const vector = await this.brainy.embed(text);
1245
- spinner.stop();
1246
- console.log(boxen(`${emojis.sparkle} ${colors.bold('Text Embedding')}\n\n` +
1247
- `${colors.dim('Input:')}\n"${text}"\n\n` +
1248
- `${colors.dim('Model:')} all-MiniLM-L6-v2 (384d)\n` +
1249
- `${colors.dim('Vector:')} [${vector.slice(0, 5).map(v => v.toFixed(4)).join(', ')}...]\n` +
1250
- `${colors.dim('Magnitude:')} ${Math.sqrt(vector.reduce((sum, v) => sum + v * v, 0)).toFixed(4)}`, { padding: 1, borderStyle: 'round', borderColor: 'cyan' }));
1251
- }
1252
- catch (error) {
1253
- spinner.fail('Failed to generate embedding');
1254
- console.error(error);
1255
- }
1256
- }
1257
- /**
1258
- * Calculate similarity between two texts
1259
- */
1260
- async similarity(text1, text2) {
1261
- await this.ensureInitialized();
1262
- const spinner = ora('Calculating similarity...').start();
1263
- try {
1264
- const vector1 = await this.brainy.embed(text1);
1265
- const vector2 = await this.brainy.embed(text2);
1266
- // Calculate cosine similarity
1267
- const dotProduct = vector1.reduce((sum, v, i) => sum + v * vector2[i], 0);
1268
- const mag1 = Math.sqrt(vector1.reduce((sum, v) => sum + v * v, 0));
1269
- const mag2 = Math.sqrt(vector2.reduce((sum, v) => sum + v * v, 0));
1270
- const similarity = dotProduct / (mag1 * mag2);
1271
- spinner.stop();
1272
- const color = similarity > 0.8 ? colors.success :
1273
- similarity > 0.5 ? colors.warning :
1274
- colors.error;
1275
- console.log(boxen(`${emojis.search} ${colors.bold('Semantic Similarity')}\n\n` +
1276
- `${colors.dim('Text 1:')}\n"${text1}"\n\n` +
1277
- `${colors.dim('Text 2:')}\n"${text2}"\n\n` +
1278
- `${colors.bold('Similarity:')} ${color((similarity * 100).toFixed(1) + '%')}\n` +
1279
- `${this.getSimilarityInterpretation(similarity)}`, { padding: 1, borderStyle: 'round', borderColor: 'magenta' }));
1280
- }
1281
- catch (error) {
1282
- spinner.fail('Failed to calculate similarity');
1283
- console.error(error);
1284
- }
1285
- }
1286
- getSimilarityInterpretation(score) {
1287
- if (score > 0.9)
1288
- return colors.success('✨ Nearly identical meaning');
1289
- if (score > 0.8)
1290
- return colors.success('🎯 Very similar');
1291
- if (score > 0.7)
1292
- return colors.warning('πŸ‘ Similar');
1293
- if (score > 0.5)
1294
- return colors.warning('πŸ€” Somewhat related');
1295
- if (score > 0.3)
1296
- return colors.error('😐 Loosely related');
1297
- return colors.error('❌ Unrelated');
1298
- }
1299
- /**
1300
- * Import .env file with automatic encryption of secrets
1301
- */
1302
- async importEnv(filePath) {
1303
- await this.ensureInitialized();
1304
- const spinner = ora('Importing environment variables...').start();
1305
- try {
1306
- const envContent = await fs.readFile(filePath, 'utf-8');
1307
- const lines = envContent.split('\n');
1308
- let imported = 0;
1309
- let encrypted = 0;
1310
- for (const line of lines) {
1311
- const trimmed = line.trim();
1312
- if (!trimmed || trimmed.startsWith('#'))
1313
- continue;
1314
- const [key, ...valueParts] = trimmed.split('=');
1315
- const value = valueParts.join('=').replace(/^["']|["']$/g, '');
1316
- if (key && value) {
1317
- const shouldEncrypt = this.isSecret(key);
1318
- await this.configSet(key, value, { encrypt: shouldEncrypt });
1319
- imported++;
1320
- if (shouldEncrypt)
1321
- encrypted++;
1322
- }
1323
- }
1324
- spinner.succeed(colors.success(`${emojis.check} Imported ${imported} variables (${encrypted} encrypted)`));
1325
- }
1326
- catch (error) {
1327
- spinner.fail('Failed to import .env file');
1328
- console.error(error);
1329
- }
1330
- }
1331
- /**
1332
- * Export configuration to .env file
1333
- */
1334
- async exportEnv(filePath) {
1335
- await this.ensureInitialized();
1336
- const spinner = ora('Exporting configuration...').start();
1337
- try {
1338
- const results = await this.brainy.search('', 1000, {
1339
- metadata: { type: 'config' }
1340
- });
1341
- let content = '# Exported from Cortex\n';
1342
- content += `# Generated: ${new Date().toISOString()}\n\n`;
1343
- for (const result of results) {
1344
- const meta = result.metadata;
1345
- if (meta?.key) {
1346
- const value = await this.configGet(meta.key);
1347
- if (value) {
1348
- content += `${meta.key}=${value}\n`;
1349
- }
1350
- }
1351
- }
1352
- await fs.writeFile(filePath, content);
1353
- spinner.succeed(colors.success(`${emojis.check} Exported to ${filePath}`));
1354
- }
1355
- catch (error) {
1356
- spinner.fail('Failed to export configuration');
1357
- console.error(error);
1358
- }
1359
- }
1360
- /**
1361
- * Delete data by ID
1362
- */
1363
- async delete(id) {
1364
- await this.ensureInitialized();
1365
- const spinner = ora('Deleting...').start();
1366
- try {
1367
- // For now, mark as deleted in metadata
1368
- await this.brainy.add(id, {
1369
- _deleted: true,
1370
- _deletedAt: new Date().toISOString()
1371
- });
1372
- spinner.succeed(colors.success(`${emojis.check} Deleted: ${id}`));
1373
- }
1374
- catch (error) {
1375
- spinner.fail('Delete failed');
1376
- console.error(error);
1377
- }
1378
- }
1379
- /**
1380
- * Update data by ID
1381
- */
1382
- async update(id, data, metadata) {
1383
- await this.ensureInitialized();
1384
- const spinner = ora('Updating...').start();
1385
- try {
1386
- // Re-add with same ID (overwrites)
1387
- await this.brainy.add(data, {
1388
- ...metadata,
1389
- id,
1390
- _updated: true,
1391
- _updatedAt: new Date().toISOString()
1392
- });
1393
- spinner.succeed(colors.success(`${emojis.check} Updated: ${id}`));
1394
- }
1395
- catch (error) {
1396
- spinner.fail('Update failed');
1397
- console.error(error);
1398
- }
1399
- }
1400
- /**
1401
- * Helpers
1402
- */
1403
- async ensureInitialized() {
1404
- if (!await this.isInitialized()) {
1405
- console.log(colors.warning(`${emojis.warning} Cortex not initialized. Run 'cortex init' first.`));
1406
- process.exit(1);
1407
- }
1408
- // Load encryption key if encryption is enabled
1409
- if (this.config.encryptionEnabled && !this.encryptionKey) {
1410
- await this.loadMasterKey();
1411
- }
1412
- // Load custom secret patterns
1413
- await this.loadCustomPatterns();
1414
- if (!this.brainy) {
1415
- await this.initBrainy();
1416
- }
1417
- }
1418
- /**
1419
- * Load master key from various sources
1420
- */
1421
- async loadMasterKey() {
1422
- // Try environment variable first
1423
- const envKey = process.env.CORTEX_MASTER_KEY;
1424
- if (envKey && envKey.length >= 32) {
1425
- this.encryptionKey = Buffer.from(envKey.substring(0, 32));
1426
- this.masterKeySource = 'env';
1427
- return;
1428
- }
1429
- // Try stored key file
1430
- const keyPath = path.join(path.dirname(this.configPath), '.master_key');
1431
- try {
1432
- await fs.access(keyPath);
1433
- const keyData = await fs.readFile(keyPath);
1434
- if (keyData.length === 32) {
1435
- // Generated key
1436
- this.encryptionKey = keyData;
1437
- this.masterKeySource = 'generated';
1438
- }
1439
- else {
1440
- // Passphrase-derived key
1441
- await this.loadPassphraseKey();
1442
- this.masterKeySource = 'passphrase';
1443
- }
1444
- }
1445
- catch {
1446
- console.log(colors.warning(`${emojis.warning} Encryption key not found. Some features may not work.`));
1447
- }
1448
- }
1449
- async isInitialized() {
1450
- try {
1451
- await fs.access(this.configPath);
1452
- const data = await fs.readFile(this.configPath, 'utf-8');
1453
- this.config = JSON.parse(data);
1454
- return this.config.initialized === true;
1455
- }
1456
- catch {
1457
- return false;
1458
- }
1459
- }
1460
- async initBrainy() {
1461
- // Map storage type to BrainyData config
1462
- let config = {};
1463
- if (this.config.storage === 'filesystem') {
1464
- config.storage = { forceFileSystemStorage: true };
1465
- }
1466
- else if (this.config.storage === 's3' && this.config.s3Bucket) {
1467
- config.storage = {
1468
- s3Storage: {
1469
- bucketName: this.config.s3Bucket
1470
- }
1471
- };
1472
- }
1473
- else if (this.config.storage === 'r2' && this.config.r2Bucket) {
1474
- // Cloudflare R2 is S3-compatible, so we use the s3Storage configuration
1475
- // Users need to set environment variables:
1476
- // CLOUDFLARE_R2_ACCOUNT_ID, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY
1477
- config.storage = {
1478
- s3Storage: {
1479
- bucketName: this.config.r2Bucket,
1480
- // R2 endpoint format: https://<account-id>.r2.cloudflarestorage.com
1481
- // The actual account ID should come from environment variables
1482
- endpoint: process.env.CLOUDFLARE_R2_ENDPOINT || `https://${process.env.CLOUDFLARE_R2_ACCOUNT_ID}.r2.cloudflarestorage.com`
1483
- }
1484
- };
1485
- }
1486
- else if (this.config.storage === 'gcs' && this.config.gcsBucket) {
1487
- config.storage = {
1488
- gcsStorage: {
1489
- bucketName: this.config.gcsBucket
1490
- }
1491
- };
1492
- }
1493
- else if (this.config.storage === 'memory') {
1494
- config.storage = { forceMemoryStorage: true };
1495
- }
1496
- this.brainy = new BrainyData(config);
1497
- await this.brainy.init();
1498
- // Initialize monitoring systems
1499
- this.performanceMonitor = new PerformanceMonitor(this.brainy);
1500
- this.healthCheck = new HealthCheck(this.brainy);
1501
- // Initialize licensing system
1502
- // Licensing system moved to quantum-vault for premium features
1503
- // Open source version has full functionality available
1504
- }
1505
- async saveConfig() {
1506
- const dir = path.dirname(this.configPath);
1507
- await fs.mkdir(dir, { recursive: true });
1508
- await fs.writeFile(this.configPath, JSON.stringify(this.config, null, 2));
1509
- }
1510
- /**
1511
- * Enhanced secret detection with custom patterns and categories
1512
- */
1513
- isSecret(key) {
1514
- const defaultSecretPatterns = [
1515
- // Standard secret patterns
1516
- /key$/i, /token$/i, /secret$/i, /password$/i, /pass$/i,
1517
- /^api[_-]?key$/i, /^auth[_-]?token$/i,
1518
- // API keys
1519
- /^openai[_-]?api[_-]?key$/i, /^anthropic[_-]?api[_-]?key$/i,
1520
- /^claude[_-]?api[_-]?key$/i, /^huggingface[_-]?token$/i,
1521
- /^github[_-]?token$/i, /^gitlab[_-]?token$/i,
1522
- // Database URLs
1523
- /database.*url$/i, /db.*url$/i, /connection[_-]?string$/i,
1524
- /mongo.*url$/i, /redis.*url$/i, /postgres.*url$/i,
1525
- // Cloud & Infrastructure
1526
- /aws.*key$/i, /aws.*secret$/i, /azure.*key$/i, /gcp.*key$/i,
1527
- /docker.*password$/i, /registry.*password$/i,
1528
- // Production patterns
1529
- /.*_prod_.*$/i, /.*_production_.*$/i,
1530
- /.*_live_.*$/i, /.*_master_.*$/i,
1531
- // Common service patterns
1532
- /stripe.*key$/i, /twilio.*token$/i, /sendgrid.*key$/i,
1533
- /jwt.*secret$/i, /session.*secret$/i, /encryption.*key$/i
1534
- ];
1535
- // Combine default and custom patterns
1536
- const allPatterns = [...defaultSecretPatterns, ...this.customSecretPatterns];
1537
- return allPatterns.some(pattern => pattern.test(key));
1538
- }
1539
- /**
1540
- * Add custom secret detection patterns
1541
- */
1542
- async addSecretPattern(pattern) {
1543
- try {
1544
- const regex = new RegExp(pattern, 'i');
1545
- this.customSecretPatterns.push(regex);
1546
- // Persist custom patterns
1547
- await this.saveCustomPatterns();
1548
- console.log(colors.success(`${emojis.check} Added secret pattern: ${pattern}`));
1549
- }
1550
- catch (error) {
1551
- throw new Error(`Invalid regex pattern: ${pattern}`);
1552
- }
1553
- }
1554
- /**
1555
- * Remove custom secret detection pattern
1556
- */
1557
- async removeSecretPattern(pattern) {
1558
- const index = this.customSecretPatterns.findIndex(p => p.source === pattern);
1559
- if (index === -1) {
1560
- throw new Error(`Pattern not found: ${pattern}`);
1561
- }
1562
- this.customSecretPatterns.splice(index, 1);
1563
- await this.saveCustomPatterns();
1564
- console.log(colors.success(`${emojis.check} Removed secret pattern: ${pattern}`));
1565
- }
1566
- /**
1567
- * List all secret detection patterns
1568
- */
1569
- async listSecretPatterns() {
1570
- console.log(boxen(`${emojis.shield} ${colors.brain('SECRET DETECTION PATTERNS')}\n\n` +
1571
- `${colors.retro('β—† Built-in Patterns:')}\n` +
1572
- ` β€’ API keys (*_key, *_token, *_secret)\n` +
1573
- ` β€’ Database URLs (*_url, connection_string)\n` +
1574
- ` β€’ Cloud credentials (aws_*, azure_*, gcp_*)\n` +
1575
- ` β€’ Production vars (*_prod_*, *_production_*)\n\n` +
1576
- `${colors.retro('β—† Custom Patterns:')}\n` +
1577
- (this.customSecretPatterns.length > 0
1578
- ? this.customSecretPatterns.map(p => ` β€’ ${p.source}`).join('\n')
1579
- : ` ${colors.dim('No custom patterns defined')}`), { padding: 1, borderStyle: 'round', borderColor: '#D67441' }));
1580
- }
1581
- /**
1582
- * Save custom patterns to disk
1583
- */
1584
- async saveCustomPatterns() {
1585
- const patternsPath = path.join(path.dirname(this.configPath), 'secret_patterns.json');
1586
- const patterns = this.customSecretPatterns.map(p => p.source);
1587
- await fs.writeFile(patternsPath, JSON.stringify(patterns, null, 2));
1588
- }
1589
- /**
1590
- * Load custom patterns from disk
1591
- */
1592
- async loadCustomPatterns() {
1593
- const patternsPath = path.join(path.dirname(this.configPath), 'secret_patterns.json');
1594
- try {
1595
- const data = await fs.readFile(patternsPath, 'utf8');
1596
- const patterns = JSON.parse(data);
1597
- this.customSecretPatterns = patterns.map((p) => new RegExp(p, 'i'));
1598
- }
1599
- catch {
1600
- // No custom patterns yet
1601
- }
1602
- }
1603
- /**
1604
- * Determine config category for enhanced management
1605
- */
1606
- getConfigCategory(key) {
1607
- // Explicit production configuration
1608
- if (key.match(/node_env|environment|stage|tier/i)) {
1609
- return Cortex.CONFIG_CATEGORIES.CONFIG;
1610
- }
1611
- // Public configuration (can be exposed)
1612
- if (key.match(/port|host|timeout|retry|limit|version/i)) {
1613
- return Cortex.CONFIG_CATEGORIES.PUBLIC;
1614
- }
1615
- // Sensitive but not secret (URLs, emails, usernames)
1616
- if (key.match(/url|email|username|user_id|org|organization/i) && !this.isSecret(key)) {
1617
- return Cortex.CONFIG_CATEGORIES.SENSITIVE;
1618
- }
1619
- // Default to secret if matches patterns
1620
- if (this.isSecret(key)) {
1621
- return Cortex.CONFIG_CATEGORIES.SECRET;
1622
- }
1623
- return Cortex.CONFIG_CATEGORIES.CONFIG;
1624
- }
1625
- /**
1626
- * Cortex Augmentation System - AI-Powered Data Understanding
1627
- */
1628
- async neuralImport(filePath, options = {}) {
1629
- await this.ensureInitialized();
1630
- // Import and create the Cortex SENSE augmentation
1631
- const { CortexSenseAugmentation } = await import('../augmentations/cortexSense.js');
1632
- const neuralSense = new CortexSenseAugmentation(this.brainy, options);
1633
- // Initialize the augmentation
1634
- await neuralSense.initialize();
1635
- try {
1636
- // Read the file
1637
- const fs = await import('fs/promises');
1638
- const fileContent = await fs.readFile(filePath, 'utf8');
1639
- const dataType = this.getDataTypeFromPath(filePath);
1640
- // Use the SENSE augmentation to process the data
1641
- const result = await neuralSense.processRawData(fileContent, dataType, options);
1642
- if (result.success) {
1643
- console.log(colors.success('βœ… Cortex import completed successfully'));
1644
- // Display summary
1645
- console.log(colors.primary(`πŸ“Š Processed: ${result.data.nouns.length} entities, ${result.data.verbs.length} relationships`));
1646
- if (result.data.confidence !== undefined) {
1647
- console.log(colors.primary(`🎯 Overall confidence: ${(result.data.confidence * 100).toFixed(1)}%`));
1648
- }
1649
- if (result.data.insights && result.data.insights.length > 0) {
1650
- console.log(colors.brain('\n🧠 Neural Insights:'));
1651
- result.data.insights.forEach((insight) => {
1652
- console.log(` ${colors.accent('β—†')} ${insight.description} (${(insight.confidence * 100).toFixed(1)}%)`);
1653
- });
1654
- }
1655
- }
1656
- else {
1657
- console.error(colors.error('❌ Cortex import failed:'), result.error);
1658
- }
1659
- }
1660
- finally {
1661
- await neuralSense.shutDown();
1662
- }
1663
- }
1664
- async neuralAnalyze(filePath) {
1665
- await this.ensureInitialized();
1666
- const { CortexSenseAugmentation } = await import('../augmentations/cortexSense.js');
1667
- const neuralSense = new CortexSenseAugmentation(this.brainy);
1668
- await neuralSense.initialize();
1669
- try {
1670
- const fs = await import('fs/promises');
1671
- const fileContent = await fs.readFile(filePath, 'utf8');
1672
- const dataType = this.getDataTypeFromPath(filePath);
1673
- // Use the analyzeStructure method
1674
- const result = await neuralSense.analyzeStructure(fileContent, dataType);
1675
- if (result.success) {
1676
- console.log(boxen(`${emojis.lab} ${colors.brain('NEURAL ANALYSIS RESULTS')}\n\n` +
1677
- `Entity Types: ${result.data.entityTypes.length}\n` +
1678
- `Relationship Types: ${result.data.relationshipTypes.length}\n` +
1679
- `Data Quality Score: ${((result.data.dataQuality.completeness + result.data.dataQuality.consistency + result.data.dataQuality.accuracy) / 3 * 100).toFixed(1)}%`, { padding: 1, borderStyle: 'round', borderColor: '#E88B5A' }));
1680
- if (result.data.recommendations.length > 0) {
1681
- console.log(colors.brain('\nπŸ’‘ Recommendations:'));
1682
- result.data.recommendations.forEach((rec) => {
1683
- console.log(` ${colors.accent('β—†')} ${rec}`);
1684
- });
1685
- }
1686
- }
1687
- else {
1688
- console.error(colors.error('❌ Analysis failed:'), result.error);
1689
- }
1690
- }
1691
- finally {
1692
- await neuralSense.shutDown();
1693
- }
1694
- }
1695
- async neuralValidate(filePath) {
1696
- await this.ensureInitialized();
1697
- const { CortexSenseAugmentation } = await import('../augmentations/cortexSense.js');
1698
- const neuralSense = new CortexSenseAugmentation(this.brainy);
1699
- await neuralSense.initialize();
1700
- try {
1701
- const fs = await import('fs/promises');
1702
- const fileContent = await fs.readFile(filePath, 'utf8');
1703
- const dataType = this.getDataTypeFromPath(filePath);
1704
- // Use the validateCompatibility method
1705
- const result = await neuralSense.validateCompatibility(fileContent, dataType);
1706
- if (result.success) {
1707
- const statusIcon = result.data.compatible ? 'βœ…' : '⚠️';
1708
- const statusText = result.data.compatible ? 'COMPATIBLE' : 'COMPATIBILITY ISSUES';
1709
- console.log(boxen(`${statusIcon} ${colors.brain(`DATA ${statusText}`)}\n\n` +
1710
- `Compatible: ${result.data.compatible ? 'Yes' : 'No'}\n` +
1711
- `Issues Found: ${result.data.issues.length}\n` +
1712
- `Suggestions: ${result.data.suggestions.length}`, { padding: 1, borderStyle: 'round', borderColor: result.data.compatible ? '#2D4A3A' : '#D67441' }));
1713
- if (result.data.issues.length > 0) {
1714
- console.log(colors.warning('\n⚠️ Issues:'));
1715
- result.data.issues.forEach((issue) => {
1716
- const severityColor = issue.severity === 'high' ? colors.error :
1717
- issue.severity === 'medium' ? colors.warning : colors.dim;
1718
- console.log(` ${severityColor(`[${issue.severity.toUpperCase()}]`)} ${issue.description}`);
1719
- });
1720
- }
1721
- if (result.data.suggestions.length > 0) {
1722
- console.log(colors.brain('\nπŸ’‘ Suggestions:'));
1723
- result.data.suggestions.forEach((suggestion) => {
1724
- console.log(` ${colors.accent('β—†')} ${suggestion}`);
1725
- });
1726
- }
1727
- }
1728
- else {
1729
- console.error(colors.error('❌ Validation failed:'), result.error);
1730
- }
1731
- }
1732
- finally {
1733
- await neuralSense.shutDown();
1734
- }
1735
- }
1736
- async neuralTypes() {
1737
- await this.ensureInitialized();
1738
- const { NounType, VerbType } = await import('../types/graphTypes.js');
1739
- console.log(boxen(`${emojis.atom} ${colors.brain('NEURAL TYPE SYSTEM')}\n\n` +
1740
- `${colors.retro('β—† Available Noun Types:')} ${colors.highlight(Object.keys(NounType).length.toString())}\n` +
1741
- `${colors.retro('β—† Available Verb Types:')} ${colors.highlight(Object.keys(VerbType).length.toString())}\n\n` +
1742
- `${colors.accent('β—†')} ${colors.dim('Noun categories: Person, Organization, Location, Thing, Concept, Event...')}\n` +
1743
- `${colors.accent('β—†')} ${colors.dim('Verb categories: Social, Temporal, Causal, Ownership, Functional...')}`, { padding: 1, borderStyle: 'round', borderColor: '#E88B5A' }));
1744
- // Show sample types
1745
- console.log(`\n${colors.highlight('Sample Noun Types:')}`);
1746
- Object.entries(NounType).slice(0, 8).forEach(([key, value]) => {
1747
- console.log(` ${colors.primary('β€’')} ${key}: ${colors.dim(value)}`);
1748
- });
1749
- console.log(`\n${colors.highlight('Sample Verb Types:')}`);
1750
- Object.entries(VerbType).slice(0, 8).forEach(([key, value]) => {
1751
- console.log(` ${colors.primary('β€’')} ${key}: ${colors.dim(value)}`);
1752
- });
1753
- console.log(`\n${colors.dim('Use')} ${colors.primary('brainy import --cortex <file>')} ${colors.dim('to leverage the full AI type system!')}`);
1754
- }
1755
- /**
1756
- * Augmentation Pipeline Management - Control the Neural Enhancement System
1757
- */
1758
- async listAugmentations() {
1759
- await this.ensureInitialized();
1760
- const spinner = ora('Scanning augmentation systems...').start();
1761
- try {
1762
- // Get current pipeline configuration (placeholder for now)
1763
- spinner.stop();
1764
- // For now, show that augmentation system is available but needs integration
1765
- console.log(colors.info(`${emojis.atom} Augmentation system detected but integration pending`));
1766
- // Show current pipeline status
1767
- console.log(boxen(`${emojis.atom} ${colors.brain('AUGMENTATION PIPELINE STATUS')}\n\n` +
1768
- `${colors.retro('β—† Pipeline State:')} ${colors.success('ACTIVE')}\n` +
1769
- `${colors.retro('β—† Registry Loaded:')} ${colors.success('OPERATIONAL')}\n` +
1770
- `${colors.retro('β—† Available Categories:')} SENSE, MEMORY, COGNITION, CONDUIT, ACTIVATION, PERCEPTION, DIALOG, WEBSOCKET`, { padding: 1, borderStyle: 'round', borderColor: '#E88B5A' }));
1771
- // List active augmentations by category
1772
- const categories = ['SENSE', 'MEMORY', 'COGNITION', 'CONDUIT', 'ACTIVATION', 'PERCEPTION', 'DIALOG', 'WEBSOCKET'];
1773
- for (const category of categories) {
1774
- console.log(`\n${colors.highlight(category)} ${colors.dim('Augmentations:')}`);
1775
- // This would need to be implemented in the actual augmentation system
1776
- // For now, show example structure
1777
- console.log(` ${colors.dim('β€’ Available augmentations would be listed here')}\n ${colors.dim('β€’ Status: Active/Inactive')}\n ${colors.dim('β€’ Configuration: Parameters')}`);
1778
- }
1779
- }
1780
- catch (error) {
1781
- spinner.fail('Failed to scan augmentations');
1782
- console.error(error);
1783
- }
1784
- }
1785
- async addAugmentation(type, position, config) {
1786
- await this.ensureInitialized();
1787
- console.log(boxen(`${emojis.magic} ${colors.retro('NEURAL ENHANCEMENT PROTOCOL')}\n\n` +
1788
- `${colors.accent('β—†')} ${colors.dim('Adding augmentation to pipeline')}\n` +
1789
- `${colors.accent('β—†')} ${colors.dim('Type:')} ${colors.highlight(type)}\n` +
1790
- `${colors.accent('β—†')} ${colors.dim('Position:')} ${colors.highlight(position || 'auto')}`, { padding: 1, borderStyle: 'round', borderColor: '#D67441' }));
1791
- const { confirm } = await prompts({
1792
- type: 'confirm',
1793
- name: 'confirm',
1794
- message: 'Add this augmentation to the pipeline?',
1795
- initial: true
1796
- });
1797
- if (!confirm) {
1798
- console.log(colors.dim('Augmentation addition cancelled'));
1799
- return;
1800
- }
1801
- const spinner = ora('Installing augmentation...').start();
1802
- try {
1803
- // This would interface with the actual augmentation system
1804
- // For now, simulate the process
1805
- await new Promise(resolve => setTimeout(resolve, 1000));
1806
- spinner.succeed(colors.success(`${emojis.check} Augmentation '${type}' added to pipeline`));
1807
- console.log(colors.dim(`Position: ${position || 'auto-assigned'}`));
1808
- }
1809
- catch (error) {
1810
- spinner.fail('Failed to add augmentation');
1811
- console.error(error);
1812
- }
1813
- }
1814
- async removeAugmentation(type) {
1815
- await this.ensureInitialized();
1816
- console.log(boxen(`${emojis.warning} ${colors.retro('AUGMENTATION REMOVAL PROTOCOL')}\n\n` +
1817
- `${colors.accent('β—†')} ${colors.dim('This will remove the augmentation from the pipeline')}\n` +
1818
- `${colors.accent('β—†')} ${colors.dim('Type:')} ${colors.highlight(type)}`, { padding: 1, borderStyle: 'round', borderColor: '#D67441' }));
1819
- const { confirm } = await prompts({
1820
- type: 'confirm',
1821
- name: 'confirm',
1822
- message: 'Remove this augmentation?',
1823
- initial: false
1824
- });
1825
- if (!confirm) {
1826
- console.log(colors.dim('Augmentation removal cancelled'));
1827
- return;
1828
- }
1829
- const spinner = ora('Removing augmentation...').start();
1830
- try {
1831
- // Interface with augmentation system
1832
- await new Promise(resolve => setTimeout(resolve, 1000));
1833
- spinner.succeed(colors.success(`${emojis.check} Augmentation '${type}' removed from pipeline`));
1834
- }
1835
- catch (error) {
1836
- spinner.fail('Failed to remove augmentation');
1837
- console.error(error);
1838
- }
1839
- }
1840
- async configureAugmentation(type, config) {
1841
- await this.ensureInitialized();
1842
- console.log(boxen(`${emojis.config} ${colors.brain('AUGMENTATION CONFIGURATION')}\n\n` +
1843
- `${colors.retro('β—† Type:')} ${colors.highlight(type)}\n` +
1844
- `${colors.retro('β—† New Config:')} ${colors.dim(JSON.stringify(config, null, 2))}`, { padding: 1, borderStyle: 'round', borderColor: '#E88B5A' }));
1845
- const { confirm } = await prompts({
1846
- type: 'confirm',
1847
- name: 'confirm',
1848
- message: 'Apply this configuration?',
1849
- initial: true
1850
- });
1851
- if (!confirm) {
1852
- console.log(colors.dim('Configuration cancelled'));
1853
- return;
1854
- }
1855
- const spinner = ora('Updating augmentation configuration...').start();
1856
- try {
1857
- // Interface with augmentation configuration system
1858
- await new Promise(resolve => setTimeout(resolve, 1000));
1859
- spinner.succeed(colors.success(`${emojis.check} Augmentation '${type}' configuration updated`));
1860
- }
1861
- catch (error) {
1862
- spinner.fail('Failed to configure augmentation');
1863
- console.error(error);
1864
- }
1865
- }
1866
- async resetPipeline() {
1867
- await this.ensureInitialized();
1868
- console.log(boxen(`${emojis.warning} ${colors.retro('PIPELINE RESET PROTOCOL')}\n\n` +
1869
- `${colors.accent('β—†')} ${colors.dim('This will reset the entire augmentation pipeline')}\n` +
1870
- `${colors.accent('β—†')} ${colors.dim('All custom configurations will be lost')}\n` +
1871
- `${colors.accent('β—†')} ${colors.dim('Pipeline will return to default state')}`, { padding: 1, borderStyle: 'round', borderColor: '#D67441' }));
1872
- const { confirm } = await prompts({
1873
- type: 'confirm',
1874
- name: 'confirm',
1875
- message: 'Reset augmentation pipeline to defaults?',
1876
- initial: false
1877
- });
1878
- if (!confirm) {
1879
- console.log(colors.dim('Pipeline reset cancelled'));
1880
- return;
1881
- }
1882
- const spinner = ora('Resetting augmentation pipeline...').start();
1883
- try {
1884
- // Interface with pipeline reset system
1885
- await new Promise(resolve => setTimeout(resolve, 2000));
1886
- spinner.succeed(colors.success(`${emojis.atom} Augmentation pipeline reset to factory defaults`));
1887
- console.log(colors.dim('All augmentations restored to default configuration'));
1888
- }
1889
- catch (error) {
1890
- spinner.fail('Failed to reset pipeline');
1891
- console.error(error);
1892
- }
1893
- }
1894
- async executePipelineStep(step, data) {
1895
- await this.ensureInitialized();
1896
- const spinner = ora(`Executing ${step} augmentation step...`).start();
1897
- try {
1898
- // Interface with pipeline execution system
1899
- await new Promise(resolve => setTimeout(resolve, 1500));
1900
- spinner.succeed(colors.success(`${emojis.magic} Pipeline step '${step}' executed successfully`));
1901
- console.log(colors.dim('Result: '), colors.highlight('[Processed data would be shown here]'));
1902
- }
1903
- catch (error) {
1904
- spinner.fail(`Failed to execute pipeline step '${step}'`);
1905
- console.error(error);
1906
- }
1907
- }
1908
- /**
1909
- * Backup & Restore System - Atomic Data Preservation
1910
- */
1911
- async backup(options = {}) {
1912
- await this.ensureInitialized();
1913
- const { BackupRestore } = await import('./backupRestore.js');
1914
- const backupSystem = new BackupRestore(this.brainy);
1915
- const backupPath = await backupSystem.createBackup({
1916
- compress: options.compress,
1917
- output: options.output,
1918
- includeMetadata: true,
1919
- includeStatistics: true,
1920
- verify: true
1921
- });
1922
- console.log(colors.success(`\nπŸŽ‰ Backup complete! Saved to: ${backupPath}`));
1923
- }
1924
- async restore(file) {
1925
- await this.ensureInitialized();
1926
- const { BackupRestore } = await import('./backupRestore.js');
1927
- const backupSystem = new BackupRestore(this.brainy);
1928
- await backupSystem.restoreBackup(file, {
1929
- verify: true,
1930
- overwrite: false // Will prompt user for confirmation
1931
- });
1932
- }
1933
- async listBackups(directory = './backups') {
1934
- const { BackupRestore } = await import('./backupRestore.js');
1935
- const backupSystem = new BackupRestore(this.brainy);
1936
- console.log(boxen(`${emojis.brain} ${colors.brain('ATOMIC VAULT INVENTORY')} ${emojis.atom}`, { padding: 1, borderStyle: 'round', borderColor: '#E88B5A' }));
1937
- const backups = await backupSystem.listBackups(directory);
1938
- if (backups.length === 0) {
1939
- console.log(colors.dim('No backups found in vault'));
1940
- return;
1941
- }
1942
- const table = new Table({
1943
- head: [colors.brain('Date'), colors.brain('Entities'), colors.brain('Relationships'), colors.brain('Size'), colors.brain('Type')],
1944
- colWidths: [20, 12, 15, 12, 15]
1945
- });
1946
- backups.forEach(backup => {
1947
- table.push([
1948
- colors.highlight(new Date(backup.timestamp).toLocaleDateString()),
1949
- colors.primary(backup.entityCount.toLocaleString()),
1950
- colors.primary(backup.relationshipCount.toLocaleString()),
1951
- colors.warning(backup.compressed ? 'Compressed' : 'Raw'),
1952
- colors.success(backup.storageType)
1953
- ]);
1954
- });
1955
- console.log(table.toString());
1956
- }
1957
- /**
1958
- * Show augmentation status and management
1959
- */
1960
- async augmentations(options = {}) {
1961
- console.log(boxen(`${this.emojis.brain} ${this.colors.brain('AUGMENTATION STATUS')} ${this.emojis.atom}`, { padding: 1, borderStyle: 'round', borderColor: '#E88B5A' }));
1962
- await this.ensureBrainy();
1963
- try {
1964
- // Import default augmentation registry
1965
- const { DefaultAugmentationRegistry } = await import('../shared/default-augmentations.js');
1966
- const registry = new DefaultAugmentationRegistry(this.brainy);
1967
- // Check Cortex health (default augmentation)
1968
- const cortexHealth = await registry.checkCortexHealth();
1969
- console.log(`\n${this.emojis.sparkles} ${this.colors.accent('Default Augmentations:')}`);
1970
- console.log(` ${this.emojis.brain} Cortex: ${cortexHealth.available ? this.colors.success('Active') : this.colors.error('Inactive')}`);
1971
- if (cortexHealth.version) {
1972
- console.log(` ${this.colors.dim('Version:')} ${cortexHealth.version}`);
1973
- }
1974
- console.log(` ${this.colors.dim('Status:')} ${cortexHealth.status}`);
1975
- console.log(` ${this.colors.dim('Category:')} SENSE (AI-powered data understanding)`);
1976
- console.log(` ${this.colors.dim('License:')} Open Source (included by default)`);
1977
- // Check for premium augmentations if license exists
1978
- if (this.licensingSystem) {
1979
- console.log(`\n${this.emojis.sparkles} ${this.colors.premium('Premium Augmentations:')}`);
1980
- // Check each premium feature from our licensing system
1981
- const premiumFeatures = [
1982
- 'notion-connector',
1983
- 'salesforce-connector',
1984
- 'slack-connector',
1985
- 'asana-connector',
1986
- 'neural-enhancement-pack'
1987
- ];
1988
- for (const feature of premiumFeatures) {
1989
- // This would check if the feature is licensed and installed
1990
- console.log(` ${this.emojis.gear} ${feature}: ${this.colors.dim('Not Installed')}`);
1991
- console.log(` ${this.colors.dim('Status:')} Available for trial/purchase`);
1992
- }
1993
- console.log(`\n${this.colors.dim('Use')} ${this.colors.highlight('cortex license catalog')} ${this.colors.dim('to see available premium augmentations')}`);
1994
- console.log(`${this.colors.dim('Use')} ${this.colors.highlight('cortex license trial <feature>')} ${this.colors.dim('to start a free trial')}`);
1995
- }
1996
- // Augmentation pipeline health
1997
- console.log(`\n${this.emojis.health} ${this.colors.accent('Pipeline Health:')}`);
1998
- console.log(` ${this.emojis.check} SENSE Pipeline: ${this.colors.success('1 active')} (Cortex)`);
1999
- console.log(` ${this.emojis.info} CONDUIT Pipeline: ${this.colors.dim('0 active')} (Premium connectors available)`);
2000
- console.log(` ${this.emojis.info} COGNITION Pipeline: ${this.colors.dim('0 active')}`);
2001
- console.log(` ${this.emojis.info} MEMORY Pipeline: ${this.colors.dim('0 active')}`);
2002
- if (options.verbose) {
2003
- console.log(`\n${this.emojis.info} ${this.colors.accent('Augmentation Categories:')}`);
2004
- console.log(` ${this.colors.highlight('SENSE:')} Input processing and data understanding`);
2005
- console.log(` ${this.colors.highlight('CONDUIT:')} External system integrations and sync`);
2006
- console.log(` ${this.colors.highlight('COGNITION:')} AI reasoning and analysis`);
2007
- console.log(` ${this.colors.highlight('MEMORY:')} Enhanced storage and retrieval`);
2008
- console.log(` ${this.colors.highlight('PERCEPTION:')} Pattern recognition and insights`);
2009
- console.log(` ${this.colors.highlight('DIALOG:')} Conversational interfaces`);
2010
- console.log(` ${this.colors.highlight('ACTIVATION:')} Automation and triggers`);
2011
- console.log(` ${this.colors.highlight('WEBSOCKET:')} Real-time communications`);
2012
- }
2013
- }
2014
- catch (error) {
2015
- console.error(`${this.emojis.cross} Failed to get augmentation status:`, error instanceof Error ? error.message : String(error));
2016
- }
2017
- }
2018
- /**
2019
- * Performance Monitoring & Health Check System - Atomic Age Intelligence Observatory
2020
- */
2021
- async monitor(options = {}) {
2022
- await this.ensureInitialized();
2023
- if (!this.performanceMonitor) {
2024
- console.log(colors.error('Performance monitor not initialized'));
2025
- return;
2026
- }
2027
- if (options.dashboard) {
2028
- // Interactive dashboard mode
2029
- console.log(boxen(`${emojis.stats} ${colors.brain('ATOMIC PERFORMANCE OBSERVATORY')} ${emojis.atom}\n\n` +
2030
- `${colors.accent('β—†')} ${colors.dim('Real-time vector + graph database monitoring')}\n` +
2031
- `${colors.accent('β—†')} ${colors.dim('Press Ctrl+C to exit dashboard')}`, { padding: 1, borderStyle: 'round', borderColor: '#E88B5A' }));
2032
- // Start monitoring in background
2033
- await this.performanceMonitor.startMonitoring(5000); // 5 second intervals
2034
- // Display dashboard in loop
2035
- const dashboardInterval = setInterval(async () => {
2036
- try {
2037
- await this.performanceMonitor.displayDashboard();
2038
- }
2039
- catch (error) {
2040
- console.error('Dashboard update failed:', error);
2041
- }
2042
- }, 5000);
2043
- // Handle cleanup on exit
2044
- process.on('SIGINT', () => {
2045
- clearInterval(dashboardInterval);
2046
- this.performanceMonitor.stopMonitoring();
2047
- console.log('\n' + colors.dim('Performance monitoring stopped'));
2048
- process.exit(0);
2049
- });
2050
- // Keep process alive
2051
- await new Promise(() => { });
2052
- }
2053
- else {
2054
- // Single snapshot mode
2055
- const metrics = await this.performanceMonitor.getCurrentMetrics();
2056
- console.log(boxen(`${emojis.stats} ${colors.brain('PERFORMANCE SNAPSHOT')} ${emojis.atom}`, { padding: 1, borderStyle: 'round', borderColor: '#E88B5A' }));
2057
- console.log(`\n${colors.accent('Vector Query Latency:')} ${colors.primary(metrics.queryLatency.vector.avg.toFixed(1) + 'ms')}`);
2058
- console.log(`${colors.accent('Graph Query Latency:')} ${colors.primary(metrics.queryLatency.graph.avg.toFixed(1) + 'ms')}`);
2059
- console.log(`${colors.accent('Combined Throughput:')} ${colors.success(metrics.throughput.totalOps.toFixed(0) + ' ops/sec')}`);
2060
- console.log(`${colors.accent('Cache Hit Rate:')} ${colors.success((metrics.storage.cacheHitRate * 100).toFixed(1) + '%')}`);
2061
- console.log(`${colors.accent('Overall Health:')} ${colors.primary(metrics.health.overall + '/100')}`);
2062
- }
2063
- }
2064
- async health(options = {}) {
2065
- await this.ensureInitialized();
2066
- if (!this.healthCheck) {
2067
- console.log(colors.error('Health check system not initialized'));
2068
- return;
2069
- }
2070
- if (options.autoFix) {
2071
- // Run health check and auto-repair
2072
- const health = await this.healthCheck.runHealthCheck();
2073
- await this.healthCheck.displayHealthReport(health);
2074
- console.log('\n' + colors.brain(`${emojis.repair} INITIATING AUTO-REPAIR SEQUENCE`));
2075
- const results = await this.healthCheck.executeAutoRepairs();
2076
- if (results.success.length > 0 || results.failed.length > 0) {
2077
- // Run health check again to show improvements
2078
- console.log('\n' + colors.info('Running post-repair health check...'));
2079
- await this.healthCheck.displayHealthReport();
2080
- }
2081
- }
2082
- else {
2083
- // Standard health check
2084
- await this.healthCheck.displayHealthReport();
2085
- // Show available repair actions
2086
- const repairs = await this.healthCheck.getRepairActions();
2087
- const safeRepairs = repairs.filter(r => r.automated && r.riskLevel === 'safe');
2088
- if (safeRepairs.length > 0) {
2089
- console.log('\n' + colors.info(`${emojis.info} Run 'cortex health --auto-fix' to apply ${safeRepairs.length} safe automated repairs`));
2090
- }
2091
- }
2092
- }
2093
- async performance(options = {}) {
2094
- await this.ensureInitialized();
2095
- if (!this.performanceMonitor) {
2096
- console.log(colors.error('Performance monitor not initialized'));
2097
- return;
2098
- }
2099
- if (options.analyze) {
2100
- // Detailed performance analysis
2101
- console.log(boxen(`${emojis.lab} ${colors.brain('PERFORMANCE ANALYSIS ENGINE')} ${emojis.atom}\n\n` +
2102
- `${colors.accent('β—†')} ${colors.dim('Deep analysis of vector + graph performance')}\n` +
2103
- `${colors.accent('β—†')} ${colors.dim('Collecting metrics over 30 seconds...')}`, { padding: 1, borderStyle: 'round', borderColor: '#E88B5A' }));
2104
- const spinner = ora('Analyzing neural pathway performance...').start();
2105
- // Start monitoring to collect data
2106
- await this.performanceMonitor.startMonitoring(2000); // 2 second intervals
2107
- // Wait for data collection
2108
- await new Promise(resolve => setTimeout(resolve, 30000));
2109
- // Stop monitoring and get dashboard data
2110
- this.performanceMonitor.stopMonitoring();
2111
- const dashboard = await this.performanceMonitor.getDashboard();
2112
- spinner.succeed('Performance analysis complete');
2113
- // Display detailed analysis
2114
- console.log('\n' + colors.brain(`${emojis.lightning} DETAILED ANALYSIS RESULTS`));
2115
- const current = dashboard.current;
2116
- const trends = dashboard.trends;
2117
- if (trends.length > 1) {
2118
- const first = trends[0];
2119
- const last = trends[trends.length - 1];
2120
- const vectorTrend = last.queryLatency.vector.avg - first.queryLatency.vector.avg;
2121
- const graphTrend = last.queryLatency.graph.avg - first.queryLatency.graph.avg;
2122
- const throughputTrend = last.throughput.totalOps - first.throughput.totalOps;
2123
- console.log(`\n${colors.accent('Vector Performance Trend:')} ${vectorTrend > 0 ? colors.warning('↑') : colors.success('↓')} ${Math.abs(vectorTrend).toFixed(1)}ms`);
2124
- console.log(`${colors.accent('Graph Performance Trend:')} ${graphTrend > 0 ? colors.warning('↑') : colors.success('↓')} ${Math.abs(graphTrend).toFixed(1)}ms`);
2125
- console.log(`${colors.accent('Throughput Trend:')} ${throughputTrend > 0 ? colors.success('↑') : colors.warning('↓')} ${Math.abs(throughputTrend).toFixed(0)} ops/sec`);
2126
- }
2127
- // Show recommendations
2128
- console.log('\n' + colors.brain(`${emojis.sparkle} OPTIMIZATION RECOMMENDATIONS`));
2129
- if (current.queryLatency.vector.p95 > 100) {
2130
- console.log(` ${colors.warning('β†’')} Vector query P95 latency is high - consider rebuilding HNSW index`);
2131
- }
2132
- if (current.storage.cacheHitRate < 0.8) {
2133
- console.log(` ${colors.warning('β†’')} Cache hit rate is below 80% - consider increasing cache size`);
2134
- }
2135
- if (current.memory.heapUsed > 1000) {
2136
- console.log(` ${colors.warning('β†’')} Memory usage is high - consider running garbage collection`);
2137
- }
2138
- if (current.health.overall < 85) {
2139
- console.log(` ${colors.error('β†’')} Overall health below 85% - run 'cortex health --auto-fix'`);
2140
- }
2141
- }
2142
- else {
2143
- // Quick performance overview
2144
- const metrics = await this.performanceMonitor.getCurrentMetrics();
2145
- console.log(boxen(`${emojis.rocket} ${colors.brain('QUICK PERFORMANCE OVERVIEW')} ${emojis.atom}`, { padding: 1, borderStyle: 'round', borderColor: '#E88B5A' }));
2146
- console.log(`\n${colors.brain('Vector + Graph Database Performance:')}\n`);
2147
- console.log(` ${colors.accent('Vector Operations:')} ${colors.primary(metrics.queryLatency.vector.avg.toFixed(1) + 'ms avg')} | ${colors.highlight(metrics.throughput.vectorOps.toFixed(0) + ' ops/sec')}`);
2148
- console.log(` ${colors.accent('Graph Operations:')} ${colors.primary(metrics.queryLatency.graph.avg.toFixed(1) + 'ms avg')} | ${colors.highlight(metrics.throughput.graphOps.toFixed(0) + ' ops/sec')}`);
2149
- console.log(` ${colors.accent('Storage Performance:')} ${colors.success((metrics.storage.cacheHitRate * 100).toFixed(1) + '% cache hit')} | ${colors.info(metrics.storage.readLatency.toFixed(1) + 'ms read')}`);
2150
- console.log(` ${colors.accent('Memory Usage:')} ${colors.primary(metrics.memory.heapUsed.toFixed(0) + 'MB')} | ${colors.success((metrics.memory.efficiency * 100).toFixed(1) + '% efficient')}`);
2151
- console.log(`\n${colors.dim('For detailed analysis: cortex performance --analyze')}`);
2152
- }
2153
- }
2154
- /**
2155
- * Premium Features - Redirect to Brain Cloud
2156
- */
2157
- async licenseCatalog() {
2158
- console.log(boxen(`${emojis.brain}☁️ ${colors.brain('BRAIN CLOUD PREMIUM FEATURES')}\n\n` +
2159
- `Premium connectors and features have moved to Brain Cloud!\n\n` +
2160
- `${colors.accent('β—†')} ${colors.dim('Setup Brain Cloud:')} ${colors.highlight('brainy cloud')}\n` +
2161
- `${colors.accent('β—†')} ${colors.dim('Learn more:')} ${colors.highlight('https://soulcraft.com/brain-cloud')}\n\n` +
2162
- `${colors.retro('Available Tiers:')}\n` +
2163
- `${colors.success('πŸ«™')} Brain Jar (Free) - Local coordination\n` +
2164
- `${colors.success('☁️')} Brain Cloud ($19/mo) - Sync everywhere\n` +
2165
- `${colors.success('🏦')} Brain Bank ($99/mo) - Enterprise features`, { padding: 1, borderStyle: 'round', borderColor: '#D67441' }));
2166
- }
2167
- async licenseStatus(licenseId) {
2168
- console.log(colors.info('License management has moved to Brain Cloud'));
2169
- console.log(colors.dim('Run: brainy cloud'));
2170
- }
2171
- async licenseTrial(featureId, customerName, customerEmail) {
2172
- console.log(boxen(`${emojis.sparkle} ${colors.brain('START YOUR BRAIN CLOUD TRIAL')}\n\n` +
2173
- `${colors.accent('β—†')} ${colors.dim('14-day free trial')}\n` +
2174
- `${colors.accent('β—†')} ${colors.dim('No credit card required')}\n` +
2175
- `${colors.accent('β—†')} ${colors.dim('Cancel anytime')}\n\n` +
2176
- `${colors.highlight('Run: brainy cloud')}\n\n` +
2177
- `Or visit: ${colors.accent('https://soulcraft.com/brain-cloud')}`, { padding: 1, borderStyle: 'round', borderColor: '#FFD700' }));
2178
- }
2179
- async licenseValidate(featureId) {
2180
- console.log(colors.info('Premium features available in Brain Cloud'));
2181
- console.log(colors.dim('Setup: brainy cloud'));
2182
- return false;
2183
- }
2184
- /**
2185
- * Check if a premium feature is available
2186
- */
2187
- async requirePremiumFeature(featureId, silent = false) {
2188
- if (!silent) {
2189
- console.log(boxen(`${emojis.lock} ${colors.brain('BRAIN CLOUD FEATURE')} ${emojis.atom}\n\n` +
2190
- `This feature is available in Brain Cloud!\n\n` +
2191
- `${colors.highlight('Setup: brainy cloud')}\n` +
2192
- `${colors.dim('Learn more: https://soulcraft.com/brain-cloud')}`, { padding: 1, borderStyle: 'round', borderColor: '#D67441' }));
2193
- }
2194
- return false;
2195
- }
2196
- /**
2197
- * Brain Jar AI Coordination Methods
2198
- */
2199
- async brainJarInstall(mode) {
2200
- const spinner = ora('Installing Brain Jar coordination...').start();
2201
- try {
2202
- if (mode === 'premium') {
2203
- spinner.text = 'Opening Brain Jar Premium signup...';
2204
- // This would open browser to brain-jar.com
2205
- console.log('\n' + boxen(`${emojis.brain}${emojis.rocket} ${colors.brain('BRAIN JAR PREMIUM')}\n\n` +
2206
- `${colors.accent('β—†')} ${colors.dim('Opening signup at:')} ${colors.highlight('https://brain-jar.com')}\n` +
2207
- `${colors.accent('β—†')} ${colors.dim('After signup, return to configure your API key')}\n\n` +
2208
- `${colors.retro('Features:')}\n` +
2209
- `${colors.success('βœ…')} Global AI coordination\n` +
2210
- `${colors.success('βœ…')} Multi-device sync\n` +
2211
- `${colors.success('βœ…')} Team workspaces\n` +
2212
- `${colors.success('βœ…')} Premium dashboard`, { padding: 1, borderStyle: 'double', borderColor: '#D67441' }));
2213
- // Open browser (would be implemented)
2214
- console.log(colors.info('\nπŸ’‘ Run: export BRAIN_JAR_KEY="your-api-key" after signup'));
2215
- }
2216
- else {
2217
- spinner.text = 'Setting up local Brain Jar server...';
2218
- console.log('\n' + boxen(`${emojis.brain}${emojis.tube} ${colors.brain('BRAIN JAR FREE')}\n\n` +
2219
- `${colors.accent('β—†')} ${colors.dim('Local AI coordination installed')}\n` +
2220
- `${colors.accent('β—†')} ${colors.dim('Server:')} ${colors.highlight('localhost:8765')}\n` +
2221
- `${colors.accent('β—†')} ${colors.dim('Dashboard:')} ${colors.highlight('localhost:3000')}\n\n` +
2222
- `${colors.retro('Features:')}\n` +
2223
- `${colors.success('βœ…')} Local AI coordination\n` +
2224
- `${colors.success('βœ…')} Real-time dashboard\n` +
2225
- `${colors.success('βœ…')} Vector storage`, { padding: 1, borderStyle: 'round', borderColor: '#2D4A3A' }));
2226
- }
2227
- spinner.succeed(`Brain Jar ${mode} installation complete!`);
2228
- }
2229
- catch (error) {
2230
- spinner.fail('Brain Jar installation failed');
2231
- console.error(colors.error('Error:'), error.message);
2232
- }
2233
- }
2234
- async brainJarStart(options) {
2235
- const spinner = ora('Starting Brain Jar coordination...').start();
2236
- try {
2237
- const isCloudMode = process.env.BRAIN_JAR_KEY !== undefined;
2238
- const serverUrl = options.server || (isCloudMode ? 'wss://api.brain-jar.com/ws' : 'ws://localhost:8765');
2239
- spinner.text = `Connecting to ${isCloudMode ? 'cloud' : 'local'} coordination...`;
2240
- console.log('\n' + boxen(`${emojis.brain}${emojis.network} ${colors.brain('BRAIN JAR COORDINATION ACTIVE')}\n\n` +
2241
- `${colors.accent('β—†')} ${colors.dim('Mode:')} ${colors.highlight(isCloudMode ? 'Premium Cloud' : 'Local Free')}\n` +
2242
- `${colors.accent('β—†')} ${colors.dim('Server:')} ${colors.highlight(serverUrl)}\n` +
2243
- `${colors.accent('β—†')} ${colors.dim('Agent:')} ${colors.highlight(options.name || 'Claude-Agent')}\n` +
2244
- `${colors.accent('β—†')} ${colors.dim('Role:')} ${colors.highlight(options.role || 'Assistant')}\n\n` +
2245
- `${colors.success('βœ…')} All Claude instances will now coordinate automatically!`, { padding: 1, borderStyle: 'round', borderColor: isCloudMode ? '#D67441' : '#2D4A3A' }));
2246
- spinner.succeed('Brain Jar coordination started!');
2247
- console.log(colors.dim('\nπŸ’‘ Keep this terminal open for coordination to remain active'));
2248
- console.log(colors.primary(`πŸ”— Dashboard: brainy brain-jar dashboard`));
2249
- }
2250
- catch (error) {
2251
- spinner.fail('Failed to start Brain Jar');
2252
- console.error(colors.error('Error:'), error.message);
2253
- }
2254
- }
2255
- async brainJarDashboard(shouldOpen = true) {
2256
- const isCloudMode = process.env.BRAIN_JAR_KEY !== undefined;
2257
- const dashboardUrl = isCloudMode ? 'https://dashboard.brain-jar.com' : 'http://localhost:3000/dashboard';
2258
- console.log(boxen(`${emojis.data}${emojis.brain} ${colors.brain('BRAIN JAR DASHBOARD')}\n\n` +
2259
- `${colors.accent('β—†')} ${colors.dim('URL:')} ${colors.highlight(dashboardUrl)}\n` +
2260
- `${colors.accent('β—†')} ${colors.dim('Mode:')} ${colors.highlight(isCloudMode ? 'Premium Cloud' : 'Local Free')}\n\n` +
2261
- `${colors.retro('Features:')}\n` +
2262
- `${colors.success('βœ…')} Live agent coordination\n` +
2263
- `${colors.success('βœ…')} Real-time conversation view\n` +
2264
- `${colors.success('βœ…')} Search coordination history\n` +
2265
- `${colors.success('βœ…')} Performance metrics`, { padding: 1, borderStyle: 'round', borderColor: isCloudMode ? '#D67441' : '#2D4A3A' }));
2266
- if (shouldOpen) {
2267
- console.log(colors.success(`\nπŸš€ Opening dashboard: ${dashboardUrl}`));
2268
- // Would open browser here
2269
- }
2270
- }
2271
- async brainJarStatus() {
2272
- const isCloudMode = process.env.BRAIN_JAR_KEY !== undefined;
2273
- console.log(boxen(`${emojis.brain}${emojis.stats} ${colors.brain('BRAIN JAR STATUS')}\n\n` +
2274
- `${colors.accent('β—†')} ${colors.dim('Mode:')} ${colors.highlight(isCloudMode ? 'Premium Cloud' : 'Local Free')}\n` +
2275
- `${colors.accent('β—†')} ${colors.dim('Status:')} ${colors.success('Active')}\n` +
2276
- `${colors.accent('β—†')} ${colors.dim('Connected Agents:')} ${colors.highlight('2')}\n` +
2277
- `${colors.accent('β—†')} ${colors.dim('Total Messages:')} ${colors.highlight('47')}\n` +
2278
- `${colors.accent('β—†')} ${colors.dim('Uptime:')} ${colors.highlight('15m 32s')}\n\n` +
2279
- `${colors.success('βœ…')} All systems operational!`, { padding: 1, borderStyle: 'round', borderColor: '#2D4A3A' }));
2280
- }
2281
- async brainJarStop() {
2282
- const spinner = ora('Stopping Brain Jar coordination...').start();
2283
- try {
2284
- // Would stop coordination server/connections here
2285
- spinner.succeed('Brain Jar coordination stopped');
2286
- console.log(colors.warning('⚠️ AI agents will no longer coordinate'));
2287
- console.log(colors.dim('πŸ’‘ Run: brainy brain-jar start to resume coordination'));
2288
- }
2289
- catch (error) {
2290
- spinner.fail('Failed to stop Brain Jar');
2291
- console.error(colors.error('Error:'), error.message);
2292
- }
2293
- }
2294
- async brainJarAgents() {
2295
- console.log(boxen(`${emojis.robot}${emojis.network} ${colors.brain('CONNECTED AGENTS')}\n\n` +
2296
- `${colors.success('πŸ€–')} ${colors.highlight('Jarvis')} - ${colors.dim('Backend Systems')}\n` +
2297
- ` ${colors.dim('Status:')} ${colors.success('Connected')}\n` +
2298
- ` ${colors.dim('Last Active:')} ${colors.dim('2 minutes ago')}\n\n` +
2299
- `${colors.success('🎨')} ${colors.highlight('Picasso')} - ${colors.dim('Frontend Design')}\n` +
2300
- ` ${colors.dim('Status:')} ${colors.success('Connected')}\n` +
2301
- ` ${colors.dim('Last Active:')} ${colors.dim('30 seconds ago')}\n\n` +
2302
- `${colors.accent('Total Active Agents:')} ${colors.highlight('2')}`, { padding: 1, borderStyle: 'round', borderColor: '#2D4A3A' }));
2303
- }
2304
- async brainJarMessage(text) {
2305
- const spinner = ora('Broadcasting message to coordination channel...').start();
2306
- try {
2307
- // Would send message through coordination system here
2308
- spinner.succeed('Message sent to all connected agents');
2309
- console.log(boxen(`${emojis.chat}${emojis.network} ${colors.brain('MESSAGE BROADCAST')}\n\n` +
2310
- `${colors.dim('Message:')} ${colors.highlight(text)}\n` +
2311
- `${colors.dim('Recipients:')} ${colors.success('All connected agents')}\n` +
2312
- `${colors.dim('Timestamp:')} ${colors.dim(new Date().toLocaleTimeString())}`, { padding: 1, borderStyle: 'round', borderColor: '#D67441' }));
2313
- }
2314
- catch (error) {
2315
- spinner.fail('Failed to send message');
2316
- console.error(colors.error('Error:'), error.message);
2317
- }
2318
- }
2319
- async brainJarSearch(query, limit) {
2320
- const spinner = ora('Searching coordination history...').start();
2321
- try {
2322
- // Would search through coordination messages here
2323
- spinner.succeed(`Found coordination messages for: "${query}"`);
2324
- console.log(boxen(`${emojis.search}${emojis.brain} ${colors.brain('COORDINATION SEARCH RESULTS')}\n\n` +
2325
- `${colors.dim('Query:')} ${colors.highlight(query)}\n` +
2326
- `${colors.dim('Results:')} ${colors.success('5 matches')}\n` +
2327
- `${colors.dim('Limit:')} ${colors.dim(limit.toString())}\n\n` +
2328
- `${colors.success('πŸ“¨')} ${colors.dim('Jarvis:')} "Setting up backend coordination..."\n` +
2329
- `${colors.success('πŸ“¨')} ${colors.dim('Picasso:')} "Frontend components ready for integration..."\n` +
2330
- `${colors.success('πŸ“¨')} ${colors.dim('Jarvis:')} "Database connections established..."\n\n` +
2331
- `${colors.dim('Use')} ${colors.primary('brainy brain-jar dashboard')} ${colors.dim('for visual search')}`, { padding: 1, borderStyle: 'round', borderColor: '#E88B5A' }));
2332
- }
2333
- catch (error) {
2334
- spinner.fail('Search failed');
2335
- console.error(colors.error('Error:'), error.message);
2336
- }
2337
- }
2338
- /**
2339
- * Brain Cloud Super Command - One command to rule them all
2340
- */
2341
- async setupBrainCloud(options) {
2342
- const { prompt } = await import('prompts');
2343
- const colors = this.colors;
2344
- const emojis = this.emojis;
2345
- console.log(boxen(`${emojis.brain}☁️ ${colors.brain('BRAIN CLOUD SETUP')}\n\n` +
2346
- `${colors.accent('Transform your AI into a coordinated system')}\n` +
2347
- `${colors.dim('One command. Global sync. Team coordination.')}\n\n` +
2348
- `${colors.success('βœ…')} Install Brain Jar in Claude Desktop\n` +
2349
- `${colors.success('βœ…')} Configure cloud sync across devices\n` +
2350
- `${colors.success('βœ…')} Setup team workspaces (optional)`, { padding: 1, borderStyle: 'double', borderColor: '#D67441' }));
2351
- // Interactive mode if not specified
2352
- if (options.mode === 'interactive') {
2353
- const response = await prompt([
2354
- {
2355
- type: 'select',
2356
- name: 'tier',
2357
- message: 'Choose your Brain Cloud tier:',
2358
- choices: [
2359
- { title: 'πŸ«™ Brain Jar (Free) - Local coordination only', value: 'free' },
2360
- { title: '☁️ Brain Cloud ($19/mo) - Sync across all devices', value: 'cloud' },
2361
- { title: '🏦 Brain Bank ($99/mo) - Enterprise features', value: 'bank' }
2362
- ],
2363
- initial: 0
2364
- }
2365
- ]);
2366
- if (!response.tier) {
2367
- console.log(colors.warning('Setup cancelled'));
2368
- return;
2369
- }
2370
- options.mode = response.tier;
2371
- }
2372
- const spinner = ora('Setting up Brain Cloud...').start();
2373
- try {
2374
- // Step 1: Install Brain Jar
2375
- if (!options.skipInstall) {
2376
- spinner.text = 'Installing Brain Jar in Claude Desktop...';
2377
- await this.brainJarInstall(options.mode);
2378
- }
2379
- // Step 2: Configure based on tier
2380
- if (options.mode === 'cloud' || options.mode === 'bank') {
2381
- spinner.text = 'Configuring cloud sync...';
2382
- const accountResponse = await prompt([
2383
- {
2384
- type: 'confirm',
2385
- name: 'hasAccount',
2386
- message: 'Do you have a Brain Cloud account?',
2387
- initial: false
2388
- }
2389
- ]);
2390
- if (!accountResponse.hasAccount) {
2391
- console.log('\n' + boxen(`${emojis.sparkles} ${colors.brain('CREATE YOUR ACCOUNT')}\n\n` +
2392
- `${colors.accent('β—†')} Visit: ${colors.highlight('https://soulcraft.com/brain-cloud')}\n` +
2393
- `${colors.accent('β—†')} Click "Start Free Trial"\n` +
2394
- `${colors.accent('β—†')} Get your API key\n` +
2395
- `${colors.accent('β—†')} Return here to continue setup`, { padding: 1, borderStyle: 'round', borderColor: '#FFD700' }));
2396
- const keyResponse = await prompt([
2397
- {
2398
- type: 'text',
2399
- name: 'apiKey',
2400
- message: 'Enter your Brain Cloud API key:'
2401
- }
2402
- ]);
2403
- if (keyResponse.apiKey) {
2404
- await this.configSet('brain-cloud.apiKey', keyResponse.apiKey, { encrypt: true });
2405
- }
2406
- }
2407
- // Enable cloud sync in Brain Jar
2408
- await this.configSet('brain-jar.cloudSync', 'true', {});
2409
- await this.configSet('brain-jar.tier', options.mode, {});
2410
- }
2411
- // Step 3: Start Brain Jar
2412
- spinner.text = 'Starting Brain Jar coordination...';
2413
- await this.brainJarStart({});
2414
- spinner.succeed('Brain Cloud setup complete!');
2415
- // Show success message
2416
- const tierMessages = {
2417
- free: 'Local AI coordination active',
2418
- cloud: 'Cloud sync enabled across all devices',
2419
- bank: 'Enterprise features activated'
2420
- };
2421
- console.log('\n' + boxen(`${emojis.check}${emojis.brain} ${colors.success('BRAIN CLOUD ACTIVE!')}\n\n` +
2422
- `${colors.accent('β—†')} ${colors.dim('Status:')} ${colors.success(tierMessages[options.mode])}\n` +
2423
- `${colors.accent('β—†')} ${colors.dim('Claude Desktop:')} ${colors.success('Brain Jar installed')}\n` +
2424
- `${colors.accent('β—†')} ${colors.dim('MCP Server:')} ${colors.success('Running')}\n\n` +
2425
- `${colors.retro('Next Steps:')}\n` +
2426
- `${colors.cyan('1.')} Open Claude Desktop\n` +
2427
- `${colors.cyan('2.')} Start a new conversation\n` +
2428
- `${colors.cyan('3.')} Your AI now has persistent memory!\n\n` +
2429
- `${colors.dim('Dashboard:')} ${colors.highlight('brainy brain-jar dashboard')}\n` +
2430
- `${colors.dim('Status:')} ${colors.highlight('brainy status')}`, { padding: 1, borderStyle: 'double', borderColor: '#5FD45C' }));
2431
- }
2432
- catch (error) {
2433
- spinner.fail('Setup failed');
2434
- console.error(colors.error('Error:'), error.message);
2435
- console.log('\n' + colors.dim('Need help? Visit https://soulcraft.com/brain-cloud/support'));
2436
- }
2437
- }
2438
- /**
2439
- * Helper method to determine data type from file path
2440
- */
2441
- getDataTypeFromPath(filePath) {
2442
- const path = require('path');
2443
- const ext = path.extname(filePath).toLowerCase();
2444
- switch (ext) {
2445
- case '.json': return 'json';
2446
- case '.csv': return 'csv';
2447
- case '.yaml':
2448
- case '.yml': return 'yaml';
2449
- case '.txt': return 'text';
2450
- default: return 'text';
2451
- }
2452
- }
2453
- }
2454
- /**
2455
- * Configuration categories for enhanced secret management
2456
- */
2457
- Cortex.CONFIG_CATEGORIES = {
2458
- SECRET: 'secret', // Encrypted, never logged
2459
- SENSITIVE: 'sensitive', // Encrypted, logged as [MASKED]
2460
- CONFIG: 'config', // Plain text configuration
2461
- PUBLIC: 'public' // Can be exposed publicly
2462
- };
2463
- //# sourceMappingURL=cortex.js.map