@soulcraft/brainy 1.5.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/CHANGELOG.md +188 -0
  2. package/LICENSE +2 -2
  3. package/README.md +200 -595
  4. package/bin/brainy-interactive.js +564 -0
  5. package/bin/brainy-ts.js +18 -0
  6. package/bin/brainy.js +672 -81
  7. package/dist/augmentationPipeline.d.ts +48 -220
  8. package/dist/augmentationPipeline.js +60 -508
  9. package/dist/augmentationRegistry.d.ts +22 -31
  10. package/dist/augmentationRegistry.js +28 -79
  11. package/dist/augmentations/apiServerAugmentation.d.ts +108 -0
  12. package/dist/augmentations/apiServerAugmentation.js +502 -0
  13. package/dist/augmentations/batchProcessingAugmentation.d.ts +95 -0
  14. package/dist/augmentations/batchProcessingAugmentation.js +567 -0
  15. package/dist/augmentations/brainyAugmentation.d.ts +153 -0
  16. package/dist/augmentations/brainyAugmentation.js +145 -0
  17. package/dist/augmentations/cacheAugmentation.d.ts +105 -0
  18. package/dist/augmentations/cacheAugmentation.js +238 -0
  19. package/dist/augmentations/conduitAugmentations.d.ts +54 -156
  20. package/dist/augmentations/conduitAugmentations.js +156 -1082
  21. package/dist/augmentations/connectionPoolAugmentation.d.ts +62 -0
  22. package/dist/augmentations/connectionPoolAugmentation.js +316 -0
  23. package/dist/augmentations/defaultAugmentations.d.ts +53 -0
  24. package/dist/augmentations/defaultAugmentations.js +88 -0
  25. package/dist/augmentations/entityRegistryAugmentation.d.ts +126 -0
  26. package/dist/augmentations/entityRegistryAugmentation.js +386 -0
  27. package/dist/augmentations/indexAugmentation.d.ts +117 -0
  28. package/dist/augmentations/indexAugmentation.js +284 -0
  29. package/dist/augmentations/intelligentVerbScoringAugmentation.d.ts +152 -0
  30. package/dist/augmentations/intelligentVerbScoringAugmentation.js +554 -0
  31. package/dist/augmentations/metricsAugmentation.d.ts +202 -0
  32. package/dist/augmentations/metricsAugmentation.js +291 -0
  33. package/dist/augmentations/monitoringAugmentation.d.ts +94 -0
  34. package/dist/augmentations/monitoringAugmentation.js +227 -0
  35. package/dist/augmentations/neuralImport.d.ts +50 -117
  36. package/dist/augmentations/neuralImport.js +255 -629
  37. package/dist/augmentations/requestDeduplicatorAugmentation.d.ts +52 -0
  38. package/dist/augmentations/requestDeduplicatorAugmentation.js +162 -0
  39. package/dist/augmentations/serverSearchAugmentations.d.ts +43 -22
  40. package/dist/augmentations/serverSearchAugmentations.js +125 -72
  41. package/dist/augmentations/storageAugmentation.d.ts +54 -0
  42. package/dist/augmentations/storageAugmentation.js +93 -0
  43. package/dist/augmentations/storageAugmentations.d.ts +96 -0
  44. package/dist/augmentations/storageAugmentations.js +182 -0
  45. package/dist/augmentations/synapseAugmentation.d.ts +156 -0
  46. package/dist/augmentations/synapseAugmentation.js +312 -0
  47. package/dist/augmentations/walAugmentation.d.ts +108 -0
  48. package/dist/augmentations/walAugmentation.js +515 -0
  49. package/dist/brainyData.d.ts +404 -130
  50. package/dist/brainyData.js +1331 -853
  51. package/dist/chat/BrainyChat.d.ts +16 -8
  52. package/dist/chat/BrainyChat.js +60 -32
  53. package/dist/chat/ChatCLI.d.ts +1 -1
  54. package/dist/chat/ChatCLI.js +6 -6
  55. package/dist/cli/catalog.d.ts +3 -3
  56. package/dist/cli/catalog.js +116 -70
  57. package/dist/cli/commands/core.d.ts +61 -0
  58. package/dist/cli/commands/core.js +348 -0
  59. package/dist/cli/commands/neural.d.ts +25 -0
  60. package/dist/cli/commands/neural.js +508 -0
  61. package/dist/cli/commands/utility.d.ts +37 -0
  62. package/dist/cli/commands/utility.js +276 -0
  63. package/dist/cli/index.d.ts +7 -0
  64. package/dist/cli/index.js +167 -0
  65. package/dist/cli/interactive.d.ts +164 -0
  66. package/dist/cli/interactive.js +542 -0
  67. package/dist/cortex/neuralImport.js +5 -5
  68. package/dist/critical/model-guardian.js +11 -4
  69. package/dist/embeddings/lightweight-embedder.d.ts +23 -0
  70. package/dist/embeddings/lightweight-embedder.js +136 -0
  71. package/dist/embeddings/universal-memory-manager.d.ts +38 -0
  72. package/dist/embeddings/universal-memory-manager.js +206 -0
  73. package/dist/embeddings/worker-embedding.d.ts +7 -0
  74. package/dist/embeddings/worker-embedding.js +77 -0
  75. package/dist/embeddings/worker-manager.d.ts +28 -0
  76. package/dist/embeddings/worker-manager.js +162 -0
  77. package/dist/examples/basicUsage.js +7 -7
  78. package/dist/graph/pathfinding.d.ts +78 -0
  79. package/dist/graph/pathfinding.js +393 -0
  80. package/dist/hnsw/hnswIndex.d.ts +13 -0
  81. package/dist/hnsw/hnswIndex.js +35 -0
  82. package/dist/hnsw/hnswIndexOptimized.d.ts +1 -0
  83. package/dist/hnsw/hnswIndexOptimized.js +3 -0
  84. package/dist/index.d.ts +9 -11
  85. package/dist/index.js +21 -11
  86. package/dist/indices/fieldIndex.d.ts +76 -0
  87. package/dist/indices/fieldIndex.js +357 -0
  88. package/dist/mcp/brainyMCPAdapter.js +3 -2
  89. package/dist/mcp/mcpAugmentationToolset.js +11 -17
  90. package/dist/neural/embeddedPatterns.d.ts +41 -0
  91. package/dist/neural/embeddedPatterns.js +4044 -0
  92. package/dist/neural/naturalLanguageProcessor.d.ts +94 -0
  93. package/dist/neural/naturalLanguageProcessor.js +317 -0
  94. package/dist/neural/naturalLanguageProcessorStatic.d.ts +64 -0
  95. package/dist/neural/naturalLanguageProcessorStatic.js +151 -0
  96. package/dist/neural/neuralAPI.d.ts +255 -0
  97. package/dist/neural/neuralAPI.js +612 -0
  98. package/dist/neural/patternLibrary.d.ts +101 -0
  99. package/dist/neural/patternLibrary.js +313 -0
  100. package/dist/neural/patterns.d.ts +27 -0
  101. package/dist/neural/patterns.js +68 -0
  102. package/dist/neural/staticPatternMatcher.d.ts +35 -0
  103. package/dist/neural/staticPatternMatcher.js +153 -0
  104. package/dist/scripts/precomputePatternEmbeddings.d.ts +19 -0
  105. package/dist/scripts/precomputePatternEmbeddings.js +100 -0
  106. package/dist/storage/adapters/fileSystemStorage.d.ts +5 -0
  107. package/dist/storage/adapters/fileSystemStorage.js +20 -0
  108. package/dist/storage/adapters/s3CompatibleStorage.d.ts +5 -0
  109. package/dist/storage/adapters/s3CompatibleStorage.js +16 -0
  110. package/dist/storage/enhancedClearOperations.d.ts +83 -0
  111. package/dist/storage/enhancedClearOperations.js +345 -0
  112. package/dist/storage/storageFactory.js +31 -27
  113. package/dist/triple/TripleIntelligence.d.ts +134 -0
  114. package/dist/triple/TripleIntelligence.js +548 -0
  115. package/dist/types/augmentations.d.ts +45 -344
  116. package/dist/types/augmentations.js +5 -2
  117. package/dist/types/brainyDataInterface.d.ts +20 -10
  118. package/dist/types/graphTypes.d.ts +46 -0
  119. package/dist/types/graphTypes.js +16 -2
  120. package/dist/utils/BoundedRegistry.d.ts +29 -0
  121. package/dist/utils/BoundedRegistry.js +54 -0
  122. package/dist/utils/embedding.js +20 -3
  123. package/dist/utils/hybridModelManager.js +10 -5
  124. package/dist/utils/metadataFilter.d.ts +33 -19
  125. package/dist/utils/metadataFilter.js +58 -23
  126. package/dist/utils/metadataIndex.d.ts +37 -6
  127. package/dist/utils/metadataIndex.js +427 -64
  128. package/dist/utils/requestDeduplicator.d.ts +10 -0
  129. package/dist/utils/requestDeduplicator.js +24 -0
  130. package/dist/utils/unifiedCache.d.ts +103 -0
  131. package/dist/utils/unifiedCache.js +311 -0
  132. package/package.json +40 -125
  133. package/scripts/ensure-models.js +108 -0
  134. package/scripts/prepare-models.js +387 -0
  135. package/OFFLINE_MODELS.md +0 -56
  136. package/dist/intelligence/neuralEngine.d.ts +0 -207
  137. package/dist/intelligence/neuralEngine.js +0 -706
  138. package/dist/utils/modelLoader.d.ts +0 -32
  139. package/dist/utils/modelLoader.js +0 -219
  140. package/dist/utils/modelManager.d.ts +0 -77
  141. package/dist/utils/modelManager.js +0 -219
