@soulcraft/brainy 0.61.0 β 0.61.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +345 -448
- package/bin/brainy.js +609 -19
- package/dist/augmentationPipeline.d.ts +19 -12
- package/dist/augmentationPipeline.js +19 -11
- package/dist/cli/catalog.d.ts +47 -0
- package/dist/cli/catalog.js +325 -0
- package/dist/cortex/cliWrapper.d.ts +32 -0
- package/dist/cortex/cliWrapper.js +209 -0
- package/dist/cortex/cortex-legacy.d.ts +264 -0
- package/dist/cortex/cortex-legacy.js +2463 -0
- package/dist/cortex/cortex.js +5 -5
- package/dist/cortex/serviceIntegration.d.ts +1 -1
- package/dist/cortex/serviceIntegration.js +1 -1
- package/dist/cortex.d.ts +11 -0
- package/dist/cortex.js +14 -0
- package/dist/index.d.ts +11 -2
- package/dist/index.js +13 -3
- package/package.json +4 -5
|
@@ -0,0 +1,2463 @@
|
|
|
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-legacy.js.map
|