ruvector 0.1.23 → 0.1.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  {
2
- "startTime": 1764217582157,
3
- "sessionId": "session-1764217582157",
4
- "lastActivity": 1764217582157,
2
+ "startTime": 1764542370768,
3
+ "sessionId": "session-1764542370768",
4
+ "lastActivity": 1764542370768,
5
5
  "sessionDuration": 0,
6
6
  "totalTasks": 1,
7
7
  "successfulTasks": 1,
@@ -1,10 +1,10 @@
1
1
  [
2
2
  {
3
- "id": "cmd-hooks-1764217582465",
3
+ "id": "cmd-hooks-1764542370895",
4
4
  "type": "hooks",
5
5
  "success": true,
6
- "duration": 37.93139400000007,
7
- "timestamp": 1764217582503,
6
+ "duration": 15.263496999999973,
7
+ "timestamp": 1764542370910,
8
8
  "metadata": {}
9
9
  }
10
10
  ]
package/bin/cli.js CHANGED
@@ -47,6 +47,46 @@ try {
47
47
  // GNN not available - commands will show helpful message
48
48
  }
49
49
 
50
+ // Import Attention (optional - graceful fallback if not available)
51
+ let DotProductAttention, MultiHeadAttention, HyperbolicAttention, FlashAttention, LinearAttention, MoEAttention;
52
+ let GraphRoPeAttention, EdgeFeaturedAttention, DualSpaceAttention, LocalGlobalAttention;
53
+ let benchmarkAttention, computeAttentionAsync, batchAttentionCompute, parallelAttentionCompute;
54
+ let expMap, logMap, mobiusAddition, poincareDistance, projectToPoincareBall;
55
+ let attentionInfo, attentionVersion;
56
+ let attentionAvailable = false;
57
+ try {
58
+ const attention = require('@ruvector/attention');
59
+ // Core mechanisms
60
+ DotProductAttention = attention.DotProductAttention;
61
+ MultiHeadAttention = attention.MultiHeadAttention;
62
+ HyperbolicAttention = attention.HyperbolicAttention;
63
+ FlashAttention = attention.FlashAttention;
64
+ LinearAttention = attention.LinearAttention;
65
+ MoEAttention = attention.MoEAttention;
66
+ // Graph attention
67
+ GraphRoPeAttention = attention.GraphRoPeAttention;
68
+ EdgeFeaturedAttention = attention.EdgeFeaturedAttention;
69
+ DualSpaceAttention = attention.DualSpaceAttention;
70
+ LocalGlobalAttention = attention.LocalGlobalAttention;
71
+ // Utilities
72
+ benchmarkAttention = attention.benchmarkAttention;
73
+ computeAttentionAsync = attention.computeAttentionAsync;
74
+ batchAttentionCompute = attention.batchAttentionCompute;
75
+ parallelAttentionCompute = attention.parallelAttentionCompute;
76
+ // Hyperbolic math
77
+ expMap = attention.expMap;
78
+ logMap = attention.logMap;
79
+ mobiusAddition = attention.mobiusAddition;
80
+ poincareDistance = attention.poincareDistance;
81
+ projectToPoincareBall = attention.projectToPoincareBall;
82
+ // Meta
83
+ attentionInfo = attention.info;
84
+ attentionVersion = attention.version;
85
+ attentionAvailable = true;
86
+ } catch (e) {
87
+ // Attention not available - commands will show helpful message
88
+ }
89
+
50
90
  const program = new Command();
51
91
 
52
92
  // Get package version from package.json
@@ -855,4 +895,1190 @@ gnnCmd
855
895
  console.log(chalk.gray(` binary (freq <= 0.01) - ~32x compression, archive`));
856
896
  });
857
897
 