package/bin/brainy.js CHANGED
@@ -78,7 +78,8 @@ async function generateAIResponse(message, brainy, options) {
78
78
  const model = options.model || 'local'
79
79
 
80
80
  // Get relevant context from user's data
81
- const contextResults = await brainy.search(message, 5, {
81
+ const contextResults = await brainy.search(message, {
82
+ limit: 5,
82
83
  includeContent: true,
83
84
  scoreThreshold: 0.3
84
85
  })
@@ -215,6 +216,17 @@ program
215
216
  .name('brainy')
216
217
  .description('šŸ§ āš›ļø Brainy - Your AI-Powered Second Brain')
217
218
  .version(packageJson.version)
219
+ .option('-i, --interactive', 'Start interactive mode')
220
+ .addHelpText('after', `
221
+ ${colors.dim('Examples:')}
222
+ ${colors.success('brainy add "Meeting notes from today"')}
223
+ ${colors.success('brainy search "project deadline"')}
224
+ ${colors.success('brainy chat')} ${colors.dim('# Interactive AI chat')}
225
+ ${colors.success('brainy -i')} ${colors.dim('# Interactive mode')}
226
+
227
+ ${colors.dim('For more help:')}
228
+ ${colors.info('brainy <command> --help')} ${colors.dim('# Command-specific help')}
229
+ ${colors.info('https://github.com/TimeSoul/brainy')} ${colors.dim('# Documentation')}`)
218
230
 
219
231
  // ========================================
220
232
  // THE 5 COMMANDS (ONE WAY TO DO EVERYTHING)
@@ -340,10 +352,8 @@ program
340
352
  metadata.encrypted = true
341
353
  }
342
354
 
343
- await brainyInstance.add(processedData, metadata, {
344
- process: options.literal ? 'literal' : 'auto'
345
- })
346
- console.log(colors.success('āœ… Added successfully!'))
355
+ const id = await brainyInstance.addNoun(processedData, metadata)
356
+ console.log(colors.success(`āœ… Added successfully! ID: ${id}`))
347
357
  }))
348
358
 
349
359
  // Command 2: CHAT - Talk to your data with AI
@@ -499,31 +509,189 @@ program
499
509
 
500
510
  // Command 3: IMPORT - Bulk/external data
501
511
  program
502
- .command('import <source>')
512
+ .command('import [source]')
503
513
  .description('Import bulk data from files, URLs, or streams')
504
514
  .option('-t, --type <type>', 'Source type (file, url, stream)')
505
515
  .option('-c, --chunk-size <size>', 'Chunk size for large imports', '1000')