898
+ // =============================================================================
899
+ // Attention Commands
900
+ // =============================================================================
901
+
902
+ // Helper to require attention module
903
+ function requireAttention() {
904
+ if (!attentionAvailable) {
905
+ console.error(chalk.red('Error: @ruvector/attention is not installed'));
906
+ console.error(chalk.yellow('Install it with: npm install @ruvector/attention'));
907
+ process.exit(1);
908
+ }
909
+ }
910
+
911
+ // Attention parent command
912
+ const attentionCmd = program
913
+ .command('attention')
914
+ .description('High-performance attention mechanism operations');
915
+
916
+ // Attention compute command - run attention on input vectors
917
+ attentionCmd
918
+ .command('compute')
919
+ .description('Compute attention over input vectors')
920
+ .requiredOption('-q, --query <json>', 'Query vector as JSON array')
921
+ .requiredOption('-k, --keys <file>', 'Keys file (JSON array of vectors)')
922
+ .option('-v, --values <file>', 'Values file (JSON array of vectors, defaults to keys)')
923
+ .option('-t, --type <type>', 'Attention type (dot|multi-head|flash|hyperbolic|linear)', 'dot')
924
+ .option('-h, --heads <number>', 'Number of attention heads (for multi-head)', '4')
925
+ .option('-d, --head-dim <number>', 'Head dimension (for multi-head)', '64')
926
+ .option('--curvature <number>', 'Curvature for hyperbolic attention', '1.0')
927
+ .option('-o, --output <file>', 'Output file for results')
928
+ .action((options) => {
929
+ requireAttention();
930
+ const spinner = ora('Loading keys...').start();
931
+
932
+ try {
933
+ const query = JSON.parse(options.query);
934
+ const keysData = JSON.parse(fs.readFileSync(options.keys, 'utf8'));
935
+ const keys = keysData.map(k => k.vector || k);
936
+
937
+ let values = keys;
938
+ if (options.values) {
939
+ const valuesData = JSON.parse(fs.readFileSync(options.values, 'utf8'));
940
+ values = valuesData.map(v => v.vector || v);
941
+ }
942
+
943
+ spinner.text = `Computing ${options.type} attention...`;
944
+
945
+ let result;
946
+ let attentionWeights;
947
+
948
+ switch (options.type) {
949
+ case 'dot': {
950
+ const attn = new DotProductAttention();
951
+ const queryMat = [query];
952
+ const output = attn.forward(queryMat, keys, values);
953
+ result = output[0];
954
+ attentionWeights = attn.getLastWeights ? attn.getLastWeights()[0] : null;
955
+ break;
956
+ }
957
+ case 'multi-head': {
958
+ const numHeads = parseInt(options.heads);
959
+ const headDim = parseInt(options.headDim);
960
+ const attn = new MultiHeadAttention(query.length, numHeads, headDim);
961
+ const queryMat = [query];
962
+ const output = attn.forward(queryMat, keys, values);
963
+ result = output[0];
964
+ break;
965
+ }
966
+ case 'flash': {
967
+ const attn = new FlashAttention(query.length);
968
+ const queryMat = [query];
969
+ const output = attn.forward(queryMat, keys, values);
970
+ result = output[0];
971
+ break;
972
+ }
973
+ case 'hyperbolic': {
974
+ const curvature = parseFloat(options.curvature);
975
+ const attn = new HyperbolicAttention(query.length, curvature);
976
+ const queryMat = [query];
977
+ const output = attn.forward(queryMat, keys, values);
978
+ result = output[0];
979
+ break;
980
+ }
981
+ case 'linear': {
982
+ const attn = new LinearAttention(query.length);
983
+ const queryMat = [query];
984
+ const output = attn.forward(queryMat, keys, values);
985
+ result = output[0];
986
+ break;
987
+ }
988
+ default:
989
+ throw new Error(`Unknown attention type: ${options.type}`);
990
+ }
991
+
992
+ spinner.succeed(chalk.green(`Attention computed (${options.type})`));
993
+
994
+ console.log(chalk.cyan('\nAttention Results:'));
995
+ console.log(chalk.white(` Type: ${chalk.yellow(options.type)}`));
996
+ console.log(chalk.white(` Query dim: ${chalk.yellow(query.length)}`));
997
+ console.log(chalk.white(` Num keys: ${chalk.yellow(keys.length)}`));
998
+ console.log(chalk.white(` Output dim: ${chalk.yellow(result.length)}`));
999
+ console.log(chalk.white(` Output: ${chalk.gray(`[${result.slice(0, 4).map(v => v.toFixed(4)).join(', ')}...]`)}`));
1000
+
1001
+ if (attentionWeights) {
1002
+ console.log(chalk.cyan('\nAttention Weights:'));
1003
+ attentionWeights.slice(0, 5).forEach((w, i) => {
1004
+ console.log(chalk.gray(` Key ${i}: ${w.toFixed(4)}`));
1005
+ });
1006
+ if (attentionWeights.length > 5) {
1007
+ console.log(chalk.gray(` ... and ${attentionWeights.length - 5} more`));
1008
+ }
1009
+ }
1010
+
1011
+ if (options.output) {
1012
+ const outputData = { result, attentionWeights };
1013
+ fs.writeFileSync(options.output, JSON.stringify(outputData, null, 2));
1014
+ console.log(chalk.green(`\nResults saved to: ${options.output}`));
1015
+ }
1016
+ } catch (error) {
1017
+ spinner.fail(chalk.red('Failed to compute attention'));
1018
+ console.error(chalk.red(error.message));
1019
+ process.exit(1);
1020
+ }
1021
+ });
1022
+
1023
+ // Attention benchmark command
1024
+ attentionCmd
1025
+ .command('benchmark')
1026
+ .description('Benchmark attention mechanisms')
1027
+ .option('-d, --dimension <number>', 'Vector dimension', '256')
1028
+ .option('-n, --num-vectors <number>', 'Number of vectors', '100')
1029
+ .option('-i, --iterations <number>', 'Benchmark iterations', '100')
1030
+ .option('-t, --types <list>', 'Attention types to benchmark (comma-separated)', 'dot,flash,linear')
1031
+ .action((options) => {
1032
+ requireAttention();
1033
+ const spinner = ora('Setting up benchmark...').start();
1034
+
1035
+ try {
1036
+ const dim = parseInt(options.dimension);
1037
+ const numVectors = parseInt(options.numVectors);
1038
+ const iterations = parseInt(options.iterations);
1039
+ const types = options.types.split(',').map(t => t.trim());
1040
+
1041
+ // Generate random test data
1042
+ spinner.text = 'Generating test data...';
1043
+ const query = Array.from({ length: dim }, () => Math.random());
1044
+ const keys = Array.from({ length: numVectors }, () =>
1045
+ Array.from({ length: dim }, () => Math.random())
1046
+ );
1047
+
1048
+ console.log(chalk.cyan('\n═══════════════════════════════════════════════════════════════'));
1049
+ console.log(chalk.cyan(' Attention Mechanism Benchmark'));
1050
+ console.log(chalk.cyan('═══════════════════════════════════════════════════════════════\n'));
1051
+
1052
+ console.log(chalk.white(` Dimension: ${chalk.yellow(dim)}`));
1053
+ console.log(chalk.white(` Vectors: ${chalk.yellow(numVectors)}`));
1054
+ console.log(chalk.white(` Iterations: ${chalk.yellow(iterations)}`));
1055
+ console.log('');
1056
+
1057
+ const results = [];
1058
+
1059
+ for (const type of types) {
1060
+ spinner.text = `Benchmarking ${type} attention...`;
1061
+ spinner.start();
1062
+
1063
+ let attn;
1064
+ try {
1065
+ switch (type) {
1066
+ case 'dot':
1067
+ attn = new DotProductAttention();
1068
+ break;
1069
+ case 'flash':
1070
+ attn = new FlashAttention(dim);
1071
+ break;
1072
+ case 'linear':
1073
+ attn = new LinearAttention(dim);
1074
+ break;
1075
+ case 'hyperbolic':
1076
+ attn = new HyperbolicAttention(dim, 1.0);
1077
+ break;
1078
+ case 'multi-head':
1079
+ attn = new MultiHeadAttention(dim, 4, 64);
1080
+ break;
1081
+ default:
1082
+ console.log(chalk.yellow(` Skipping unknown type: ${type}`));
1083
+ continue;
1084
+ }
1085
+ } catch (e) {
1086
+ console.log(chalk.yellow(` ${type}: not available`));
1087
+ continue;
1088
+ }
1089
+
1090
+ // Warm up
1091
+ const queryMat = [query];
1092
+ for (let i = 0; i < 5; i++) {
1093
+ attn.forward(queryMat, keys, keys);
1094
+ }
1095
+
1096
+ // Benchmark
1097
+ const start = process.hrtime.bigint();
1098
+ for (let i = 0; i < iterations; i++) {
1099
+ attn.forward(queryMat, keys, keys);
1100
+ }
1101
+ const end = process.hrtime.bigint();
1102
+ const totalMs = Number(end - start) / 1_000_000;
1103
+ const avgMs = totalMs / iterations;
1104
+ const opsPerSec = 1000 / avgMs;
1105
+
1106
+ results.push({ type, avgMs, opsPerSec });
1107
+ spinner.succeed(chalk.green(`${type}: ${avgMs.toFixed(3)} ms/op (${opsPerSec.toFixed(1)} ops/sec)`));
1108
+ }
1109
+
1110
+ // Summary
1111
+ if (results.length > 0) {
1112
+ console.log(chalk.cyan('\n═══════════════════════════════════════════════════════════════'));
1113
+ console.log(chalk.cyan(' Summary'));
1114
+ console.log(chalk.cyan('═══════════════════════════════════════════════════════════════\n'));
1115
+
1116
+ const fastest = results.reduce((a, b) => a.avgMs < b.avgMs ? a : b);
1117
+ console.log(chalk.green(` Fastest: ${fastest.type} (${fastest.avgMs.toFixed(3)} ms/op)\n`));
1118
+
1119
+ console.log(chalk.white(' Relative Performance:'));
1120
+ for (const r of results) {
1121
+ const relPerf = (fastest.avgMs / r.avgMs * 100).toFixed(1);
1122
+ const bar = '█'.repeat(Math.round(relPerf / 5));
1123
+ console.log(chalk.white(` ${r.type.padEnd(12)} ${chalk.cyan(bar)} ${relPerf}%`));
1124
+ }
1125
+ }
1126
+ } catch (error) {
1127
+ spinner.fail(chalk.red('Benchmark failed'));
1128
+ console.error(chalk.red(error.message));
1129
+ process.exit(1);
1130
+ }
1131
+ });
1132
+
1133
+ // Hyperbolic math command
1134
+ attentionCmd
1135
+ .command('hyperbolic')
1136
+ .description('Hyperbolic geometry operations')
1137
+ .requiredOption('-a, --action <type>', 'Action: exp-map|log-map|distance|project|mobius-add')
1138
+ .requiredOption('-v, --vector <json>', 'Input vector(s) as JSON')
1139
+ .option('-b, --vector-b <json>', 'Second vector for binary operations')
1140
+ .option('-c, --curvature <number>', 'Poincaré ball curvature', '1.0')
1141
+ .option('-o, --origin <json>', 'Origin point for exp/log maps')
1142
+ .action((options) => {
1143
+ requireAttention();
1144
+
1145
+ try {
1146
+ const vecArray = JSON.parse(options.vector);
1147
+ const vec = new Float32Array(vecArray);
1148
+ const curvature = parseFloat(options.curvature);
1149
+
1150
+ let result;
1151
+ let description;
1152
+
1153
+ switch (options.action) {
1154
+ case 'exp-map': {
1155
+ const originArray = options.origin ? JSON.parse(options.origin) : Array(vec.length).fill(0);
1156
+ const origin = new Float32Array(originArray);
1157
+ result = expMap(origin, vec, curvature);
1158
+ description = 'Exponential map (tangent → Poincaré ball)';
1159
+ break;
1160
+ }
1161
+ case 'log-map': {
1162
+ const originArray = options.origin ? JSON.parse(options.origin) : Array(vec.length).fill(0);
1163
+ const origin = new Float32Array(originArray);
1164
+ result = logMap(origin, vec, curvature);
1165
+ description = 'Logarithmic map (Poincaré ball → tangent)';
1166
+ break;
1167
+ }
1168
+ case 'distance': {
1169
+ if (!options.vectorB) {
1170
+ throw new Error('--vector-b required for distance calculation');
1171
+ }
1172
+ const vecBArray = JSON.parse(options.vectorB);
1173
+ const vecB = new Float32Array(vecBArray);
1174
+ result = poincareDistance(vec, vecB, curvature);
1175
+ description = 'Poincaré distance';
1176
+ break;
1177
+ }
1178
+ case 'project': {
1179
+ result = projectToPoincareBall(vec, curvature);
1180
+ description = 'Project to Poincaré ball';
1181
+ break;
1182
+ }
1183
+ case 'mobius-add': {
1184
+ if (!options.vectorB) {
1185
+ throw new Error('--vector-b required for Möbius addition');
1186
+ }
1187
+ const vecBArray = JSON.parse(options.vectorB);
1188
+ const vecB = new Float32Array(vecBArray);
1189
+ result = mobiusAddition(vec, vecB, curvature);
1190
+ description = 'Möbius addition';
1191
+ break;
1192
+ }
1193
+ default:
1194
+ throw new Error(`Unknown action: ${options.action}`);
1195
+ }
1196
+
1197
+ console.log(chalk.cyan('\nHyperbolic Operation:'));
1198
+ console.log(chalk.white(` Action: ${chalk.yellow(description)}`));
1199
+ console.log(chalk.white(` Curvature: ${chalk.yellow(curvature)}`));
1200
+
1201
+ if (typeof result === 'number') {
1202
+ console.log(chalk.white(` Result: ${chalk.green(result.toFixed(6))}`));
1203
+ } else {
1204
+ const resultArray = Array.from(result);
1205
+ console.log(chalk.white(` Input dim: ${chalk.yellow(vec.length)}`));
1206
+ console.log(chalk.white(` Output dim: ${chalk.yellow(resultArray.length)}`));
1207
+ console.log(chalk.white(` Result: ${chalk.gray(`[${resultArray.slice(0, 5).map(v => v.toFixed(4)).join(', ')}...]`)}`));
1208
+
1209
+ // Compute norm to verify it's in the ball
1210
+ const norm = Math.sqrt(resultArray.reduce((sum, x) => sum + x * x, 0));
1211
+ console.log(chalk.white(` Norm: ${chalk.yellow(norm.toFixed(6))} ${norm < 1 ? chalk.green('(inside ball)') : chalk.red('(outside ball)')}`));
1212
+ }
1213
+ } catch (error) {
1214
+ console.error(chalk.red('Hyperbolic operation failed:'), error.message);
1215
+ process.exit(1);
1216
+ }
1217
+ });
1218
+
1219
+ // Attention info command
1220
+ attentionCmd
1221
+ .command('info')
1222
+ .description('Show attention module information')
1223
+ .action(() => {
1224
+ if (!attentionAvailable) {
1225
+ console.log(chalk.yellow('\nAttention Module: Not installed'));
1226
+ console.log(chalk.white('Install with: npm install @ruvector/attention'));
1227
+ return;
1228
+ }
1229
+
1230
+ console.log(chalk.cyan('\nAttention Module Information'));
1231
+ console.log(chalk.white(` Status: ${chalk.green('Available')}`));
1232
+ console.log(chalk.white(` Version: ${chalk.yellow(attentionVersion ? attentionVersion() : 'unknown')}`));
1233
+ console.log(chalk.white(` Platform: ${chalk.yellow(process.platform)}`));
1234
+ console.log(chalk.white(` Architecture: ${chalk.yellow(process.arch)}`));
1235
+
1236
+ console.log(chalk.cyan('\nCore Attention Mechanisms:'));
1237
+ console.log(chalk.white(` • DotProductAttention - Scaled dot-product attention`));
1238
+ console.log(chalk.white(` • MultiHeadAttention - Multi-head self-attention`));
1239
+ console.log(chalk.white(` • FlashAttention - Memory-efficient IO-aware attention`));
1240
+ console.log(chalk.white(` • HyperbolicAttention - Poincaré ball attention`));
1241
+ console.log(chalk.white(` • LinearAttention - O(n) linear complexity attention`));
1242
+ console.log(chalk.white(` • MoEAttention - Mixture of Experts attention`));
1243
+
1244
+ console.log(chalk.cyan('\nGraph Attention:'));
1245
+ console.log(chalk.white(` • GraphRoPeAttention - Rotary position embeddings for graphs`));
1246
+ console.log(chalk.white(` • EdgeFeaturedAttention - Edge feature-enhanced attention`));
1247
+ console.log(chalk.white(` • DualSpaceAttention - Euclidean + hyperbolic dual space`));
1248
+ console.log(chalk.white(` • LocalGlobalAttention - Local-global graph attention`));
1249
+
1250
+ console.log(chalk.cyan('\nHyperbolic Math:'));
1251
+ console.log(chalk.white(` • expMap, logMap - Exponential/logarithmic maps`));
1252
+ console.log(chalk.white(` • mobiusAddition - Möbius addition in Poincaré ball`));
1253
+ console.log(chalk.white(` • poincareDistance - Hyperbolic distance metric`));
1254
+ console.log(chalk.white(` • projectToPoincareBall - Project vectors to ball`));
1255
+
1256
+ console.log(chalk.cyan('\nTraining Utilities:'));
1257
+ console.log(chalk.white(` • AdamOptimizer, AdamWOptimizer, SgdOptimizer`));
1258
+ console.log(chalk.white(` • InfoNceLoss, LocalContrastiveLoss`));
1259
+ console.log(chalk.white(` • CurriculumScheduler, TemperatureAnnealing`));
1260
+ console.log(chalk.white(` • HardNegativeMiner, InBatchMiner`));
1261
+ });
1262
+
1263
+ // Attention list command - list available mechanisms
1264
+ attentionCmd
1265
+ .command('list')
1266
+ .description('List all available attention mechanisms')
1267
+ .option('-v, --verbose', 'Show detailed information')
1268
+ .action((options) => {
1269
+ console.log(chalk.cyan('\n═══════════════════════════════════════════════════════════════'));
1270
+ console.log(chalk.cyan(' Available Attention Mechanisms'));
1271
+ console.log(chalk.cyan('═══════════════════════════════════════════════════════════════\n'));
1272
+
1273
+ const mechanisms = [
1274
+ { name: 'DotProductAttention', type: 'core', complexity: 'O(n²)', available: !!DotProductAttention },
1275
+ { name: 'MultiHeadAttention', type: 'core', complexity: 'O(n²)', available: !!MultiHeadAttention },
1276
+ { name: 'FlashAttention', type: 'core', complexity: 'O(n²) IO-optimized', available: !!FlashAttention },
1277
+ { name: 'HyperbolicAttention', type: 'core', complexity: 'O(n²)', available: !!HyperbolicAttention },
1278
+ { name: 'LinearAttention', type: 'core', complexity: 'O(n)', available: !!LinearAttention },
1279
+ { name: 'MoEAttention', type: 'core', complexity: 'O(n*k)', available: !!MoEAttention },
1280
+ { name: 'GraphRoPeAttention', type: 'graph', complexity: 'O(n²)', available: !!GraphRoPeAttention },
1281
+ { name: 'EdgeFeaturedAttention', type: 'graph', complexity: 'O(n²)', available: !!EdgeFeaturedAttention },
1282
+ { name: 'DualSpaceAttention', type: 'graph', complexity: 'O(n²)', available: !!DualSpaceAttention },
1283
+ { name: 'LocalGlobalAttention', type: 'graph', complexity: 'O(n*k)', available: !!LocalGlobalAttention },
1284
+ ];
1285
+
1286
+ console.log(chalk.white(' Core Attention:'));
1287
+ mechanisms.filter(m => m.type === 'core').forEach(m => {
1288
+ const status = m.available ? chalk.green('✓') : chalk.red('✗');
1289
+ console.log(chalk.white(` ${status} ${m.name.padEnd(22)} ${chalk.gray(m.complexity)}`));
1290
+ });
1291
+
1292
+ console.log(chalk.white('\n Graph Attention:'));
1293
+ mechanisms.filter(m => m.type === 'graph').forEach(m => {
1294
+ const status = m.available ? chalk.green('✓') : chalk.red('✗');
1295
+ console.log(chalk.white(` ${status} ${m.name.padEnd(22)} ${chalk.gray(m.complexity)}`));
1296
+ });
1297
+
1298
+ if (!attentionAvailable) {
1299
+ console.log(chalk.yellow('\n Note: @ruvector/attention not installed'));
1300
+ console.log(chalk.white(' Install with: npm install @ruvector/attention'));
1301
+ }
1302
+
1303
+ if (options.verbose) {
1304
+ console.log(chalk.cyan('\n Usage Examples:'));
1305
+ console.log(chalk.gray(' # Compute dot-product attention'));
1306
+ console.log(chalk.white(' npx ruvector attention compute -q "[1,2,3]" -k keys.json -t dot'));
1307
+ console.log(chalk.gray('\n # Benchmark attention mechanisms'));
1308
+ console.log(chalk.white(' npx ruvector attention benchmark -d 256 -n 100'));
1309
+ console.log(chalk.gray('\n # Hyperbolic distance'));
1310
+ console.log(chalk.white(' npx ruvector attention hyperbolic -a distance -v "[0.1,0.2]" -b "[0.3,0.4]"'));
1311
+ }
1312
+ });
1313
+
1314
+ // =============================================================================
1315
+ // Doctor Command - Check system health and dependencies
1316
+ // =============================================================================
1317
+
1318
+ program
1319
+ .command('doctor')
1320
+ .description('Check system health and dependencies')
1321
+ .option('-v, --verbose', 'Show detailed information')
1322
+ .action(async (options) => {
1323
+ const { execSync } = require('child_process');
1324
+
1325
+ console.log(chalk.cyan('\n═══════════════════════════════════════════════════════════════'));
1326
+ console.log(chalk.cyan(' RuVector Doctor'));
1327
+ console.log(chalk.cyan('═══════════════════════════════════════════════════════════════\n'));
1328
+
1329
+ let issues = 0;
1330
+ let warnings = 0;
1331
+
1332
+ // Helper functions
1333
+ const check = (name, condition, fix) => {
1334
+ if (condition) {
1335
+ console.log(chalk.green(` ✓ ${name}`));
1336
+ return true;
1337
+ } else {
1338
+ console.log(chalk.red(` ✗ ${name}`));
1339
+ if (fix) console.log(chalk.gray(` Fix: ${fix}`));
1340
+ issues++;
1341
+ return false;
1342
+ }
1343
+ };
1344
+
1345
+ const warn = (name, condition, suggestion) => {
1346
+ if (condition) {
1347
+ console.log(chalk.green(` ✓ ${name}`));
1348
+ return true;
1349
+ } else {
1350
+ console.log(chalk.yellow(` ! ${name}`));
1351
+ if (suggestion) console.log(chalk.gray(` Suggestion: ${suggestion}`));
1352
+ warnings++;
1353
+ return false;
1354
+ }
1355
+ };
1356
+
1357
+ const getVersion = (cmd) => {
1358
+ try {
1359
+ return execSync(cmd, { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();
1360
+ } catch (e) {
1361
+ return null;
1362
+ }
1363
+ };
1364
+
1365
+ // System Information
1366
+ console.log(chalk.cyan('System Information:'));
1367
+ console.log(chalk.white(` Platform: ${chalk.yellow(process.platform)}`));
1368
+ console.log(chalk.white(` Architecture: ${chalk.yellow(process.arch)}`));
1369
+ console.log(chalk.white(` Node.js: ${chalk.yellow(process.version)}`));
1370
+ console.log('');
1371
+
1372
+ // Node.js Checks
1373
+ console.log(chalk.cyan('Node.js Environment:'));
1374
+ const nodeVersion = parseInt(process.version.slice(1).split('.')[0]);
1375
+ check('Node.js >= 14', nodeVersion >= 14, 'Upgrade Node.js: https://nodejs.org');
1376
+
1377
+ const npmVersion = getVersion('npm --version');
1378
+ if (npmVersion) {
1379
+ console.log(chalk.green(` ✓ npm ${npmVersion}`));
1380
+ } else {
1381
+ check('npm installed', false, 'Install npm or reinstall Node.js');
1382
+ }
1383
+ console.log('');
1384
+
1385
+ // RuVector Packages
1386
+ console.log(chalk.cyan('RuVector Packages:'));
1387
+
1388
+ // Check @ruvector/core
1389
+ let coreAvailable = false;
1390
+ try {
1391
+ require.resolve('@ruvector/core');
1392
+ coreAvailable = true;
1393
+ console.log(chalk.green(` ✓ @ruvector/core installed`));
1394
+ } catch (e) {
1395
+ console.log(chalk.yellow(` ! @ruvector/core not found (using WASM fallback)`));
1396
+ warnings++;
1397
+ }
1398
+
1399
+ // Check if native binding works
1400
+ if (coreAvailable && loadRuvector()) {
1401
+ const info = getVersion();
1402
+ console.log(chalk.green(` ✓ Native binding working (${info.implementation})`));
1403
+ } else if (coreAvailable) {
1404
+ console.log(chalk.yellow(` ! Native binding failed to load`));
1405
+ warnings++;
1406
+ }
1407
+
1408
+ // Check @ruvector/gnn
1409
+ if (gnnAvailable) {
1410
+ console.log(chalk.green(` ✓ @ruvector/gnn installed`));
1411
+ } else {
1412
+ console.log(chalk.gray(` ○ @ruvector/gnn not installed (optional)`));
1413
+ }
1414
+
1415
+ // Check @ruvector/attention
1416
+ if (attentionAvailable) {
1417
+ console.log(chalk.green(` ✓ @ruvector/attention installed`));
1418
+ } else {
1419
+ console.log(chalk.gray(` ○ @ruvector/attention not installed (optional)`));
1420
+ }
1421
+
1422
+ // Check @ruvector/graph-node
1423
+ try {
1424
+ require.resolve('@ruvector/graph-node');
1425
+ console.log(chalk.green(` ✓ @ruvector/graph-node installed`));
1426
+ } catch (e) {
1427
+ console.log(chalk.gray(` ○ @ruvector/graph-node not installed (optional)`));
1428
+ }
1429
+ console.log('');
1430
+
1431
+ // Rust Toolchain (optional for development)
1432
+ console.log(chalk.cyan('Rust Toolchain (optional):'));
1433
+
1434
+ const rustVersion = getVersion('rustc --version');
1435
+ if (rustVersion) {
1436
+ console.log(chalk.green(` ✓ ${rustVersion}`));
1437
+ } else {
1438
+ console.log(chalk.gray(` ○ Rust not installed (only needed for development)`));
1439
+ }
1440
+
1441
+ const cargoVersion = getVersion('cargo --version');
1442
+ if (cargoVersion) {
1443
+ console.log(chalk.green(` ✓ ${cargoVersion}`));
1444
+ } else if (rustVersion) {
1445
+ console.log(chalk.yellow(` ! cargo not found`));
1446
+ warnings++;
1447
+ }
1448
+ console.log('');
1449
+
1450
+ // Build Tools (optional)
1451
+ if (options.verbose) {
1452
+ console.log(chalk.cyan('Build Tools (for native compilation):'));
1453
+
1454
+ const hasGcc = getVersion('gcc --version');
1455
+ const hasClang = getVersion('clang --version');
1456
+ const hasCc = getVersion('cc --version');
1457
+
1458
+ if (hasGcc || hasClang || hasCc) {
1459
+ console.log(chalk.green(` ✓ C compiler available`));
1460
+ } else {
1461
+ console.log(chalk.gray(` ○ No C compiler found (only needed for building from source)`));
1462
+ }
1463
+
1464
+ const hasMake = getVersion('make --version');
1465
+ if (hasMake) {
1466
+ console.log(chalk.green(` ✓ make available`));
1467
+ } else {
1468
+ console.log(chalk.gray(` ○ make not found`));
1469
+ }
1470
+
1471
+ const hasCmake = getVersion('cmake --version');
1472
+ if (hasCmake) {
1473
+ console.log(chalk.green(` ✓ cmake available`));
1474
+ } else {
1475
+ console.log(chalk.gray(` ○ cmake not found`));
1476
+ }
1477
+ console.log('');
1478
+ }
1479
+
1480
+ // Summary
1481
+ console.log(chalk.cyan('═══════════════════════════════════════════════════════════════'));
1482
+ if (issues === 0 && warnings === 0) {
1483
+ console.log(chalk.green('\n ✓ All checks passed! RuVector is ready to use.\n'));
1484
+ } else if (issues === 0) {
1485
+ console.log(chalk.yellow(`\n ! ${warnings} warning(s) found. RuVector should work but may have limited features.\n`));
1486
+ } else {
1487
+ console.log(chalk.red(`\n ✗ ${issues} issue(s) and ${warnings} warning(s) found.\n`));
1488
+ console.log(chalk.white(' Run "npx ruvector setup" for installation instructions.\n'));
1489
+ }
1490
+ });
1491
+
1492
+ // =============================================================================
1493
+ // Setup Command - Installation instructions
1494
+ // =============================================================================
1495
+
1496
+ program
1497
+ .command('setup')
1498
+ .description('Show installation and setup instructions')
1499
+ .option('--rust', 'Show Rust installation instructions')
1500
+ .option('--npm', 'Show npm package installation instructions')
1501
+ .option('--all', 'Show all installation instructions')
1502
+ .action((options) => {
1503
+ const showAll = options.all || (!options.rust && !options.npm);
1504
+
1505
+ console.log(chalk.cyan('\n═══════════════════════════════════════════════════════════════'));
1506
+ console.log(chalk.cyan(' RuVector Setup Guide'));
1507
+ console.log(chalk.cyan('═══════════════════════════════════════════════════════════════\n'));
1508
+
1509
+ // Quick install
1510
+ console.log(chalk.cyan('Quick Install (one-liner):'));
1511
+ console.log(chalk.white(' curl -fsSL https://raw.githubusercontent.com/ruvnet/ruvector/main/install.sh | bash'));
1512
+ console.log('');
1513
+
1514
+ if (showAll || options.npm) {
1515
+ console.log(chalk.cyan('───────────────────────────────────────────────────────────────'));
1516
+ console.log(chalk.cyan('npm Packages'));
1517
+ console.log(chalk.cyan('───────────────────────────────────────────────────────────────\n'));
1518
+
1519
+ console.log(chalk.yellow('All-in-one CLI:'));
1520
+ console.log(chalk.white(' npm install -g ruvector'));
1521
+ console.log(chalk.white(' npx ruvector'));
1522
+ console.log('');
1523
+
1524
+ console.log(chalk.yellow('Core packages:'));
1525
+ console.log(chalk.white(' npm install @ruvector/core # Vector database'));
1526
+ console.log(chalk.white(' npm install @ruvector/gnn # Graph Neural Networks'));
1527
+ console.log(chalk.white(' npm install @ruvector/graph-node # Hypergraph database'));
1528
+ console.log('');
1529
+
1530
+ console.log(chalk.yellow('Install all optional packages:'));
1531
+ console.log(chalk.white(' npx ruvector install --all'));
1532
+ console.log('');
1533
+
1534
+ console.log(chalk.yellow('List available packages:'));
1535
+ console.log(chalk.white(' npx ruvector install'));
1536
+ console.log('');
1537
+ }
1538
+
1539
+ if (showAll || options.rust) {
1540
+ console.log(chalk.cyan('───────────────────────────────────────────────────────────────'));
1541
+ console.log(chalk.cyan('Rust Installation'));
1542
+ console.log(chalk.cyan('───────────────────────────────────────────────────────────────\n'));
1543
+
1544
+ console.log(chalk.yellow('1. Install Rust:'));
1545
+ console.log(chalk.white(' curl --proto \'=https\' --tlsv1.2 -sSf https://sh.rustup.rs | sh'));
1546
+ console.log(chalk.gray(' # Follow the prompts, then restart your terminal or run:'));
1547
+ console.log(chalk.white(' source $HOME/.cargo/env'));
1548
+ console.log('');
1549
+
1550
+ console.log(chalk.yellow('2. Verify installation:'));
1551
+ console.log(chalk.white(' rustc --version'));
1552
+ console.log(chalk.white(' cargo --version'));
1553
+ console.log('');
1554
+
1555
+ console.log(chalk.yellow('3. Add RuVector crates to your project:'));
1556
+ console.log(chalk.white(' cargo add ruvector-core # Vector database'));
1557
+ console.log(chalk.white(' cargo add ruvector-graph # Hypergraph with Cypher'));
1558
+ console.log(chalk.white(' cargo add ruvector-gnn # Graph Neural Networks'));
1559
+ console.log('');
1560
+
1561
+ console.log(chalk.yellow('4. Other available crates:'));
1562
+ console.log(chalk.white(' cargo add ruvector-cluster # Distributed clustering'));
1563
+ console.log(chalk.white(' cargo add ruvector-raft # Raft consensus'));
1564
+ console.log(chalk.white(' cargo add ruvector-replication # Data replication'));
1565
+ console.log(chalk.white(' cargo add ruvector-tiny-dancer-core # AI routing'));
1566
+ console.log(chalk.white(' cargo add ruvector-router-core # Semantic routing'));
1567
+ console.log('');
1568
+
1569
+ console.log(chalk.yellow('Platform-specific notes:'));
1570
+ console.log('');
1571
+
1572
+ if (process.platform === 'darwin') {
1573
+ console.log(chalk.cyan(' macOS:'));
1574
+ console.log(chalk.white(' xcode-select --install # Install command line tools'));
1575
+ console.log('');
1576
+ } else if (process.platform === 'linux') {
1577
+ console.log(chalk.cyan(' Linux (Debian/Ubuntu):'));
1578
+ console.log(chalk.white(' sudo apt-get update'));
1579
+ console.log(chalk.white(' sudo apt-get install build-essential pkg-config libssl-dev'));
1580
+ console.log('');
1581
+ console.log(chalk.cyan(' Linux (RHEL/CentOS):'));
1582
+ console.log(chalk.white(' sudo yum groupinstall "Development Tools"'));
1583
+ console.log(chalk.white(' sudo yum install openssl-devel'));
1584
+ console.log('');
1585
+ } else if (process.platform === 'win32') {
1586
+ console.log(chalk.cyan(' Windows:'));
1587
+ console.log(chalk.white(' # Install Visual Studio Build Tools'));
1588
+ console.log(chalk.white(' # https://visualstudio.microsoft.com/visual-cpp-build-tools/'));
1589
+ console.log(chalk.white(' # Or use WSL2 for best experience'));
1590
+ console.log('');
1591
+ }
1592
+ }
1593
+
1594
+ console.log(chalk.cyan('───────────────────────────────────────────────────────────────'));
1595
+ console.log(chalk.cyan('Documentation & Resources'));
1596
+ console.log(chalk.cyan('───────────────────────────────────────────────────────────────\n'));
1597
+
1598
+ console.log(chalk.white(' GitHub: https://github.com/ruvnet/ruvector'));
1599
+ console.log(chalk.white(' npm: https://www.npmjs.com/package/ruvector'));
1600
+ console.log(chalk.white(' crates.io: https://crates.io/crates/ruvector-core'));
1601
+ console.log(chalk.white(' Issues: https://github.com/ruvnet/ruvector/issues'));
1602
+ console.log('');
1603
+
1604
+ console.log(chalk.cyan('Quick Commands:'));
1605
+ console.log(chalk.white(' npx ruvector doctor # Check system health'));
1606
+ console.log(chalk.white(' npx ruvector info # Show version info'));
1607
+ console.log(chalk.white(' npx ruvector benchmark # Run performance test'));
1608
+ console.log(chalk.white(' npx ruvector install # List available packages'));
1609
+ console.log('');
1610
+ });
1611
+
1612
+ // =============================================================================
1613
+ // Graph Commands - Cypher queries and graph operations
1614
+ // =============================================================================
1615
+
1616
+ program
1617
+ .command('graph')
1618
+ .description('Graph database operations (requires @ruvector/graph-node)')
1619
+ .option('-q, --query <cypher>', 'Execute Cypher query')
1620
+ .option('-c, --create <label>', 'Create a node with label')
1621
+ .option('-p, --properties <json>', 'Node properties as JSON')
1622
+ .option('-r, --relate <spec>', 'Create relationship (from:rel:to)')
1623
+ .option('--info', 'Show graph info and stats')
1624
+ .action(async (options) => {
1625
+ let graphNode;
1626
+ try {
1627
+ graphNode = require('@ruvector/graph-node');
1628
+ } catch (e) {
1629
+ console.log(chalk.yellow('\n @ruvector/graph-node is not installed.\n'));
1630
+ console.log(chalk.cyan(' Install with:'));
1631
+ console.log(chalk.white(' npm install @ruvector/graph-node\n'));
1632
+ console.log(chalk.cyan(' Features:'));
1633
+ console.log(chalk.gray(' - Cypher query language support'));
1634
+ console.log(chalk.gray(' - Hypergraph data structure'));
1635
+ console.log(chalk.gray(' - Knowledge graph operations'));
1636
+ console.log(chalk.gray(' - Neo4j-compatible syntax\n'));
1637
+ console.log(chalk.cyan(' Example usage:'));
1638
+ console.log(chalk.white(' npx ruvector graph --query "CREATE (n:Person {name: \'Alice\'})"'));
1639
+ console.log(chalk.white(' npx ruvector graph --query "MATCH (n) RETURN n"'));
1640
+ console.log('');
1641
+ return;
1642
+ }
1643
+
1644
+ console.log(chalk.cyan('\n═══════════════════════════════════════════════════════════════'));
1645
+ console.log(chalk.cyan(' RuVector Graph'));
1646
+ console.log(chalk.cyan('═══════════════════════════════════════════════════════════════\n'));
1647
+
1648
+ if (options.info) {
1649
+ console.log(chalk.green(' @ruvector/graph-node is available!'));
1650
+ console.log(chalk.gray(` Platform: ${process.platform}-${process.arch}`));
1651
+ console.log('');
1652
+ console.log(chalk.yellow(' Available operations:'));
1653
+ console.log(chalk.white(' --query <cypher> Execute Cypher query'));
1654
+ console.log(chalk.white(' --create <label> Create node with label'));
1655
+ console.log(chalk.white(' --relate <spec> Create relationship'));
1656
+ console.log('');
1657
+ return;
1658
+ }
1659
+
1660
+ if (options.query) {
1661
+ console.log(chalk.yellow(' Cypher Query:'), chalk.white(options.query));
1662
+ console.log('');
1663
+ // Actual implementation would execute the query
1664
+ console.log(chalk.gray(' Note: Full Cypher execution requires running ruvector-server'));
1665
+ console.log(chalk.gray(' See: npx ruvector server --help'));
1666
+ }
1667
+
1668
+ if (options.create) {
1669
+ const label = options.create;
1670
+ const props = options.properties ? JSON.parse(options.properties) : {};
1671
+ console.log(chalk.yellow(' Creating node:'), chalk.white(label));
1672
+ console.log(chalk.gray(' Properties:'), JSON.stringify(props, null, 2));
1673
+ }
1674
+
1675
+ console.log('');
1676
+ });
1677
+
1678
+ // =============================================================================
1679
+ // Router Commands - AI agent routing
1680
+ // =============================================================================
1681
+
1682
+ program
1683
+ .command('router')
1684
+ .description('AI semantic router operations (requires ruvector-router-core)')
1685
+ .option('--route <text>', 'Route text to best matching intent')
1686
+ .option('--intents <file>', 'Load intents from JSON file')
1687
+ .option('--add-intent <name>', 'Add new intent')
1688
+ .option('--examples <json>', 'Example utterances for intent')
1689
+ .option('--info', 'Show router info')
1690
+ .action(async (options) => {
1691
+ console.log(chalk.cyan('\n═══════════════════════════════════════════════════════════════'));
1692
+ console.log(chalk.cyan(' RuVector Router'));
1693
+ console.log(chalk.cyan('═══════════════════════════════════════════════════════════════\n'));
1694
+
1695
+ console.log(chalk.yellow(' Semantic Router for AI Agent Routing\n'));
1696
+
1697
+ if (options.info || (!options.route && !options.intents && !options.addIntent)) {
1698
+ console.log(chalk.cyan(' Features:'));
1699
+ console.log(chalk.gray(' - Semantic intent matching'));
1700
+ console.log(chalk.gray(' - Multi-agent routing'));
1701
+ console.log(chalk.gray(' - Dynamic intent registration'));
1702
+ console.log(chalk.gray(' - Vector-based similarity matching'));
1703
+ console.log('');
1704
+ console.log(chalk.cyan(' Status:'), chalk.yellow('Coming Soon'));
1705
+ console.log(chalk.gray(' The npm package for router is in development.'));
1706
+ console.log(chalk.gray(' Rust crate available: cargo add ruvector-router-core'));
1707
+ console.log('');
1708
+ console.log(chalk.cyan(' Usage (when available):'));
1709
+ console.log(chalk.white(' npx ruvector router --route "What is the weather?"'));
1710
+ console.log(chalk.white(' npx ruvector router --intents intents.json --route "query"'));
1711
+ console.log('');
1712
+ return;
1713
+ }
1714
+
1715
+ if (options.route) {
1716
+ console.log(chalk.yellow(' Input:'), chalk.white(options.route));
1717
+ console.log(chalk.gray(' Router package not yet available in npm.'));
1718
+ console.log(chalk.gray(' Check issue #20 for roadmap.'));
1719
+ }
1720
+
1721
+ console.log('');
1722
+ });
1723
+
1724
+ // =============================================================================
1725
+ // Server Commands - HTTP/gRPC server
1726
+ // =============================================================================
1727
+
1728
+ program
1729
+ .command('server')
1730
+ .description('Start RuVector HTTP/gRPC server')
1731
+ .option('-p, --port <number>', 'HTTP port', '8080')
1732
+ .option('-g, --grpc-port <number>', 'gRPC port', '50051')
1733
+ .option('-d, --data-dir <path>', 'Data directory', './ruvector-data')
1734
+ .option('--http-only', 'Start only HTTP server')
1735
+ .option('--grpc-only', 'Start only gRPC server')
1736
+ .option('--cors', 'Enable CORS for all origins')
1737
+ .option('--info', 'Show server info')
1738
+ .action(async (options) => {
1739
+ console.log(chalk.cyan('\n═══════════════════════════════════════════════════════════════'));
1740
+ console.log(chalk.cyan(' RuVector Server'));
1741
+ console.log(chalk.cyan('═══════════════════════════════════════════════════════════════\n'));
1742
+
1743
+ if (options.info || Object.keys(options).filter(k => k !== 'port' && k !== 'grpcPort' && k !== 'dataDir').length === 0) {
1744
+ console.log(chalk.cyan(' Status:'), chalk.yellow('Coming Soon'));
1745
+ console.log('');
1746
+ console.log(chalk.cyan(' Planned Features:'));
1747
+ console.log(chalk.gray(' - REST API for vector operations'));
1748
+ console.log(chalk.gray(' - gRPC high-performance interface'));
1749
+ console.log(chalk.gray(' - WebSocket real-time updates'));
1750
+ console.log(chalk.gray(' - OpenAPI/Swagger documentation'));
1751
+ console.log(chalk.gray(' - Prometheus metrics endpoint'));
1752
+ console.log(chalk.gray(' - Health check endpoints'));
1753
+ console.log('');
1754
+ console.log(chalk.cyan(' Rust binary available:'));
1755
+ console.log(chalk.white(' cargo install ruvector-server # When published'));
1756
+ console.log('');
1757
+ console.log(chalk.cyan(' Configuration (when available):'));
1758
+ console.log(chalk.white(` --port ${options.port} # HTTP port`));
1759
+ console.log(chalk.white(` --grpc-port ${options.grpcPort} # gRPC port`));
1760
+ console.log(chalk.white(` --data-dir ${options.dataDir} # Data directory`));
1761
+ console.log('');
1762
+ console.log(chalk.gray(' Track progress: https://github.com/ruvnet/ruvector/issues/20'));
1763
+ console.log('');
1764
+ return;
1765
+ }
1766
+
1767
+ console.log(chalk.yellow(' Server package not yet available.'));
1768
+ console.log(chalk.gray(' Check issue #20 for roadmap.'));
1769
+ console.log('');
1770
+ });
1771
+
1772
+ // =============================================================================
1773
+ // Cluster Commands - Distributed operations
1774
+ // =============================================================================
1775
+
1776
+ program
1777
+ .command('cluster')
1778
+ .description('Distributed cluster operations')
1779
+ .option('--status', 'Show cluster status')
1780
+ .option('--join <address>', 'Join existing cluster')
1781
+ .option('--leave', 'Leave cluster')
1782
+ .option('--nodes', 'List cluster nodes')
1783
+ .option('--leader', 'Show current leader')
1784
+ .option('--info', 'Show cluster info')
1785
+ .action(async (options) => {
1786
+ console.log(chalk.cyan('\n═══════════════════════════════════════════════════════════════'));
1787
+ console.log(chalk.cyan(' RuVector Cluster'));
1788
+ console.log(chalk.cyan('═══════════════════════════════════════════════════════════════\n'));
1789
+
1790
+ console.log(chalk.cyan(' Status:'), chalk.yellow('Coming Soon'));
1791
+ console.log('');
1792
+ console.log(chalk.cyan(' Features:'));
1793
+ console.log(chalk.gray(' - Raft consensus for leader election'));
1794
+ console.log(chalk.gray(' - Automatic failover'));
1795
+ console.log(chalk.gray(' - Data replication'));
1796
+ console.log(chalk.gray(' - Sharding support'));
1797
+ console.log(chalk.gray(' - Distributed queries'));
1798
+ console.log('');
1799
+ console.log(chalk.cyan(' Rust crates available:'));
1800
+ console.log(chalk.white(' cargo add ruvector-cluster # Clustering'));
1801
+ console.log(chalk.white(' cargo add ruvector-raft # Raft consensus'));
1802
+ console.log(chalk.white(' cargo add ruvector-replication # Replication'));
1803
+ console.log('');
1804
+ console.log(chalk.cyan(' Commands (when available):'));
1805
+ console.log(chalk.white(' npx ruvector cluster --status'));
1806
+ console.log(chalk.white(' npx ruvector cluster --join 192.168.1.10:7000'));
1807
+ console.log(chalk.white(' npx ruvector cluster --nodes'));
1808
+ console.log('');
1809
+ console.log(chalk.gray(' Track progress: https://github.com/ruvnet/ruvector/issues/20'));
1810
+ console.log('');
1811
+ });
1812
+
1813
+ // =============================================================================
1814
+ // Export/Import Commands - Database backup/restore
1815
+ // =============================================================================
1816
+
1817
+ program
1818
+ .command('export <database>')
1819
+ .description('Export database to file')
1820
+ .option('-o, --output <file>', 'Output file path')
1821
+ .option('-f, --format <type>', 'Export format (json|binary|parquet)', 'json')
1822
+ .option('--compress', 'Compress output')
1823
+ .option('--vectors-only', 'Export only vectors (no metadata)')
1824
+ .action(async (dbPath, options) => {
1825
+ requireRuvector();
1826
+ const spinner = ora('Exporting database...').start();
1827
+
1828
+ try {
1829
+ const outputFile = options.output || `${dbPath.replace(/\/$/, '')}_export.${options.format}`;
1830
+
1831
+ // Load database
1832
+ const db = new VectorDB({ dimension: 384 }); // Will be overwritten by load
1833
+ if (fs.existsSync(dbPath)) {
1834
+ db.load(dbPath);
1835
+ } else {
1836
+ spinner.fail(chalk.red(`Database not found: ${dbPath}`));
1837
+ process.exit(1);
1838
+ }
1839
+
1840
+ const stats = db.getStats();
1841
+ const data = {
1842
+ version: packageJson.version,
1843
+ exportedAt: new Date().toISOString(),
1844
+ stats: stats,
1845
+ vectors: [] // Would contain actual vector data
1846
+ };
1847
+
1848
+ if (options.format === 'json') {
1849
+ fs.writeFileSync(outputFile, JSON.stringify(data, null, 2));
1850
+ } else {
1851
+ spinner.fail(chalk.yellow(`Format '${options.format}' not yet supported. Using JSON.`));
1852
+ fs.writeFileSync(outputFile.replace(/\.[^.]+$/, '.json'), JSON.stringify(data, null, 2));
1853
+ }
1854
+
1855
+ spinner.succeed(chalk.green(`Exported to: ${outputFile}`));
1856
+ console.log(chalk.gray(` Vectors: ${stats.count || 0}`));
1857
+ console.log(chalk.gray(` Format: ${options.format}`));
1858
+ } catch (error) {
1859
+ spinner.fail(chalk.red('Export failed'));
1860
+ console.error(chalk.red(error.message));
1861
+ process.exit(1);
1862
+ }
1863
+ });
1864
+
1865
+ program
1866
+ .command('import <file>')
1867
+ .description('Import database from file')
1868
+ .option('-d, --database <path>', 'Target database path')
1869
+ .option('--merge', 'Merge with existing data')
1870
+ .option('--replace', 'Replace existing data')
1871
+ .action(async (file, options) => {
1872
+ requireRuvector();
1873
+ const spinner = ora('Importing database...').start();
1874
+
1875
+ try {
1876
+ if (!fs.existsSync(file)) {
1877
+ spinner.fail(chalk.red(`File not found: ${file}`));
1878
+ process.exit(1);
1879
+ }
1880
+
1881
+ const data = JSON.parse(fs.readFileSync(file, 'utf8'));
1882
+ const dbPath = options.database || file.replace(/_export\.json$/, '');
1883
+
1884
+ spinner.text = 'Creating database...';
1885
+
1886
+ const db = new VectorDB({
1887
+ dimension: data.stats?.dimension || 384,
1888
+ path: dbPath,
1889
+ autoPersist: true
1890
+ });
1891
+
1892
+ // Would import actual vectors here
1893
+ db.save(dbPath);
1894
+
1895
+ spinner.succeed(chalk.green(`Imported to: ${dbPath}`));
1896
+ console.log(chalk.gray(` Source version: ${data.version}`));
1897
+ console.log(chalk.gray(` Exported at: ${data.exportedAt}`));
1898
+ } catch (error) {
1899
+ spinner.fail(chalk.red('Import failed'));
1900
+ console.error(chalk.red(error.message));
1901
+ process.exit(1);
1902
+ }
1903
+ });
1904
+
1905
+ // =============================================================================
1906
+ // Embed Command - Generate embeddings
1907
+ // =============================================================================
1908
+
1909
+ program
1910
+ .command('embed')
1911
+ .description('Generate embeddings from text')
1912
+ .option('-t, --text <string>', 'Text to embed')
1913
+ .option('-f, --file <path>', 'File containing text (one per line)')
1914
+ .option('-m, --model <name>', 'Embedding model', 'all-minilm-l6-v2')
1915
+ .option('-o, --output <file>', 'Output file for embeddings')
1916
+ .option('--info', 'Show embedding info')
1917
+ .action(async (options) => {
1918
+ console.log(chalk.cyan('\n═══════════════════════════════════════════════════════════════'));
1919
+ console.log(chalk.cyan(' RuVector Embed'));
1920
+ console.log(chalk.cyan('═══════════════════════════════════════════════════════════════\n'));
1921
+
1922
+ if (options.info || (!options.text && !options.file)) {
1923
+ console.log(chalk.cyan(' Generate vector embeddings from text\n'));
1924
+ console.log(chalk.cyan(' Supported Models:'));
1925
+ console.log(chalk.gray(' - all-minilm-l6-v2 (384 dims, fast)'));
1926
+ console.log(chalk.gray(' - nomic-embed-text-v1.5 (768 dims, balanced)'));
1927
+ console.log(chalk.gray(' - openai/text-embedding-3-small (1536 dims, requires API key)'));
1928
+ console.log('');
1929
+ console.log(chalk.cyan(' Status:'), chalk.yellow('Coming Soon'));
1930
+ console.log(chalk.gray(' Built-in embedding generation is planned for future release.'));
1931
+ console.log('');
1932
+ console.log(chalk.cyan(' Current options:'));
1933
+ console.log(chalk.gray(' 1. Use external embedding API (OpenAI, Cohere, etc.)'));
1934
+ console.log(chalk.gray(' 2. Use transformers.js in your application'));
1935
+ console.log(chalk.gray(' 3. Pre-generate embeddings with Python'));
1936
+ console.log('');
1937
+ console.log(chalk.cyan(' Usage (when available):'));
1938
+ console.log(chalk.white(' npx ruvector embed --text "Hello world"'));
1939
+ console.log(chalk.white(' npx ruvector embed --file texts.txt --output embeddings.json'));
1940
+ console.log('');
1941
+ return;
1942
+ }
1943
+
1944
+ if (options.text) {
1945
+ console.log(chalk.yellow(' Input text:'), chalk.white(options.text.substring(0, 50) + '...'));
1946
+ console.log(chalk.yellow(' Model:'), chalk.white(options.model));
1947
+ console.log('');
1948
+ console.log(chalk.gray(' Embedding generation not yet available in CLI.'));
1949
+ console.log(chalk.gray(' Use the SDK or external embedding services.'));
1950
+ }
1951
+
1952
+ console.log('');
1953
+ });
1954
+
1955
+ // =============================================================================
1956
+ // Demo Command - Interactive tutorial
1957
+ // =============================================================================
1958
+
1959
+ program
1960
+ .command('demo')
1961
+ .description('Run interactive demo and tutorials')
1962
+ .option('--basic', 'Basic vector operations demo')
1963
+ .option('--gnn', 'GNN differentiable search demo')
1964
+ .option('--graph', 'Graph database demo')
1965
+ .option('--benchmark', 'Performance benchmark demo')
1966
+ .option('-i, --interactive', 'Interactive mode')
1967
+ .action(async (options) => {
1968
+ console.log(chalk.cyan('\n═══════════════════════════════════════════════════════════════'));
1969
+ console.log(chalk.cyan(' RuVector Demo'));
1970
+ console.log(chalk.cyan('═══════════════════════════════════════════════════════════════\n'));
1971
+
1972
+ const showMenu = !options.basic && !options.gnn && !options.graph && !options.benchmark;
1973
+
1974
+ if (showMenu) {
1975
+ console.log(chalk.yellow(' Available Demos:\n'));
1976
+ console.log(chalk.white(' --basic '), chalk.gray('Basic vector operations (insert, search, delete)'));
1977
+ console.log(chalk.white(' --gnn '), chalk.gray('GNN differentiable search with gradients'));
1978
+ console.log(chalk.white(' --graph '), chalk.gray('Graph database and Cypher queries'));
1979
+ console.log(chalk.white(' --benchmark '), chalk.gray('Performance benchmark suite'));
1980
+ console.log('');
1981
+ console.log(chalk.cyan(' Run a demo:'));
1982
+ console.log(chalk.white(' npx ruvector demo --basic'));
1983
+ console.log(chalk.white(' npx ruvector demo --gnn'));
1984
+ console.log('');
1985
+ return;
1986
+ }
1987
+
1988
+ if (options.basic) {
1989
+ requireRuvector();
1990
+ console.log(chalk.yellow(' Basic Vector Operations Demo\n'));
1991
+
1992
+ const spinner = ora('Creating demo database...').start();
1993
+
1994
+ try {
1995
+ const db = new VectorDB({ dimension: 4, metric: 'cosine' });
1996
+
1997
+ spinner.text = 'Inserting vectors...';
1998
+ db.insert('vec1', [1.0, 0.0, 0.0, 0.0], { label: 'x-axis' });
1999
+ db.insert('vec2', [0.0, 1.0, 0.0, 0.0], { label: 'y-axis' });
2000
+ db.insert('vec3', [0.0, 0.0, 1.0, 0.0], { label: 'z-axis' });
2001
+ db.insert('vec4', [0.7, 0.7, 0.0, 0.0], { label: 'xy-diagonal' });
2002
+
2003
+ spinner.succeed('Demo database created with 4 vectors');
2004
+
2005
+ console.log(chalk.cyan('\n Vectors inserted:'));
2006
+ console.log(chalk.gray(' vec1: [1,0,0,0] - x-axis'));
2007
+ console.log(chalk.gray(' vec2: [0,1,0,0] - y-axis'));
2008
+ console.log(chalk.gray(' vec3: [0,0,1,0] - z-axis'));
2009
+ console.log(chalk.gray(' vec4: [0.7,0.7,0,0] - xy-diagonal'));
2010
+
2011
+ console.log(chalk.cyan('\n Searching for nearest to [0.8, 0.6, 0, 0]:'));
2012
+ const results = db.search([0.8, 0.6, 0.0, 0.0], 3);
2013
+ results.forEach((r, i) => {
2014
+ console.log(chalk.gray(` ${i + 1}. ${r.id} (score: ${r.score.toFixed(4)})`));
2015
+ });
2016
+
2017
+ console.log(chalk.green('\n Demo complete!'));
2018
+ } catch (error) {
2019
+ spinner.fail(chalk.red('Demo failed'));
2020
+ console.error(chalk.red(error.message));
2021
+ }
2022
+ }
2023
+
2024
+ if (options.gnn) {
2025
+ if (!gnnAvailable) {
2026
+ console.log(chalk.yellow(' @ruvector/gnn not installed.'));
2027
+ console.log(chalk.white(' Install with: npm install @ruvector/gnn'));
2028
+ console.log('');
2029
+ return;
2030
+ }
2031
+
2032
+ console.log(chalk.yellow(' GNN Differentiable Search Demo\n'));
2033
+
2034
+ try {
2035
+ console.log(chalk.cyan(' Running differentiable search with gradients...\n'));
2036
+
2037
+ const queryVec = [1.0, 0.5, 0.3, 0.1];
2038
+ const dbVectors = [
2039
+ [1.0, 0.0, 0.0, 0.0],
2040
+ [0.0, 1.0, 0.0, 0.0],
2041
+ [0.5, 0.5, 0.5, 0.5],
2042
+ [0.9, 0.4, 0.2, 0.1]
2043
+ ];
2044
+
2045
+ const result = differentiableSearch(queryVec, dbVectors, 3, 10.0);
2046
+
2047
+ console.log(chalk.cyan(' Query:'), JSON.stringify(queryVec));
2048
+ console.log(chalk.cyan(' Top 3 results:'));
2049
+ result.indices.forEach((idx, i) => {
2050
+ console.log(chalk.gray(` ${i + 1}. Index ${idx} (attention: ${result.attention_weights[i].toFixed(4)})`));
2051
+ });
2052
+
2053
+ console.log(chalk.cyan('\n Gradient flow enabled:'), chalk.green('Yes'));
2054
+ console.log(chalk.gray(' Use for: Neural network training, learned retrieval'));
2055
+
2056
+ console.log(chalk.green('\n GNN demo complete!'));
2057
+ } catch (error) {
2058
+ console.error(chalk.red('GNN demo failed:', error.message));
2059
+ }
2060
+ }
2061
+
2062
+ if (options.graph) {
2063
+ console.log(chalk.yellow(' Graph Database Demo\n'));
2064
+
2065
+ let graphNode;
2066
+ try {
2067
+ graphNode = require('@ruvector/graph-node');
2068
+ console.log(chalk.green(' @ruvector/graph-node is available!'));
2069
+ console.log(chalk.gray(' Full graph demo coming soon.'));
2070
+ } catch (e) {
2071
+ console.log(chalk.yellow(' @ruvector/graph-node not installed.'));
2072
+ console.log(chalk.white(' Install with: npm install @ruvector/graph-node'));
2073
+ }
2074
+ console.log('');
2075
+ }
2076
+
2077
+ if (options.benchmark) {
2078
+ console.log(chalk.yellow(' Redirecting to benchmark command...\n'));
2079
+ console.log(chalk.white(' Run: npx ruvector benchmark'));
2080
+ console.log('');
2081
+ }
2082
+ });
2083
+
858
2084
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ruvector",
3
- "version": "0.1.23",
3
+ "version": "0.1.25",
4
4
  "description": "High-performance vector database for Node.js with automatic native/WASM fallback",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -29,7 +29,11 @@
29
29
  "wasm",
30
30
  "native",
31
31
  "ruv",
32
- "ruvector"
32
+ "ruvector",
33
+ "attention",
34
+ "transformer",
35
+ "flash-attention",
36
+ "hyperbolic"
33
37
  ],
34
38
  "author": "ruv.io Team <info@ruv.io> (https://ruv.io)",
35
39
  "homepage": "https://ruv.io",
@@ -43,12 +47,15 @@
43
47
  "directory": "npm/packages/ruvector"
44
48
  },
45
49
  "dependencies": {
46
- "@ruvector/core": "^0.1.15",
50
+ "@ruvector/core": "^0.1.16",
47
51
  "@ruvector/gnn": "^0.1.15",
48
52
  "commander": "^11.1.0",
49
53
  "chalk": "^4.1.2",
50
54
  "ora": "^5.4.1"
51
55
  },
56
+ "optionalDependencies": {
57
+ "@ruvector/attention": "^0.1.1"
58
+ },
52
59
  "devDependencies": {
53
60
  "@types/node": "^20.10.5",
54
61
  "typescript": "^5.3.3"