506
516
  .action(wrapAction(async (source, options) => {
517
+
518
+ // Interactive mode if no source provided
519
+ if (!source) {
520
+ console.log(colors.primary('šŸ“„ Interactive Import Mode'))
521
+ console.log(colors.dim('Import data from various sources\n'))
522
+
523
+ const rl = createInterface({
524
+ input: process.stdin,
525
+ output: process.stdout
526
+ })
527
+
528
+ // Ask for source type first
529
+ console.log(colors.cyan('Source types:'))
530
+ console.log(colors.info(' 1. Local file'))
531
+ console.log(colors.info(' 2. URL'))
532
+ console.log(colors.info(' 3. Direct input'))
533
+ console.log()
534
+
535
+ const sourceType = await new Promise(resolve => {
536
+ rl.question(colors.cyan('Select source type (1-3): '), (answer) => {
537
+ resolve(answer)
538
+ })
539
+ })
540
+
541
+ if (sourceType === '3') {
542
+ // Direct input mode
543
+ console.log(colors.info('\nEnter your data (type END on a new line when done):\n'))
544
+ let data = ''
545
+ let line = ''
546
+
547
+ while ((line = await new Promise(resolve => {
548
+ rl.question('', resolve)
549
+ })) !== 'END') {
550
+ data += line + '\n'
551
+ }
552
+
553
+ rl.close()
554
+
555
+ // Save to temp file
556
+ const fs = require('fs')
557
+ source = `/tmp/brainy-import-${Date.now()}.json`
558
+ fs.writeFileSync(source, data.trim())
559
+ console.log(colors.info(`\nSaved to temporary file: ${source}`))
560
+ } else {
561
+ // File or URL
562
+ source = await new Promise(resolve => {
563
+ const prompt = sourceType === '2' ? 'Enter URL: ' : 'Enter file path: '
564
+ rl.question(colors.cyan(prompt), (answer) => {
565
+ rl.close()
566
+ resolve(answer)
567
+ })
568
+ })
569
+
570
+ if (!source.trim()) {
571
+ console.log(colors.warning('No source provided'))
572
+ process.exit(1)
573
+ }
574
+ }
575
+ }
507
576
  console.log(colors.info('šŸ“„ Starting neural import...'))
508
577
  console.log(colors.info(`Source: ${source}`))
509
578
 
510
- // Use the unified import system from the cleanup plan
511
- const { NeuralImport } = await import('../dist/cortex/neuralImport.js')
512
- const importer = new NeuralImport()
579
+ // Read and prepare data for import
580
+ const fs = require('fs')
581
+ let data
513
582
 
514
- const result = await importer.import(source, {
515
- chunkSize: parseInt(options.chunkSize)
583
+ try {
584
+ if (source.startsWith('http')) {
585
+ // Handle URL import
586
+ const response = await fetch(source)
587
+ data = await response.text()
588
+ } else {
589
+ // Handle file import
590
+ data = fs.readFileSync(source, 'utf8')
591
+ }
592
+
593
+ // Parse data if JSON
594
+ try {
595
+ data = JSON.parse(data)
596
+ } catch {
597
+ // Keep as string if not JSON
598
+ }
599
+ } catch (error) {
600
+ console.log(colors.error(`Failed to read source: ${error.message}`))
601
+ process.exit(1)
602
+ }
603
+
604
+ const brainyInstance = await getBrainy()
605
+ const result = await brainyInstance.import(data, {
606
+ batchSize: parseInt(options.chunkSize) || 50
516
607
  })
517
608
 
518
- console.log(colors.success(`āœ… Imported ${result.count} items`))
519
- if (result.detectedTypes) {
520
- console.log(colors.info('šŸ” Detected types:'), result.detectedTypes)
609
+ console.log(colors.success(`āœ… Imported ${result.length} items`))
610
+ }))
611
+
612
+ // Command 3: FIND - Intelligent search using Triple Intelligence
613
+ program
614
+ .command('find [query]')
615
+ .description('Intelligent search using natural language and structured queries')
616
+ .option('-l, --limit <number>', 'Results limit', '10')
617
+ .option('-m, --mode <mode>', 'Search mode (auto, semantic, structured)', 'auto')
618
+ .option('--like <term>', 'Vector similarity search term')
619
+ .option('--where <json>', 'Metadata filters as JSON')
620
+ .action(wrapAction(async (query, options) => {
621
+
622
+ if (!query && !options.like) {
623
+ console.log(colors.primary('🧠 Intelligent Find Mode'))
624
+ console.log(colors.dim('Use natural language or structured queries\n'))
625
+
626
+ const rl = createInterface({
627
+ input: process.stdin,
628
+ output: process.stdout
629
+ })
630
+
631
+ query = await new Promise(resolve => {
632
+ rl.question(colors.cyan('What would you like to find? '), (answer) => {
633
+ rl.close()
634
+ resolve(answer)
635
+ })
636
+ })
637
+
638
+ if (!query.trim()) {
639
+ console.log(colors.warning('No query provided'))
640
+ process.exit(1)
641
+ }
642
+ }
643
+
644
+ console.log(colors.info(`🧠 Finding: "${query || options.like}"`))
645
+
646
+ const brainyInstance = await getBrainy()
647
+
648
+ // Build query object for find() API
649
+ let findQuery = query
650
+
651
+ // Handle structured queries
652
+ if (options.like || options.where) {
653
+ findQuery = {}
654
+ if (options.like) findQuery.like = options.like
655
+ if (options.where) {
656
+ try {
657
+ findQuery.where = JSON.parse(options.where)
658
+ } catch {
659
+ console.error(colors.error('Invalid JSON in --where option'))
660
+ process.exit(1)
661
+ }
662
+ }
663
+ }
664
+
665
+ const findOptions = {
666
+ limit: parseInt(options.limit),
667
+ mode: options.mode
668
+ }
669
+
670
+ const results = await brainyInstance.find(findQuery, findOptions)
671
+
672
+ if (results.length === 0) {
673
+ console.log(colors.warning('No results found'))
674
+ return
521
675
  }
676
+
677
+ console.log(colors.success(`āœ… Found ${results.length} intelligent results:`))
678
+ results.forEach((result, i) => {
679
+ console.log(colors.primary(`\n${i + 1}. ${result.content || result.id}`))
680
+ if (result.score) {
681
+ console.log(colors.info(` Relevance: ${(result.score * 100).toFixed(1)}%`))
682
+ }
683
+ if (result.fusionScore) {
684
+ console.log(colors.info(` AI Score: ${(result.fusionScore * 100).toFixed(1)}%`))
685
+ }
686
+ if (result.metadata && Object.keys(result.metadata).length > 0) {
687
+ console.log(colors.dim(` Metadata: ${JSON.stringify(result.metadata)}`))
688
+ }
689
+ })
522
690
  }))
523
691
 
524
- // Command 3: SEARCH - Triple-power search
692
+ // Command 4: SEARCH - Triple-power search
525
693
  program
526
- .command('search <query>')
694
+ .command('search [query]')
527
695
  .description('Search your brain (vector + graph + facets)')
528
696
  .option('-l, --limit <number>', 'Results limit', '10')
529
697
  .option('-f, --filter <json>', 'Metadata filters (see "brainy fields" for available fields)')
@@ -531,6 +699,29 @@ program
531
699
  .option('--fields', 'Show available filter fields and exit')
532
700
  .action(wrapAction(async (query, options) => {
533
701
 
702
+ // Interactive mode if no query provided
703
+ if (!query) {
704
+ console.log(colors.primary('šŸ” Interactive Search Mode'))
705
+ console.log(colors.dim('Search your neural database with natural language\n'))
706
+
707
+ const rl = createInterface({
708
+ input: process.stdin,
709
+ output: process.stdout
710
+ })
711
+
712
+ query = await new Promise(resolve => {
713
+ rl.question(colors.cyan('What would you like to search for? '), (answer) => {
714
+ rl.close()
715
+ resolve(answer)
716
+ })
717
+ })
718
+
719
+ if (!query.trim()) {
720
+ console.log(colors.warning('No search query provided'))
721
+ process.exit(1)
722
+ }
723
+ }
724
+
534
725
  // Handle --fields option
535
726
  if (options.fields) {
536
727
  console.log(colors.primary('šŸ” Available Filter Fields'))
@@ -578,7 +769,7 @@ program
578
769
  }
579
770
 
580
771
  const brainyInstance = await getBrainy()
581
- const results = await brainyInstance.search(query, searchOptions.limit || 10, searchOptions)
772
+ const results = await brainyInstance.search(query, searchOptions)
582
773
 
583
774
  if (results.length === 0) {
584
775
  console.log(colors.warning('No results found'))
@@ -597,9 +788,74 @@ program
597
788
  })
598
789
  }))
599
790
 
600
- // Command 4: UPDATE - Update existing data
791
+ // Command 4: GET - Retrieve specific data by ID
601
792
  program
602
- .command('update <id>')
793
+ .command('get [id]')
794
+ .description('Get a specific item by ID')
795
+ .option('-f, --format <format>', 'Output format (json, table, plain)', 'plain')
796
+ .action(wrapAction(async (id, options) => {
797
+ if (!id) {
798
+ console.log(colors.primary('šŸ” Interactive Get Mode'))
799
+ console.log(colors.dim('Retrieve a specific item by ID\n'))
800
+
801
+ const rl = createInterface({
802
+ input: process.stdin,
803
+ output: process.stdout
804
+ })
805
+
806
+ id = await new Promise(resolve => {
807
+ rl.question(colors.cyan('Enter item ID: '), (answer) => {
808
+ rl.close()
809
+ resolve(answer)
810
+ })
811
+ })
812
+
813
+ if (!id.trim()) {
814
+ console.log(colors.warning('No ID provided'))
815
+ process.exit(1)
816
+ }
817
+ }
818
+
819
+ console.log(colors.info(`šŸ” Getting item: "${id}"`))
820
+
821
+ const brainyInstance = await getBrainy()
822
+ const item = await brainyInstance.getNoun(id)
823
+
824
+ if (!item) {
825
+ console.log(colors.warning('Item not found'))
826
+ return
827
+ }
828
+
829
+ if (options.format === 'json') {
830
+ console.log(JSON.stringify(item, null, 2))
831
+ } else if (options.format === 'table') {
832
+ const table = new Table({
833
+ head: [colors.brain('Property'), colors.brain('Value')],
834
+ style: { head: [], border: [] }
835
+ })
836
+
837
+ table.push(['ID', colors.primary(item.id)])
838
+ table.push(['Content', colors.info(item.content || 'N/A')])
839
+ if (item.metadata) {
840
+ Object.entries(item.metadata).forEach(([key, value]) => {
841
+ table.push([key, colors.dim(JSON.stringify(value))])
842
+ })
843
+ }
844
+ console.log(table.toString())
845
+ } else {
846
+ console.log(colors.primary(`ID: ${item.id}`))
847
+ if (item.content) {
848
+ console.log(colors.info(`Content: ${item.content}`))
849
+ }
850
+ if (item.metadata && Object.keys(item.metadata).length > 0) {
851
+ console.log(colors.info(`Metadata: ${JSON.stringify(item.metadata, null, 2)}`))
852
+ }
853
+ }
854
+ }))
855
+
856
+ // Command 5: UPDATE - Update existing data
857
+ program
858
+ .command('update [id]')
603
859
  .description('Update existing data with new content or metadata')
604
860
  .option('-d, --data <data>', 'New data content')
605
861
  .option('-m, --metadata <json>', 'New metadata as JSON')
@@ -607,6 +863,41 @@ program
607
863
  .option('--no-reindex', 'Skip reindexing (faster but less accurate search)')
608
864
  .option('--cascade', 'Update related verbs')
609
865
  .action(wrapAction(async (id, options) => {
866
+
867
+ // Interactive mode if no ID provided
868
+ if (!id) {
869
+ console.log(colors.primary('šŸ”„ Interactive Update Mode'))
870
+ console.log(colors.dim('Select an item to update\n'))
871
+
872
+ // Show recent items
873
+ const brainyInstance = await getBrainy()
874
+ const recent = await brainyInstance.search('*', { limit: 10, sortBy: 'timestamp' })
875
+
876
+ if (recent.length > 0) {
877
+ console.log(colors.cyan('Recent items:'))
878
+ recent.forEach((item, i) => {
879
+ console.log(colors.info(` ${i + 1}. ${item.id} - ${item.content?.substring(0, 50)}...`))
880
+ })
881
+ console.log()
882
+ }
883
+
884
+ const rl = createInterface({
885
+ input: process.stdin,
886
+ output: process.stdout
887
+ })
888
+
889
+ id = await new Promise(resolve => {
890
+ rl.question(colors.cyan('Enter ID to update: '), (answer) => {
891
+ rl.close()
892
+ resolve(answer)
893
+ })
894
+ })
895
+
896
+ if (!id.trim()) {
897
+ console.log(colors.warning('No ID provided'))
898
+ process.exit(1)
899
+ }
900
+ }
610
901
  console.log(colors.info(`šŸ”„ Updating: "${id}"`))
611
902
 
612
903
  if (!options.data && !options.metadata) {
@@ -626,7 +917,7 @@ program
626
917
 
627
918
  const brainyInstance = await getBrainy()
628
919
 
629
- const success = await brainyInstance.update(id, options.data, metadata, {
920
+ const success = await brainyInstance.updateNoun(id, options.data, metadata, {
630
921
  merge: options.merge !== false, // Default true unless --no-merge
631
922
  reindex: options.reindex !== false, // Default true unless --no-reindex
632
923
  cascade: options.cascade || false
@@ -644,12 +935,66 @@ program
644
935
 
645
936
  // Command 5: DELETE - Remove data (soft delete by default)
646
937
  program
647
- .command('delete <id>')
938
+ .command('delete [id]')
648
939
  .description('Delete data (soft delete by default, preserves indexes)')
649
940
  .option('--hard', 'Permanent deletion (removes from indexes)')
650
941
  .option('--cascade', 'Delete related verbs')
651
942
  .option('--force', 'Force delete even if has relationships')
652
943
  .action(wrapAction(async (id, options) => {
944
+
945
+ // Interactive mode if no ID provided
946
+ if (!id) {
947
+ console.log(colors.warning('šŸ—‘ļø Interactive Delete Mode'))
948
+ console.log(colors.dim('Select an item to delete\n'))
949
+
950
+ // Show recent items for selection
951
+ const brainyInstance = await getBrainy()
952
+ const recent = await brainyInstance.search('*', { limit: 10, sortBy: 'timestamp' })
953
+
954
+ if (recent.length > 0) {
955
+ console.log(colors.cyan('Recent items:'))
956
+ recent.forEach((item, i) => {
957
+ console.log(colors.info(` ${i + 1}. ${item.id} - ${item.content?.substring(0, 50)}...`))
958
+ })
959
+ console.log()
960
+ }
961
+
962
+ const rl = createInterface({
963
+ input: process.stdin,
964
+ output: process.stdout
965
+ })
966
+
967
+ id = await new Promise(resolve => {
968
+ rl.question(colors.warning('Enter ID to delete (or "cancel"): '), (answer) => {
969
+ rl.close()
970
+ resolve(answer)
971
+ })
972
+ })
973
+
974
+ if (!id.trim() || id.toLowerCase() === 'cancel') {
975
+ console.log(colors.info('Delete cancelled'))
976
+ process.exit(0)
977
+ }
978
+
979
+ // Confirm deletion in interactive mode
980
+ const confirmRl = createInterface({
981
+ input: process.stdin,
982
+ output: process.stdout
983
+ })
984
+
985
+ const confirm = await new Promise(resolve => {
986
+ const deleteType = options.hard ? 'permanently delete' : 'soft delete'
987
+ confirmRl.question(colors.warning(`Are you sure you want to ${deleteType} "${id}"? (yes/no): `), (answer) => {
988
+ confirmRl.close()
989
+ resolve(answer.toLowerCase() === 'yes' || answer.toLowerCase() === 'y')
990
+ })
991
+ })
992
+
993
+ if (!confirm) {
994
+ console.log(colors.info('Delete cancelled'))
995
+ process.exit(0)
996
+ }
997
+ }
653
998
  console.log(colors.info(`šŸ—‘ļø Deleting: "${id}"`))
654
999
 
655
1000
  if (options.hard) {
@@ -661,7 +1006,7 @@ program
661
1006
  const brainyInstance = await getBrainy()
662
1007
 
663
1008
  try {
664
- const success = await brainyInstance.delete(id, {
1009
+ const success = await brainyInstance.deleteNoun(id, {
665
1010
  soft: !options.hard, // Soft delete unless --hard specified
666
1011
  cascade: options.cascade || false,
667
1012
  force: options.force || false
@@ -685,12 +1030,57 @@ program
685
1030
 
686
1031
  // Command 6A: ADD-NOUN - Create typed entities (Method #4)
687
1032
  program
688
- .command('add-noun <name>')
1033
+ .command('add-noun [name]')
689
1034
  .description('Add a typed entity to your knowledge graph')
690
1035
  .option('-t, --type <type>', 'Noun type (Person, Organization, Project, Event, Concept, Location, Product)', 'Concept')
691
1036
  .option('-m, --metadata <json>', 'Metadata as JSON')
692
1037
  .option('--encrypt', 'Encrypt this entity')
693
1038
  .action(wrapAction(async (name, options) => {
1039
+
1040
+ // Interactive mode if no name provided
1041
+ if (!name) {
1042
+ console.log(colors.primary('šŸ‘¤ Interactive Entity Creation'))
1043
+ console.log(colors.dim('Create a typed entity in your knowledge graph\n'))
1044
+
1045
+ const rl = createInterface({
1046
+ input: process.stdin,
1047
+ output: process.stdout
1048
+ })
1049
+
1050
+ name = await new Promise(resolve => {
1051
+ rl.question(colors.cyan('Enter entity name: '), (answer) => {
1052
+ resolve(answer)
1053
+ })
1054
+ })
1055
+
1056
+ if (!name.trim()) {
1057
+ rl.close()
1058
+ console.log(colors.warning('No name provided'))
1059
+ process.exit(1)
1060
+ }
1061
+
1062
+ // Interactive type selection if not provided
1063
+ if (!options.type || options.type === 'Concept') {
1064
+ console.log(colors.cyan('\nSelect entity type:'))
1065
+ const types = ['Person', 'Organization', 'Project', 'Event', 'Concept', 'Location', 'Product']
1066
+ types.forEach((t, i) => {
1067
+ console.log(colors.info(` ${i + 1}. ${t}`))
1068
+ })
1069
+ console.log()
1070
+
1071
+ const typeIndex = await new Promise(resolve => {
1072
+ rl.question(colors.cyan('Select type (1-7): '), (answer) => {
1073
+ resolve(parseInt(answer) - 1)
1074
+ })
1075
+ })
1076
+
1077
+ if (typeIndex >= 0 && typeIndex < types.length) {
1078
+ options.type = types[typeIndex]
1079
+ }
1080
+ }
1081
+
1082
+ rl.close()
1083
+ }
694
1084
  const brainy = await getBrainy()
695
1085
 
696
1086
  // Validate noun type
@@ -716,8 +1106,9 @@ program
716
1106
  }
717
1107
 
718
1108
  try {
719
- const { NounType } = await import('../dist/types/graphTypes.js')
720
- const id = await brainy.addNoun(name, NounType[options.type], metadata)
1109
+ // In 2.0 API, addNoun takes (data, metadata) - type goes in metadata
1110
+ metadata.type = options.type
1111
+ const id = await brainy.addNoun(name, metadata)
721
1112
 
722
1113
  console.log(colors.success('āœ… Noun added successfully!'))
723
1114
  console.log(colors.info(`šŸ†” ID: ${id}`))
@@ -735,12 +1126,103 @@ program
735
1126
 
736
1127
  // Command 6B: ADD-VERB - Create relationships (Method #5)
737
1128
  program
738
- .command('add-verb <source> <target>')
1129
+ .command('add-verb [source] [target]')
739
1130
  .description('Create a relationship between two entities')
740
1131
  .option('-t, --type <type>', 'Verb type (WorksFor, Knows, CreatedBy, BelongsTo, Uses, etc.)', 'RelatedTo')
741
1132
  .option('-m, --metadata <json>', 'Relationship metadata as JSON')
742
1133
  .option('--encrypt', 'Encrypt this relationship')
743
1134
  .action(wrapAction(async (source, target, options) => {
1135
+
1136
+ // Interactive mode if parameters missing
1137
+ if (!source || !target) {
1138
+ console.log(colors.primary('šŸ”— Interactive Relationship Builder'))
1139
+ console.log(colors.dim('Connect two entities with a semantic relationship\n'))
1140
+
1141
+ const brainyInstance = await getBrainy()
1142
+ const rl = createInterface({
1143
+ input: process.stdin,
1144
+ output: process.stdout
1145
+ })
1146
+
1147
+ // Get source if not provided
1148
+ if (!source) {
1149
+ // Show recent items
1150
+ const recent = await brainyInstance.search('*', { limit: 10, sortBy: 'timestamp' })
1151
+ if (recent.length > 0) {
1152
+ console.log(colors.cyan('Recent items (source):'))
1153
+ recent.forEach((item, i) => {
1154
+ console.log(colors.info(` ${i + 1}. ${item.id} - ${item.content?.substring(0, 40)}...`))
1155
+ })
1156
+ console.log()
1157
+ }
1158
+
1159
+ source = await new Promise(resolve => {
1160
+ rl.question(colors.cyan('Enter source entity ID: '), (answer) => {
1161
+ resolve(answer)
1162
+ })
1163
+ })
1164
+
1165
+ if (!source.trim()) {
1166
+ rl.close()
1167
+ console.log(colors.warning('No source provided'))
1168
+ process.exit(1)
1169
+ }
1170
+ }
1171
+
1172
+ // Interactive verb type selection
1173
+ if (!options.type || options.type === 'RelatedTo') {
1174
+ console.log(colors.cyan('\nSelect relationship type:'))
1175
+ const verbs = ['WorksFor', 'Knows', 'CreatedBy', 'BelongsTo', 'Uses', 'Manages', 'LocatedIn', 'RelatedTo', 'Custom...']
1176
+ verbs.forEach((v, i) => {
1177
+ console.log(colors.info(` ${i + 1}. ${v}`))
1178
+ })
1179
+ console.log()
1180
+
1181
+ const verbIndex = await new Promise(resolve => {
1182
+ rl.question(colors.cyan('Select type (1-9): '), (answer) => {
1183
+ resolve(parseInt(answer) - 1)
1184
+ })
1185
+ })
1186
+
1187
+ if (verbIndex >= 0 && verbIndex < verbs.length - 1) {
1188
+ options.type = verbs[verbIndex]
1189
+ } else if (verbIndex === verbs.length - 1) {
1190
+ // Custom verb
1191
+ options.type = await new Promise(resolve => {
1192
+ rl.question(colors.cyan('Enter custom relationship: '), (answer) => {
1193
+ resolve(answer)
1194
+ })
1195
+ })
1196
+ }
1197
+ }
1198
+
1199
+ // Get target if not provided
1200
+ if (!target) {
1201
+ // Show recent items again
1202
+ const recent = await brainyInstance.search('*', { limit: 10, sortBy: 'timestamp' })
1203
+ if (recent.length > 0) {
1204
+ console.log(colors.cyan('\nRecent items (target):'))
1205
+ recent.forEach((item, i) => {
1206
+ console.log(colors.info(` ${i + 1}. ${item.id} - ${item.content?.substring(0, 40)}...`))
1207
+ })
1208
+ console.log()
1209
+ }
1210
+
1211
+ target = await new Promise(resolve => {
1212
+ rl.question(colors.cyan('Enter target entity ID: '), (answer) => {
1213
+ resolve(answer)
1214
+ })
1215
+ })
1216
+
1217
+ if (!target.trim()) {
1218
+ rl.close()
1219
+ console.log(colors.warning('No target provided'))
1220
+ process.exit(1)
1221
+ }
1222
+ }
1223
+
1224
+ rl.close()
1225
+ }
744
1226
  const brainy = await getBrainy()
745
1227
 
746
1228
  // Common verb types for validation
@@ -999,39 +1481,121 @@ program
999
1481
  const actions = {
1000
1482
  list: async () => {
1001
1483
  try {
1002
- // Use unified professional catalog
1003
- const REGISTRY_URL = 'https://registry.soulcraft.com/api/registry/augmentations'
1484
+ // Use soulcraft.com registry API
1485
+ const REGISTRY_URL = 'https://api.soulcraft.com/v1/augmentations'
1004
1486
  const response = await fetch(REGISTRY_URL)
1005
1487
 
1006
1488
  if (response && response.ok) {
1007
1489
  console.log(colors.brain('šŸ¢ SOULCRAFT PROFESSIONAL SUITE\n'))
1008
1490
 
1009
1491
  const data = await response.json()
1010
- const { augmentations = [] } = data
1492
+ const augmentations = data.data || [] // NEW: data is in .data array
1011
1493
 
1012
- const professional = augmentations.filter(a => a.tier === 'professional')
1013
- const community = augmentations.filter(a => a.tier === 'community')
1494
+ // Get local augmentations to check what's installed
1495
+ const localAugmentations = brainy.listAugmentations()
1496
+ const localPackageNames = localAugmentations.map(aug => aug.package || aug.name).filter(Boolean)
1497
+
1498
+ // Find installed registry augmentations
1499
+ const installed = augmentations.filter(aug =>
1500
+ aug.package && localPackageNames.includes(aug.package)
1501
+ )
1502
+
1503
+ // Display installed augmentations first
1504
+ if (installed.length > 0) {
1505
+ console.log(colors.success('āœ… INSTALLED AUGMENTATIONS'))
1506
+ installed.forEach(aug => {
1507
+ const pricing = aug.price
1508
+ ? `$${aug.price.monthly}/mo`
1509
+ : (aug.tier === 'free' ? 'FREE' : 'TBD')
1510
+ const pricingColor = aug.tier === 'free' ? colors.success(pricing) : colors.yellow(pricing)
1511
+
1512
+ console.log(` ${aug.name.padEnd(20)} ${pricingColor.padEnd(15)} ${colors.success('āœ… ACTIVE')}`)
1513
+ console.log(` ${colors.dim(aug.description)}`)
1514
+ console.log('')
1515
+ })
1516
+ console.log('') // Extra space before available augmentations
1517
+ }
1518
+
1519
+ // Filter out installed ones from the available lists
1520
+ const availableAugmentations = augmentations.filter(aug =>
1521
+ !installed.find(inst => inst.id === aug.id)
1522
+ )
1014
1523
 
1015
- // Display professional augmentations
1016
- if (professional.length > 0) {
1017
- console.log(colors.primary('šŸš€ PROFESSIONAL AUGMENTATIONS'))
1018
- professional.forEach(aug => {
1019
- const pricing = aug.pricing === 'FREE' ? colors.success(aug.pricing) : colors.yellow(aug.pricing)
1020
- const badges = aug.verified ? colors.blue('āœ“') : ''
1021
- console.log(` ${aug.name.padEnd(20)} ${pricing.padEnd(15)} ${badges}`)
1524
+ // NEW: Use new tier names - "premium" instead of "professional"
1525
+ const premium = availableAugmentations.filter(a => a.tier === 'premium')
1526
+ const free = availableAugmentations.filter(a => a.tier === 'free')
1527
+ const community = availableAugmentations.filter(a => a.tier === 'community')
1528
+ const comingSoon = availableAugmentations.filter(a => a.status === 'coming_soon')
1529
+
1530
+ // Display premium augmentations
1531
+ if (premium.length > 0) {
1532
+ console.log(colors.primary('šŸš€ PREMIUM AUGMENTATIONS'))
1533
+ premium.forEach(aug => {
1534
+ // NEW: price object format
1535
+ const pricing = aug.price
1536
+ ? `$${aug.price.monthly}/mo`
1537
+ : (aug.tier === 'free' ? 'FREE' : 'TBD')
1538
+ const pricingColor = aug.tier === 'free' ? colors.success(pricing) : colors.yellow(pricing)
1539
+
1540
+ // NEW: status instead of verified
1541
+ const status = aug.status === 'available' ? colors.blue('āœ“') :
1542
+ aug.status === 'coming_soon' ? colors.yellow('ā³') :
1543
+ colors.dim('•')
1544
+
1545
+ console.log(` ${aug.name.padEnd(20)} ${pricingColor.padEnd(15)} ${status}`)
1022
1546
  console.log(` ${colors.dim(aug.description)}`)
1023
- if (aug.businessValue) {
1024
- console.log(` ${colors.cyan('→ ' + aug.businessValue)}`)
1547
+
1548
+ if (aug.status === 'coming_soon' && aug.eta) {
1549
+ console.log(` ${colors.cyan('→ Coming ' + aug.eta)}`)
1550
+ }
1551
+
1552
+ if (aug.features && aug.features.length > 0) {
1553
+ console.log(` ${colors.cyan('→ ' + aug.features.join(', '))}`)
1025
1554
  }
1026
1555
  console.log('')
1027
1556
  })
1028
1557
  }
1029
1558
 
1030
- // Display local augmentations
1031
- const localAugmentations = brainy.listAugmentations()
1032
- if (localAugmentations.length > 0) {
1033
- console.log(colors.primary('šŸ“¦ LOCAL AUGMENTATIONS'))
1034
- localAugmentations.forEach(aug => {
1559
+ // Display free augmentations
1560
+ if (free.length > 0) {
1561
+ console.log(colors.primary('šŸ†“ FREE AUGMENTATIONS'))
1562
+ free.forEach(aug => {
1563
+ const status = aug.status === 'available' ? colors.blue('āœ“') :
1564
+ aug.status === 'coming_soon' ? colors.yellow('ā³') :
1565
+ colors.dim('•')
1566
+
1567
+ console.log(` ${aug.name.padEnd(20)} ${colors.success('FREE').padEnd(15)} ${status}`)
1568
+ console.log(` ${colors.dim(aug.description)}`)
1569
+
1570
+ if (aug.status === 'coming_soon' && aug.eta) {
1571
+ console.log(` ${colors.cyan('→ Coming ' + aug.eta)}`)
1572
+ }
1573
+ console.log('')
1574
+ })
1575
+ }
1576
+
1577
+ // Display community augmentations
1578
+ if (community.length > 0) {
1579
+ console.log(colors.primary('šŸ‘„ COMMUNITY AUGMENTATIONS'))
1580
+ community.forEach(aug => {
1581
+ const status = aug.status === 'available' ? colors.blue('āœ“') :
1582
+ aug.status === 'coming_soon' ? colors.yellow('ā³') :
1583
+ colors.dim('•')
1584
+
1585
+ console.log(` ${aug.name.padEnd(20)} ${colors.success('COMMUNITY').padEnd(15)} ${status}`)
1586
+ console.log(` ${colors.dim(aug.description)}`)
1587
+ console.log('')
1588
+ })
1589
+ }
1590
+
1591
+ // Display truly local (non-registry) augmentations
1592
+ const localOnly = localAugmentations.filter(aug =>
1593
+ !aug.package || !augmentations.find(regAug => regAug.package === aug.package)
1594
+ )
1595
+
1596
+ if (localOnly.length > 0) {
1597
+ console.log(colors.primary('šŸ“¦ CUSTOM AUGMENTATIONS'))
1598
+ localOnly.forEach(aug => {
1035
1599
  const status = aug.enabled ? colors.success('āœ… Enabled') : colors.dim('⚪ Disabled')
1036
1600
  console.log(` ${aug.name.padEnd(20)} ${status}`)
1037
1601
  console.log(` ${colors.dim(aug.description || 'Custom augmentation')}`)
@@ -1174,7 +1738,48 @@ program
1174
1738
  }
1175
1739
  }))
1176
1740
 
1177
- // Command 7: EXPORT - Export your data
1741
+ // Command 7: CLEAR - Clear all data
1742
+ program
1743
+ .command('clear')
1744
+ .description('Clear all data from your brain (with safety prompt)')
1745
+ .option('--force', 'Force clear without confirmation')
1746
+ .option('--backup', 'Create backup before clearing')
1747
+ .action(wrapAction(async (options) => {
1748
+ if (!options.force) {
1749
+ console.log(colors.warning('🚨 This will delete ALL data in your brain!'))
1750
+
1751
+ const rl = createInterface({
1752
+ input: process.stdin,
1753
+ output: process.stdout
1754
+ })
1755
+
1756
+ const confirmed = await new Promise(resolve => {
1757
+ rl.question(colors.warning('Type "DELETE EVERYTHING" to confirm: '), (answer) => {
1758
+ rl.close()
1759
+ resolve(answer === 'DELETE EVERYTHING')
1760
+ })
1761
+ })
1762
+
1763
+ if (!confirmed) {
1764
+ console.log(colors.info('Clear operation cancelled'))
1765
+ return
1766
+ }
1767
+ }
1768
+
1769
+ const brainyInstance = await getBrainy()
1770
+
1771
+ if (options.backup) {
1772
+ console.log(colors.info('šŸ’¾ Creating backup...'))
1773
+ // Future: implement backup functionality
1774
+ console.log(colors.success('āœ… Backup created'))
1775
+ }
1776
+
1777
+ console.log(colors.info('šŸ—‘ļø Clearing all data...'))
1778
+ await brainyInstance.clear({ force: true })
1779
+ console.log(colors.success('āœ… All data cleared successfully'))
1780
+ }))
1781
+
1782
+ // Command 8: EXPORT - Export your data
1178
1783
  program
1179
1784
  .command('export')
1180
1785
  .description('Export your brain data in various formats')
@@ -1271,7 +1876,7 @@ program
1271
1876
  console.log(colors.info('\nšŸ“§ Check your email for activation link!'))
1272
1877
  console.log(colors.dim('\nOr visit: https://app.soulcraft.com/activate\n'))
1273
1878
 
1274
- // TODO: Actually call Brain Cloud API when ready
1879
+ // Cloud features planned for future release
1275
1880
  console.log(colors.brain('šŸŽ‰ Your Brain Cloud trial is ready!'))
1276
1881
  console.log(colors.success('\nNext steps:'))
1277
1882
  console.log(colors.dim(' 1. Check your email for API key'))
@@ -1281,42 +1886,16 @@ program
1281
1886
  connect: async () => {
1282
1887
  console.log(colors.info('šŸ”— Connecting to Brain Cloud...'))
1283
1888
  // Dynamic import to avoid loading premium code unnecessarily
1284
- try {
1285
- const { BrainCloudSDK } = await import('@brainy-cloud/sdk')
1286
- const connected = await BrainCloudSDK.connect(options.instance)
1287
- if (connected) {
1288
- console.log(colors.success('āœ… Connected to Brain Cloud'))
1289
- console.log(colors.info(`Instance: ${connected.instanceId}`))
1290
- }
1291
- } catch (error) {
1292
- console.log(colors.warning('āš ļø Brain Cloud SDK not installed'))
1293
- console.log(colors.info('Install with: npm install @brainy-cloud/sdk'))
1294
- console.log(colors.info('Or visit: https://brain-cloud.soulcraft.com'))
1295
- }
1889
+ console.log(colors.info('šŸ”— Cloud features coming soon...'))
1890
+ console.log(colors.info('Brainy works offline by default'))
1296
1891
  },
1297
1892
  status: async () => {
1298
- try {
1299
- const { BrainCloudSDK } = await import('@brainy-cloud/sdk')
1300
- const status = await BrainCloudSDK.getStatus()
1301
- console.log(colors.success('ā˜ļø Cloud Status: Connected'))
1302
- console.log(colors.info(`Instance: ${status.instanceId}`))
1303
- console.log(colors.info(`Augmentations: ${status.augmentationCount} available`))
1304
- } catch {
1305
- console.log(colors.warning('ā˜ļø Cloud Status: Not connected'))
1306
- console.log(colors.info('Use "brainy cloud connect" to connect'))
1307
- }
1893
+ console.log(colors.info('ā˜ļø Cloud Status: Available in future release'))
1894
+ console.log(colors.info('Current version works offline'))
1308
1895
  },
1309
1896
  augmentations: async () => {
1310
- try {
1311
- const { BrainCloudSDK } = await import('@brainy-cloud/sdk')
1312
- const augs = await BrainCloudSDK.listAugmentations()
1313
- console.log(colors.primary('🧩 Available Premium Augmentations:'))
1314
- augs.forEach(aug => {
1315
- console.log(colors.success(` āœ… ${aug.name} - ${aug.description}`))
1316
- })
1317
- } catch {
1318
- console.log(colors.warning('Connect to Brain Cloud first: brainy cloud connect'))
1319
- }
1897
+ console.log(colors.info('🧩 Cloud augmentations coming in future release'))
1898
+ console.log(colors.info('Local augmentations available now'))
1320
1899
  }
1321
1900
  }
1322
1901
 
@@ -1464,9 +2043,21 @@ program
1464
2043
  // FALLBACK - Show interactive help if no command
1465
2044
  // ========================================
1466
2045
 
1467
- // If no arguments provided, show interactive help
1468
- if (process.argv.length === 2) {
2046
+ // Handle --interactive flag
2047
+ if (process.argv.includes('-i') || process.argv.includes('--interactive')) {
2048
+ // Start full interactive mode
2049
+ console.log(colors.primary('🧠 Starting Interactive Mode...'))
2050
+ import('./brainy-interactive.js').then(module => {
2051
+ module.startInteractiveMode()
2052
+ }).catch(error => {
2053
+ console.error(colors.error('Failed to start interactive mode:'), error.message)
2054
+ // Fallback to simple interactive prompt
2055
+ program.parse(['node', 'brainy', 'help'])
2056
+ })
2057
+ } else if (process.argv.length === 2) {
2058
+ // No arguments - show interactive help
1469
2059
  program.parse(['node', 'brainy', 'help'])
1470
2060
  } else {
2061
+ // Parse normally
1471
2062
  program.parse(process.argv)
1472
2063
  }