ruvector 0.2.23 → 0.2.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.
- package/bin/cli.js +211 -63
- package/dist/analysis/complexity.d.ts +52 -0
- package/dist/analysis/complexity.d.ts.map +1 -0
- package/dist/analysis/complexity.js +146 -0
- package/dist/analysis/index.d.ts +15 -0
- package/dist/analysis/index.d.ts.map +1 -0
- package/dist/analysis/index.js +38 -0
- package/dist/analysis/patterns.d.ts +71 -0
- package/dist/analysis/patterns.d.ts.map +1 -0
- package/dist/analysis/patterns.js +243 -0
- package/dist/analysis/security.d.ts +51 -0
- package/dist/analysis/security.d.ts.map +1 -0
- package/dist/analysis/security.js +139 -0
- package/dist/core/adaptive-embedder.d.ts +156 -0
- package/dist/core/adaptive-embedder.d.ts.map +1 -0
- package/dist/core/adaptive-embedder.js +838 -0
- package/dist/core/agentdb-fast.d.ts +149 -0
- package/dist/core/agentdb-fast.d.ts.map +1 -0
- package/dist/core/agentdb-fast.js +301 -0
- package/dist/core/ast-parser.d.ts +108 -0
- package/dist/core/ast-parser.d.ts.map +1 -0
- package/dist/core/ast-parser.js +602 -0
- package/dist/core/attention-fallbacks.d.ts +321 -0
- package/dist/core/attention-fallbacks.d.ts.map +1 -0
- package/dist/core/attention-fallbacks.js +552 -0
- package/dist/core/cluster-wrapper.d.ts +148 -0
- package/dist/core/cluster-wrapper.d.ts.map +1 -0
- package/dist/core/cluster-wrapper.js +271 -0
- package/dist/core/coverage-router.d.ts +88 -0
- package/dist/core/coverage-router.d.ts.map +1 -0
- package/dist/core/coverage-router.js +315 -0
- package/dist/core/diff-embeddings.d.ts +93 -0
- package/dist/core/diff-embeddings.d.ts.map +1 -0
- package/dist/core/diff-embeddings.js +334 -0
- package/dist/core/diskann-wrapper.d.ts +53 -0
- package/dist/core/diskann-wrapper.d.ts.map +1 -0
- package/dist/core/diskann-wrapper.js +105 -0
- package/dist/core/gnn-wrapper.d.ts +143 -0
- package/dist/core/gnn-wrapper.d.ts.map +1 -0
- package/dist/core/gnn-wrapper.js +213 -0
- package/dist/core/graph-algorithms.d.ts +83 -0
- package/dist/core/graph-algorithms.d.ts.map +1 -0
- package/dist/core/graph-algorithms.js +514 -0
- package/dist/core/graph-wrapper.d.ts +147 -0
- package/dist/core/graph-wrapper.d.ts.map +1 -0
- package/dist/core/graph-wrapper.js +299 -0
- package/dist/core/index.d.ts +50 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +92 -0
- package/dist/core/intelligence-engine.d.ts +258 -0
- package/dist/core/intelligence-engine.d.ts.map +1 -0
- package/dist/core/intelligence-engine.js +1030 -0
- package/dist/core/learning-engine.d.ts +160 -0
- package/dist/core/learning-engine.d.ts.map +1 -0
- package/dist/core/learning-engine.js +589 -0
- package/dist/core/neural-embeddings.d.ts +393 -0
- package/dist/core/neural-embeddings.d.ts.map +1 -0
- package/dist/core/neural-embeddings.js +1091 -0
- package/dist/core/neural-perf.d.ts +331 -0
- package/dist/core/neural-perf.d.ts.map +1 -0
- package/dist/core/neural-perf.js +704 -0
- package/dist/core/onnx/pkg/package.json +3 -0
- package/dist/core/onnx-embedder.d.ts +105 -0
- package/dist/core/onnx-embedder.d.ts.map +1 -0
- package/dist/core/onnx-embedder.js +410 -0
- package/dist/core/onnx-optimized.d.ts +109 -0
- package/dist/core/onnx-optimized.d.ts.map +1 -0
- package/dist/core/onnx-optimized.js +419 -0
- package/dist/core/parallel-intelligence.d.ts +109 -0
- package/dist/core/parallel-intelligence.d.ts.map +1 -0
- package/dist/core/parallel-intelligence.js +340 -0
- package/dist/core/parallel-workers.d.ts +177 -0
- package/dist/core/parallel-workers.d.ts.map +1 -0
- package/dist/core/parallel-workers.js +783 -0
- package/dist/core/router-wrapper.d.ts +75 -0
- package/dist/core/router-wrapper.d.ts.map +1 -0
- package/dist/core/router-wrapper.js +243 -0
- package/dist/core/rvf-wrapper.d.ts +86 -0
- package/dist/core/rvf-wrapper.d.ts.map +1 -0
- package/dist/core/rvf-wrapper.js +102 -0
- package/dist/core/sona-wrapper.d.ts +226 -0
- package/dist/core/sona-wrapper.d.ts.map +1 -0
- package/dist/core/sona-wrapper.js +282 -0
- package/dist/core/tensor-compress.d.ts +134 -0
- package/dist/core/tensor-compress.d.ts.map +1 -0
- package/dist/core/tensor-compress.js +432 -0
- package/dist/index.d.ts +106 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +258 -0
- package/dist/services/embedding-service.d.ts +136 -0
- package/dist/services/embedding-service.d.ts.map +1 -0
- package/dist/services/embedding-service.js +294 -0
- package/dist/services/index.d.ts +6 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +26 -0
- package/dist/types.d.ts +145 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/workers/benchmark.d.ts +44 -0
- package/dist/workers/benchmark.d.ts.map +1 -0
- package/dist/workers/benchmark.js +230 -0
- package/dist/workers/index.d.ts +10 -0
- package/dist/workers/index.d.ts.map +1 -0
- package/dist/workers/index.js +25 -0
- package/dist/workers/native-worker.d.ts +76 -0
- package/dist/workers/native-worker.d.ts.map +1 -0
- package/dist/workers/native-worker.js +490 -0
- package/dist/workers/types.d.ts +69 -0
- package/dist/workers/types.d.ts.map +1 -0
- package/dist/workers/types.js +7 -0
- package/package.json +8 -7
package/bin/cli.js
CHANGED
|
@@ -125,6 +125,21 @@ const program = new Command();
|
|
|
125
125
|
// Get package version from package.json
|
|
126
126
|
const packageJson = require('../package.json');
|
|
127
127
|
|
|
128
|
+
// `@ruvector/gnn@0.1.25` has a native-binding regression where every method
|
|
129
|
+
// throws `Given napi value is not an array` regardless of input shape (verified
|
|
130
|
+
// with both Array<Float32Array> and number[][]). Use this helper to print a
|
|
131
|
+
// pointer to the upstream issue when the CLI-side typed-array conversion is
|
|
132
|
+
// already correct.
|
|
133
|
+
function reportGnnBindingError(error) {
|
|
134
|
+
const msg = error && error.message ? error.message : String(error);
|
|
135
|
+
console.error(chalk.red(msg));
|
|
136
|
+
if (msg.includes('Given napi value is not an array') || msg.includes('TypedArray info failed')) {
|
|
137
|
+
console.error(chalk.yellow(' Note: this is a known regression in the @ruvector/gnn native binding,'));
|
|
138
|
+
console.error(chalk.yellow(' not in the CLI. Track at:'));
|
|
139
|
+
console.error(chalk.white(' https://github.com/ruvnet/ruvector/issues/402'));
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
128
143
|
// Version and description (lazy load implementation info)
|
|
129
144
|
program
|
|
130
145
|
.name('ruvector')
|
|
@@ -758,13 +773,16 @@ gnnCmd
|
|
|
758
773
|
if (options.test) {
|
|
759
774
|
spinner.start('Running test forward pass...');
|
|
760
775
|
|
|
761
|
-
//
|
|
762
|
-
|
|
763
|
-
const
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
776
|
+
// The @ruvector/gnn binding requires Float32Array — plain number[] surfaces
|
|
777
|
+
// as `Get TypedArray info failed` from napi-rs.
|
|
778
|
+
const randVec = (n) => {
|
|
779
|
+
const v = new Float32Array(n);
|
|
780
|
+
for (let i = 0; i < n; i++) v[i] = Math.random();
|
|
781
|
+
return v;
|
|
782
|
+
};
|
|
783
|
+
const nodeEmbedding = randVec(inputDim);
|
|
784
|
+
const neighborEmbeddings = [randVec(inputDim), randVec(inputDim)];
|
|
785
|
+
const edgeWeights = new Float32Array([0.6, 0.4]);
|
|
768
786
|
|
|
769
787
|
const output = layer.forward(nodeEmbedding, neighborEmbeddings, edgeWeights);
|
|
770
788
|
spinner.succeed(chalk.green('Forward pass completed'));
|
|
@@ -782,7 +800,7 @@ gnnCmd
|
|
|
782
800
|
}
|
|
783
801
|
} catch (error) {
|
|
784
802
|
spinner.fail(chalk.red('Failed to create GNN layer'));
|
|
785
|
-
|
|
803
|
+
reportGnnBindingError(error);
|
|
786
804
|
process.exit(1);
|
|
787
805
|
}
|
|
788
806
|
});
|
|
@@ -812,7 +830,9 @@ gnnCmd
|
|
|
812
830
|
let totalCompressedSize = 0;
|
|
813
831
|
|
|
814
832
|
for (const embedding of embeddings) {
|
|
815
|
-
const
|
|
833
|
+
const rawVec = embedding.vector || embedding;
|
|
834
|
+
// TensorCompress requires Float32Array.
|
|
835
|
+
const vec = rawVec instanceof Float32Array ? rawVec : new Float32Array(rawVec);
|
|
816
836
|
totalOriginalSize += vec.length * 4; // float32 = 4 bytes
|
|
817
837
|
|
|
818
838
|
let compressed;
|
|
@@ -855,7 +875,7 @@ gnnCmd
|
|
|
855
875
|
}
|
|
856
876
|
} catch (error) {
|
|
857
877
|
spinner.fail(chalk.red('Failed to compress embeddings'));
|
|
858
|
-
|
|
878
|
+
reportGnnBindingError(error);
|
|
859
879
|
process.exit(1);
|
|
860
880
|
}
|
|
861
881
|
});
|
|
@@ -875,12 +895,18 @@ gnnCmd
|
|
|
875
895
|
try {
|
|
876
896
|
const query = JSON.parse(options.query);
|
|
877
897
|
const candidatesData = JSON.parse(fs.readFileSync(options.candidates, 'utf8'));
|
|
878
|
-
|
|
898
|
+
// @ruvector/gnn's differentiableSearch needs Float32Array everywhere; plain
|
|
899
|
+
// number[] surfaces as napi-rs `Get TypedArray info failed`.
|
|
900
|
+
const queryVec = query instanceof Float32Array ? query : new Float32Array(query);
|
|
901
|
+
const candidates = candidatesData.map((c) => {
|
|
902
|
+
const v = c.vector || c;
|
|
903
|
+
return v instanceof Float32Array ? v : new Float32Array(v);
|
|
904
|
+
});
|
|
879
905
|
const k = parseInt(options.topK);
|
|
880
906
|
const temperature = parseFloat(options.temperature);
|
|
881
907
|
|
|
882
908
|
spinner.text = 'Running differentiable search...';
|
|
883
|
-
const result = differentiableSearch(
|
|
909
|
+
const result = differentiableSearch(queryVec, candidates, k, temperature);
|
|
884
910
|
|
|
885
911
|
spinner.succeed(chalk.green(`Found top-${k} results`));
|
|
886
912
|
|
|
@@ -889,17 +915,19 @@ gnnCmd
|
|
|
889
915
|
console.log(chalk.white(` Candidates: ${chalk.yellow(candidates.length)}`));
|
|
890
916
|
console.log(chalk.white(` Temperature: ${chalk.yellow(temperature)}`));
|
|
891
917
|
|
|
918
|
+
// The wrapper exposes `weights`; older native shape used `attention_weights`.
|
|
919
|
+
const weights = result.weights || result.attention_weights || [];
|
|
892
920
|
console.log(chalk.cyan('\nTop-K Results:'));
|
|
893
921
|
for (let i = 0; i < result.indices.length; i++) {
|
|
894
922
|
const idx = result.indices[i];
|
|
895
|
-
const weight =
|
|
923
|
+
const weight = weights[i];
|
|
896
924
|
const id = candidatesData[idx]?.id || `candidate_${idx}`;
|
|
897
925
|
console.log(chalk.white(` ${i + 1}. ${chalk.yellow(id)} (index: ${idx})`));
|
|
898
|
-
console.log(chalk.gray(` Weight: ${weight.toFixed(6)}`));
|
|
926
|
+
console.log(chalk.gray(` Weight: ${weight != null ? weight.toFixed(6) : 'n/a'}`));
|
|
899
927
|
}
|
|
900
928
|
} catch (error) {
|
|
901
929
|
spinner.fail(chalk.red('Failed to run search'));
|
|
902
|
-
|
|
930
|
+
reportGnnBindingError(error);
|
|
903
931
|
process.exit(1);
|
|
904
932
|
}
|
|
905
933
|
});
|
|
@@ -971,59 +999,60 @@ attentionCmd
|
|
|
971
999
|
const spinner = ora('Loading keys...').start();
|
|
972
1000
|
|
|
973
1001
|
try {
|
|
974
|
-
const
|
|
1002
|
+
const queryRaw = JSON.parse(options.query);
|
|
975
1003
|
const keysData = JSON.parse(fs.readFileSync(options.keys, 'utf8'));
|
|
976
|
-
|
|
1004
|
+
// The native @ruvector/attention bindings require Float32Array; passing
|
|
1005
|
+
// plain number[] surfaces as napi-rs `Get TypedArray info failed` or
|
|
1006
|
+
// (when dim is read off a missing arg) `... Undefined into rust type u32`.
|
|
1007
|
+
const toF32 = (v) => (v instanceof Float32Array ? v : new Float32Array(v));
|
|
1008
|
+
const query = toF32(queryRaw);
|
|
1009
|
+
const keys = keysData.map((k) => toF32(k.vector || k));
|
|
977
1010
|
|
|
978
1011
|
let values = keys;
|
|
979
1012
|
if (options.values) {
|
|
980
1013
|
const valuesData = JSON.parse(fs.readFileSync(options.values, 'utf8'));
|
|
981
|
-
values = valuesData.map(v => v.vector || v);
|
|
1014
|
+
values = valuesData.map((v) => toF32(v.vector || v));
|
|
982
1015
|
}
|
|
983
1016
|
|
|
1017
|
+
const dim = query.length;
|
|
1018
|
+
|
|
984
1019
|
spinner.text = `Computing ${options.type} attention...`;
|
|
985
1020
|
|
|
986
1021
|
let result;
|
|
987
1022
|
let attentionWeights;
|
|
988
1023
|
|
|
1024
|
+
// The native @ruvector/attention bindings expose `compute(query, keys, values)`
|
|
1025
|
+
// — a flat Float32Array query plus Float32Array[] keys/values, returning a
|
|
1026
|
+
// flat Float32Array. The older CLI invoked `forward([query], keys, values)`,
|
|
1027
|
+
// which doesn't exist on the current binding (issue #402 §B).
|
|
989
1028
|
switch (options.type) {
|
|
990
1029
|
case 'dot': {
|
|
991
|
-
const attn = new DotProductAttention();
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
result = output[0];
|
|
995
|
-
attentionWeights = attn.getLastWeights ? attn.getLastWeights()[0] : null;
|
|
1030
|
+
const attn = new DotProductAttention(dim);
|
|
1031
|
+
result = attn.compute(query, keys, values);
|
|
1032
|
+
attentionWeights = attn.getLastWeights ? attn.getLastWeights() : null;
|
|
996
1033
|
break;
|
|
997
1034
|
}
|
|
998
1035
|
case 'multi-head': {
|
|
999
1036
|
const numHeads = parseInt(options.heads);
|
|
1000
1037
|
const headDim = parseInt(options.headDim);
|
|
1001
|
-
const attn = new MultiHeadAttention(
|
|
1002
|
-
|
|
1003
|
-
const output = attn.forward(queryMat, keys, values);
|
|
1004
|
-
result = output[0];
|
|
1038
|
+
const attn = new MultiHeadAttention(dim, numHeads, headDim);
|
|
1039
|
+
result = attn.compute(query, keys, values);
|
|
1005
1040
|
break;
|
|
1006
1041
|
}
|
|
1007
1042
|
case 'flash': {
|
|
1008
|
-
const attn = new FlashAttention(
|
|
1009
|
-
|
|
1010
|
-
const output = attn.forward(queryMat, keys, values);
|
|
1011
|
-
result = output[0];
|
|
1043
|
+
const attn = new FlashAttention(dim);
|
|
1044
|
+
result = attn.compute(query, keys, values);
|
|
1012
1045
|
break;
|
|
1013
1046
|
}
|
|
1014
1047
|
case 'hyperbolic': {
|
|
1015
1048
|
const curvature = parseFloat(options.curvature);
|
|
1016
|
-
const attn = new HyperbolicAttention(
|
|
1017
|
-
|
|
1018
|
-
const output = attn.forward(queryMat, keys, values);
|
|
1019
|
-
result = output[0];
|
|
1049
|
+
const attn = new HyperbolicAttention(dim, curvature);
|
|
1050
|
+
result = attn.compute(query, keys, values);
|
|
1020
1051
|
break;
|
|
1021
1052
|
}
|
|
1022
1053
|
case 'linear': {
|
|
1023
|
-
const attn = new LinearAttention(
|
|
1024
|
-
|
|
1025
|
-
const output = attn.forward(queryMat, keys, values);
|
|
1026
|
-
result = output[0];
|
|
1054
|
+
const attn = new LinearAttention(dim);
|
|
1055
|
+
result = attn.compute(query, keys, values);
|
|
1027
1056
|
break;
|
|
1028
1057
|
}
|
|
1029
1058
|
default:
|
|
@@ -1619,7 +1648,8 @@ program
|
|
|
1619
1648
|
console.log(chalk.white(' cargo add ruvector-raft # Raft consensus'));
|
|
1620
1649
|
console.log(chalk.white(' cargo add ruvector-replication # Data replication'));
|
|
1621
1650
|
console.log(chalk.white(' cargo add ruvector-tiny-dancer-core # AI routing'));
|
|
1622
|
-
console.log(chalk.white(' cargo add ruvector-router-core
|
|
1651
|
+
console.log(chalk.white(' cargo add ruvector-router-core # Semantic routing (Rust crate)'));
|
|
1652
|
+
console.log(chalk.white(' npm install @ruvector/router # Semantic routing (npm)'));
|
|
1623
1653
|
console.log('');
|
|
1624
1654
|
|
|
1625
1655
|
console.log(chalk.yellow('Platform-specific notes:'));
|
|
@@ -1737,7 +1767,7 @@ program
|
|
|
1737
1767
|
|
|
1738
1768
|
program
|
|
1739
1769
|
.command('router')
|
|
1740
|
-
.description('AI semantic router operations (requires ruvector
|
|
1770
|
+
.description('AI semantic router operations (requires @ruvector/router)')
|
|
1741
1771
|
.option('--route <text>', 'Route text to best matching intent')
|
|
1742
1772
|
.option('--intents <file>', 'Load intents from JSON file')
|
|
1743
1773
|
.option('--add-intent <name>', 'Add new intent')
|
|
@@ -1758,8 +1788,9 @@ program
|
|
|
1758
1788
|
console.log(chalk.gray(' - Vector-based similarity matching'));
|
|
1759
1789
|
console.log('');
|
|
1760
1790
|
console.log(chalk.cyan(' Status:'), chalk.yellow('Coming Soon'));
|
|
1761
|
-
console.log(chalk.gray(' The
|
|
1762
|
-
console.log(chalk.gray('
|
|
1791
|
+
console.log(chalk.gray(' The router subcommand integration is still in development.'));
|
|
1792
|
+
console.log(chalk.gray(' npm package: npm install @ruvector/router'));
|
|
1793
|
+
console.log(chalk.gray(' Rust crate: cargo add ruvector-router-core'));
|
|
1763
1794
|
console.log('');
|
|
1764
1795
|
console.log(chalk.cyan(' Usage (when available):'));
|
|
1765
1796
|
console.log(chalk.white(' npx ruvector router --route "What is the weather?"'));
|
|
@@ -2534,13 +2565,15 @@ program
|
|
|
2534
2565
|
const spinner = ora('Creating demo database...').start();
|
|
2535
2566
|
|
|
2536
2567
|
try {
|
|
2537
|
-
const db = new VectorDB({ dimensions: 4,
|
|
2568
|
+
const db = new VectorDB({ dimensions: 4, distanceMetric: 'cosine' });
|
|
2538
2569
|
|
|
2539
2570
|
spinner.text = 'Inserting vectors...';
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
db.insert('
|
|
2543
|
-
db.insert('
|
|
2571
|
+
// VectorDBWrapper.insert takes a single object: { id?, vector, metadata? }.
|
|
2572
|
+
// Wrap to Float32Array so the native binding sees the right typed array.
|
|
2573
|
+
await db.insert({ id: 'vec1', vector: new Float32Array([1.0, 0.0, 0.0, 0.0]), metadata: { label: 'x-axis' } });
|
|
2574
|
+
await db.insert({ id: 'vec2', vector: new Float32Array([0.0, 1.0, 0.0, 0.0]), metadata: { label: 'y-axis' } });
|
|
2575
|
+
await db.insert({ id: 'vec3', vector: new Float32Array([0.0, 0.0, 1.0, 0.0]), metadata: { label: 'z-axis' } });
|
|
2576
|
+
await db.insert({ id: 'vec4', vector: new Float32Array([0.7, 0.7, 0.0, 0.0]), metadata: { label: 'xy-diagonal' } });
|
|
2544
2577
|
|
|
2545
2578
|
spinner.succeed('Demo database created with 4 vectors');
|
|
2546
2579
|
|
|
@@ -2551,7 +2584,7 @@ program
|
|
|
2551
2584
|
console.log(chalk.gray(' vec4: [0.7,0.7,0,0] - xy-diagonal'));
|
|
2552
2585
|
|
|
2553
2586
|
console.log(chalk.cyan('\n Searching for nearest to [0.8, 0.6, 0, 0]:'));
|
|
2554
|
-
const results = db.search([0.8, 0.6, 0.0, 0.0], 3);
|
|
2587
|
+
const results = await db.search({ vector: new Float32Array([0.8, 0.6, 0.0, 0.0]), k: 3 });
|
|
2555
2588
|
results.forEach((r, i) => {
|
|
2556
2589
|
console.log(chalk.gray(` ${i + 1}. ${r.id} (score: ${r.score.toFixed(4)})`));
|
|
2557
2590
|
});
|
|
@@ -2577,20 +2610,26 @@ program
|
|
|
2577
2610
|
try {
|
|
2578
2611
|
console.log(chalk.cyan(' Running differentiable search with gradients...\n'));
|
|
2579
2612
|
|
|
2580
|
-
|
|
2613
|
+
// The native @ruvector/gnn binding expects Float32Array typed arrays.
|
|
2614
|
+
const queryVec = new Float32Array([1.0, 0.5, 0.3, 0.1]);
|
|
2581
2615
|
const dbVectors = [
|
|
2582
|
-
[1.0, 0.0, 0.0, 0.0],
|
|
2583
|
-
[0.0, 1.0, 0.0, 0.0],
|
|
2584
|
-
[0.5, 0.5, 0.5, 0.5],
|
|
2585
|
-
[0.9, 0.4, 0.2, 0.1]
|
|
2616
|
+
new Float32Array([1.0, 0.0, 0.0, 0.0]),
|
|
2617
|
+
new Float32Array([0.0, 1.0, 0.0, 0.0]),
|
|
2618
|
+
new Float32Array([0.5, 0.5, 0.5, 0.5]),
|
|
2619
|
+
new Float32Array([0.9, 0.4, 0.2, 0.1]),
|
|
2586
2620
|
];
|
|
2587
2621
|
|
|
2588
2622
|
const result = differentiableSearch(queryVec, dbVectors, 3, 10.0);
|
|
2589
2623
|
|
|
2590
|
-
|
|
2624
|
+
// The wrapper returns `{ indices, weights }`; older binding versions
|
|
2625
|
+
// exposed `attention_weights` instead.
|
|
2626
|
+
const weights = result.weights || result.attention_weights || [];
|
|
2627
|
+
|
|
2628
|
+
console.log(chalk.cyan(' Query:'), JSON.stringify(Array.from(queryVec)));
|
|
2591
2629
|
console.log(chalk.cyan(' Top 3 results:'));
|
|
2592
2630
|
result.indices.forEach((idx, i) => {
|
|
2593
|
-
|
|
2631
|
+
const w = weights[i] != null ? weights[i].toFixed(4) : 'n/a';
|
|
2632
|
+
console.log(chalk.gray(` ${i + 1}. Index ${idx} (attention: ${w})`));
|
|
2594
2633
|
});
|
|
2595
2634
|
|
|
2596
2635
|
console.log(chalk.cyan('\n Gradient flow enabled:'), chalk.green('Yes'));
|
|
@@ -2598,7 +2637,19 @@ program
|
|
|
2598
2637
|
|
|
2599
2638
|
console.log(chalk.green('\n GNN demo complete!'));
|
|
2600
2639
|
} catch (error) {
|
|
2601
|
-
|
|
2640
|
+
// `@ruvector/gnn@0.1.25`'s native binding has a regression where every
|
|
2641
|
+
// method throws `Given napi value is not an array`, regardless of the
|
|
2642
|
+
// input shape (verified with both Array<Float32Array> and number[][]).
|
|
2643
|
+
// Surface that explicitly so users don't think it's their CLI install.
|
|
2644
|
+
const msg = error && error.message ? error.message : String(error);
|
|
2645
|
+
if (msg.includes('not an array') || msg.includes('TypedArray')) {
|
|
2646
|
+
console.error(chalk.red(` GNN demo failed: ${msg}`));
|
|
2647
|
+
console.error(chalk.yellow('\n This looks like a regression in the @ruvector/gnn native binding,'));
|
|
2648
|
+
console.error(chalk.yellow(' not in the CLI. Tracking at:'));
|
|
2649
|
+
console.error(chalk.white(' https://github.com/ruvnet/ruvector/issues/402'));
|
|
2650
|
+
} else {
|
|
2651
|
+
console.error(chalk.red('GNN demo failed:', msg));
|
|
2652
|
+
}
|
|
2602
2653
|
}
|
|
2603
2654
|
}
|
|
2604
2655
|
|
|
@@ -2608,18 +2659,111 @@ program
|
|
|
2608
2659
|
let graphNode;
|
|
2609
2660
|
try {
|
|
2610
2661
|
graphNode = require('@ruvector/graph-node');
|
|
2611
|
-
console.log(chalk.green(' @ruvector/graph-node is available!'));
|
|
2612
|
-
console.log(chalk.gray(' Full graph demo coming soon.'));
|
|
2613
2662
|
} catch (e) {
|
|
2614
2663
|
console.log(chalk.yellow(' @ruvector/graph-node not installed.'));
|
|
2615
2664
|
console.log(chalk.white(' Install with: npm install @ruvector/graph-node'));
|
|
2665
|
+
console.log('');
|
|
2666
|
+
return;
|
|
2667
|
+
}
|
|
2668
|
+
|
|
2669
|
+
try {
|
|
2670
|
+
// The current binding exposes a `GraphDatabase` class (not Graph /
|
|
2671
|
+
// HyperGraph / RuVectorGraph) with createNode / createEdge / query.
|
|
2672
|
+
const GraphDatabase = graphNode.GraphDatabase;
|
|
2673
|
+
if (typeof GraphDatabase !== 'function') {
|
|
2674
|
+
console.log(chalk.yellow(' @ruvector/graph-node has no GraphDatabase constructor.'));
|
|
2675
|
+
console.log(chalk.gray(` Available exports: ${Object.keys(graphNode).join(', ')}`));
|
|
2676
|
+
return;
|
|
2677
|
+
}
|
|
2678
|
+
|
|
2679
|
+
const g = new GraphDatabase();
|
|
2680
|
+
console.log(chalk.green(' ✓ GraphDatabase instance created'));
|
|
2681
|
+
|
|
2682
|
+
// createNode / createEdge take a JsNode / JsEdge object (not positional
|
|
2683
|
+
// args) and are async — see @ruvector/graph-node index.d.ts.
|
|
2684
|
+
const aId = await g.createNode({
|
|
2685
|
+
id: 'alice',
|
|
2686
|
+
embedding: new Float32Array([1, 0, 0, 0]),
|
|
2687
|
+
properties: { name: 'Alice', label: 'Person' },
|
|
2688
|
+
});
|
|
2689
|
+
const bId = await g.createNode({
|
|
2690
|
+
id: 'bob',
|
|
2691
|
+
embedding: new Float32Array([0, 1, 0, 0]),
|
|
2692
|
+
properties: { name: 'Bob', label: 'Person' },
|
|
2693
|
+
});
|
|
2694
|
+
console.log(chalk.green(` ✓ Created nodes: Alice (${aId}), Bob (${bId})`));
|
|
2695
|
+
|
|
2696
|
+
const edgeId = await g.createEdge({
|
|
2697
|
+
from: 'alice',
|
|
2698
|
+
to: 'bob',
|
|
2699
|
+
description: 'KNOWS',
|
|
2700
|
+
embedding: new Float32Array([0.5, 0.5, 0, 0]),
|
|
2701
|
+
confidence: 0.95,
|
|
2702
|
+
});
|
|
2703
|
+
console.log(chalk.green(` ✓ Created edge Alice -[:KNOWS]-> Bob (${edgeId})`));
|
|
2704
|
+
|
|
2705
|
+
const stats = g.stats();
|
|
2706
|
+
console.log(chalk.gray(` Stats: ${typeof stats === 'string' ? stats : JSON.stringify(stats)}`));
|
|
2707
|
+
|
|
2708
|
+
console.log(chalk.green('\n Graph demo complete!'));
|
|
2709
|
+
} catch (error) {
|
|
2710
|
+
// The createNode/createEdge signatures vary across binding versions
|
|
2711
|
+
// (some take (label, propsJson), some take (label, propsObject)).
|
|
2712
|
+
// Print enough context that the user can adapt without guessing.
|
|
2713
|
+
console.error(chalk.red(` Graph demo failed: ${error.message}`));
|
|
2714
|
+
const G = graphNode && graphNode.GraphDatabase;
|
|
2715
|
+
if (G) {
|
|
2716
|
+
const methods = Object.getOwnPropertyNames(G.prototype || {}).filter((m) => m !== 'constructor');
|
|
2717
|
+
console.error(chalk.gray(` GraphDatabase prototype: ${methods.join(', ')}`));
|
|
2718
|
+
}
|
|
2616
2719
|
}
|
|
2617
2720
|
console.log('');
|
|
2618
2721
|
}
|
|
2619
2722
|
|
|
2620
2723
|
if (options.benchmark) {
|
|
2621
|
-
|
|
2622
|
-
console.log(chalk.
|
|
2724
|
+
requireRuvector();
|
|
2725
|
+
console.log(chalk.yellow(' Mini Benchmark Demo\n'));
|
|
2726
|
+
|
|
2727
|
+
try {
|
|
2728
|
+
// Note: ruvector-core-linux-x64-gnu@0.1.29 (and current sister binaries)
|
|
2729
|
+
// has a regression where the `dimensions` constructor arg is ignored
|
|
2730
|
+
// and inserts are pinned to dim=4. Tracking at issue #402. Keeping the
|
|
2731
|
+
// demo at dim=4 so it completes; once the binding is rebuilt from
|
|
2732
|
+
// current source, this can scale up.
|
|
2733
|
+
const dim = 4;
|
|
2734
|
+
const n = 1000;
|
|
2735
|
+
const k = 10;
|
|
2736
|
+
const db = new VectorDB({ dimensions: dim, distanceMetric: 'cosine' });
|
|
2737
|
+
|
|
2738
|
+
console.log(chalk.cyan(` Generating ${n} random ${dim}-dim vectors...`));
|
|
2739
|
+
const t0 = Date.now();
|
|
2740
|
+
const entries = [];
|
|
2741
|
+
for (let i = 0; i < n; i++) {
|
|
2742
|
+
const v = new Float32Array(dim);
|
|
2743
|
+
for (let j = 0; j < dim; j++) v[j] = Math.random();
|
|
2744
|
+
entries.push({ id: `v${i}`, vector: v });
|
|
2745
|
+
}
|
|
2746
|
+
const insertStart = Date.now();
|
|
2747
|
+
for (const entry of entries) await db.insert(entry);
|
|
2748
|
+
const insertMs = Date.now() - insertStart;
|
|
2749
|
+
|
|
2750
|
+
const queryVec = new Float32Array(dim);
|
|
2751
|
+
for (let j = 0; j < dim; j++) queryVec[j] = Math.random();
|
|
2752
|
+
|
|
2753
|
+
const searchStart = Date.now();
|
|
2754
|
+
const iters = 100;
|
|
2755
|
+
for (let i = 0; i < iters; i++) {
|
|
2756
|
+
await db.search({ vector: queryVec, k });
|
|
2757
|
+
}
|
|
2758
|
+
const searchMs = Date.now() - searchStart;
|
|
2759
|
+
|
|
2760
|
+
console.log(chalk.green(`\n ✓ Inserted ${n} vectors in ${insertMs}ms (${(insertMs / n).toFixed(2)}ms/vec)`));
|
|
2761
|
+
console.log(chalk.green(` ✓ ${iters}× top-${k} search in ${searchMs}ms (${(searchMs / iters).toFixed(2)}ms/query)`));
|
|
2762
|
+
console.log(chalk.gray(` Wall time: ${Date.now() - t0}ms`));
|
|
2763
|
+
console.log(chalk.gray(' For deeper benchmarks: npx ruvector benchmark'));
|
|
2764
|
+
} catch (error) {
|
|
2765
|
+
console.error(chalk.red(` Benchmark demo failed: ${error.message}`));
|
|
2766
|
+
}
|
|
2623
2767
|
console.log('');
|
|
2624
2768
|
}
|
|
2625
2769
|
});
|
|
@@ -9119,10 +9263,14 @@ const optimizeCmd = program.command('optimize')
|
|
|
9119
9263
|
.action(async (opts) => {
|
|
9120
9264
|
let optimizerMod;
|
|
9121
9265
|
try {
|
|
9266
|
+
// Resolve via package.json so it works whether the optimizer ships under
|
|
9267
|
+
// src/optimizer/ or dist/optimizer/.
|
|
9122
9268
|
optimizerMod = require('../src/optimizer/index.js');
|
|
9123
9269
|
} catch (e) {
|
|
9124
|
-
console.error(chalk.
|
|
9125
|
-
console.error(chalk.
|
|
9270
|
+
console.error(chalk.yellow('\n ruvector optimize: not yet shipped in this release.\n'));
|
|
9271
|
+
console.error(chalk.gray(' The optimizer module (profiles, settings generation) is in development'));
|
|
9272
|
+
console.error(chalk.gray(' and will land in a future release. Track progress at:'));
|
|
9273
|
+
console.error(chalk.white(' https://github.com/ruvnet/ruvector/issues/401\n'));
|
|
9126
9274
|
process.exit(1);
|
|
9127
9275
|
}
|
|
9128
9276
|
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Complexity Analysis Module - Consolidated code complexity metrics
|
|
3
|
+
*
|
|
4
|
+
* Single source of truth for cyclomatic complexity and code metrics.
|
|
5
|
+
* Used by native-worker.ts and parallel-workers.ts
|
|
6
|
+
*/
|
|
7
|
+
export interface ComplexityResult {
|
|
8
|
+
file: string;
|
|
9
|
+
lines: number;
|
|
10
|
+
nonEmptyLines: number;
|
|
11
|
+
cyclomaticComplexity: number;
|
|
12
|
+
functions: number;
|
|
13
|
+
avgFunctionSize: number;
|
|
14
|
+
maxFunctionComplexity?: number;
|
|
15
|
+
}
|
|
16
|
+
export interface ComplexityThresholds {
|
|
17
|
+
complexity: number;
|
|
18
|
+
functions: number;
|
|
19
|
+
lines: number;
|
|
20
|
+
avgSize: number;
|
|
21
|
+
}
|
|
22
|
+
export declare const DEFAULT_THRESHOLDS: ComplexityThresholds;
|
|
23
|
+
/**
|
|
24
|
+
* Analyze complexity of a single file
|
|
25
|
+
*/
|
|
26
|
+
export declare function analyzeFile(filePath: string, content?: string): ComplexityResult;
|
|
27
|
+
/**
|
|
28
|
+
* Analyze complexity of multiple files
|
|
29
|
+
*/
|
|
30
|
+
export declare function analyzeFiles(files: string[], maxFiles?: number): ComplexityResult[];
|
|
31
|
+
/**
|
|
32
|
+
* Check if complexity exceeds thresholds
|
|
33
|
+
*/
|
|
34
|
+
export declare function exceedsThresholds(result: ComplexityResult, thresholds?: ComplexityThresholds): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Get complexity rating
|
|
37
|
+
*/
|
|
38
|
+
export declare function getComplexityRating(complexity: number): 'low' | 'medium' | 'high' | 'critical';
|
|
39
|
+
/**
|
|
40
|
+
* Filter files exceeding thresholds
|
|
41
|
+
*/
|
|
42
|
+
export declare function filterComplex(results: ComplexityResult[], thresholds?: ComplexityThresholds): ComplexityResult[];
|
|
43
|
+
declare const _default: {
|
|
44
|
+
DEFAULT_THRESHOLDS: ComplexityThresholds;
|
|
45
|
+
analyzeFile: typeof analyzeFile;
|
|
46
|
+
analyzeFiles: typeof analyzeFiles;
|
|
47
|
+
exceedsThresholds: typeof exceedsThresholds;
|
|
48
|
+
getComplexityRating: typeof getComplexityRating;
|
|
49
|
+
filterComplex: typeof filterComplex;
|
|
50
|
+
};
|
|
51
|
+
export default _default;
|
|
52
|
+
//# sourceMappingURL=complexity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"complexity.d.ts","sourceRoot":"","sources":["../../src/analysis/complexity.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,eAAO,MAAM,kBAAkB,EAAE,oBAKhC,CAAC;AAEF;;GAEG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAsDhF;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,QAAQ,GAAE,MAAY,GAAG,gBAAgB,EAAE,CAExF;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,gBAAgB,EACxB,UAAU,GAAE,oBAAyC,GACpD,OAAO,CAOT;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,UAAU,CAK9F;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,gBAAgB,EAAE,EAC3B,UAAU,GAAE,oBAAyC,GACpD,gBAAgB,EAAE,CAEpB;;;;;;;;;AAED,wBAOE"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Complexity Analysis Module - Consolidated code complexity metrics
|
|
4
|
+
*
|
|
5
|
+
* Single source of truth for cyclomatic complexity and code metrics.
|
|
6
|
+
* Used by native-worker.ts and parallel-workers.ts
|
|
7
|
+
*/
|
|
8
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
9
|
+
if (k2 === undefined) k2 = k;
|
|
10
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
11
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
12
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
13
|
+
}
|
|
14
|
+
Object.defineProperty(o, k2, desc);
|
|
15
|
+
}) : (function(o, m, k, k2) {
|
|
16
|
+
if (k2 === undefined) k2 = k;
|
|
17
|
+
o[k2] = m[k];
|
|
18
|
+
}));
|
|
19
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
20
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
21
|
+
}) : function(o, v) {
|
|
22
|
+
o["default"] = v;
|
|
23
|
+
});
|
|
24
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
25
|
+
var ownKeys = function(o) {
|
|
26
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
27
|
+
var ar = [];
|
|
28
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
29
|
+
return ar;
|
|
30
|
+
};
|
|
31
|
+
return ownKeys(o);
|
|
32
|
+
};
|
|
33
|
+
return function (mod) {
|
|
34
|
+
if (mod && mod.__esModule) return mod;
|
|
35
|
+
var result = {};
|
|
36
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
37
|
+
__setModuleDefault(result, mod);
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
40
|
+
})();
|
|
41
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
+
exports.DEFAULT_THRESHOLDS = void 0;
|
|
43
|
+
exports.analyzeFile = analyzeFile;
|
|
44
|
+
exports.analyzeFiles = analyzeFiles;
|
|
45
|
+
exports.exceedsThresholds = exceedsThresholds;
|
|
46
|
+
exports.getComplexityRating = getComplexityRating;
|
|
47
|
+
exports.filterComplex = filterComplex;
|
|
48
|
+
const fs = __importStar(require("fs"));
|
|
49
|
+
exports.DEFAULT_THRESHOLDS = {
|
|
50
|
+
complexity: 10,
|
|
51
|
+
functions: 30,
|
|
52
|
+
lines: 500,
|
|
53
|
+
avgSize: 50,
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Analyze complexity of a single file
|
|
57
|
+
*/
|
|
58
|
+
function analyzeFile(filePath, content) {
|
|
59
|
+
try {
|
|
60
|
+
const fileContent = content ?? (fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf-8') : '');
|
|
61
|
+
if (!fileContent) {
|
|
62
|
+
return { file: filePath, lines: 0, nonEmptyLines: 0, cyclomaticComplexity: 1, functions: 0, avgFunctionSize: 0 };
|
|
63
|
+
}
|
|
64
|
+
const lines = fileContent.split('\n');
|
|
65
|
+
const nonEmptyLines = lines.filter(l => l.trim().length > 0).length;
|
|
66
|
+
// Count branching statements for cyclomatic complexity
|
|
67
|
+
const branches = (fileContent.match(/\bif\b/g)?.length || 0) +
|
|
68
|
+
(fileContent.match(/\belse\b/g)?.length || 0) +
|
|
69
|
+
(fileContent.match(/\bfor\b/g)?.length || 0) +
|
|
70
|
+
(fileContent.match(/\bwhile\b/g)?.length || 0) +
|
|
71
|
+
(fileContent.match(/\bswitch\b/g)?.length || 0) +
|
|
72
|
+
(fileContent.match(/\bcase\b/g)?.length || 0) +
|
|
73
|
+
(fileContent.match(/\bcatch\b/g)?.length || 0) +
|
|
74
|
+
(fileContent.match(/\?\?/g)?.length || 0) +
|
|
75
|
+
(fileContent.match(/&&/g)?.length || 0) +
|
|
76
|
+
(fileContent.match(/\|\|/g)?.length || 0) +
|
|
77
|
+
(fileContent.match(/\?[^:]/g)?.length || 0); // Ternary
|
|
78
|
+
const cyclomaticComplexity = branches + 1;
|
|
79
|
+
// Count functions
|
|
80
|
+
const functionPatterns = [
|
|
81
|
+
/function\s+\w+/g,
|
|
82
|
+
/\w+\s*=\s*(?:async\s*)?\(/g,
|
|
83
|
+
/\w+\s*:\s*(?:async\s*)?\(/g,
|
|
84
|
+
/(?:async\s+)?(?:public|private|protected)?\s+\w+\s*\([^)]*\)\s*[:{]/g,
|
|
85
|
+
];
|
|
86
|
+
let functions = 0;
|
|
87
|
+
for (const pattern of functionPatterns) {
|
|
88
|
+
functions += (fileContent.match(pattern) || []).length;
|
|
89
|
+
}
|
|
90
|
+
// Deduplicate by rough estimate
|
|
91
|
+
functions = Math.ceil(functions / 2);
|
|
92
|
+
const avgFunctionSize = functions > 0 ? Math.round(nonEmptyLines / functions) : nonEmptyLines;
|
|
93
|
+
return {
|
|
94
|
+
file: filePath,
|
|
95
|
+
lines: lines.length,
|
|
96
|
+
nonEmptyLines,
|
|
97
|
+
cyclomaticComplexity,
|
|
98
|
+
functions,
|
|
99
|
+
avgFunctionSize,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return { file: filePath, lines: 0, nonEmptyLines: 0, cyclomaticComplexity: 1, functions: 0, avgFunctionSize: 0 };
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Analyze complexity of multiple files
|
|
108
|
+
*/
|
|
109
|
+
function analyzeFiles(files, maxFiles = 100) {
|
|
110
|
+
return files.slice(0, maxFiles).map(f => analyzeFile(f));
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Check if complexity exceeds thresholds
|
|
114
|
+
*/
|
|
115
|
+
function exceedsThresholds(result, thresholds = exports.DEFAULT_THRESHOLDS) {
|
|
116
|
+
return (result.cyclomaticComplexity > thresholds.complexity ||
|
|
117
|
+
result.functions > thresholds.functions ||
|
|
118
|
+
result.lines > thresholds.lines ||
|
|
119
|
+
result.avgFunctionSize > thresholds.avgSize);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Get complexity rating
|
|
123
|
+
*/
|
|
124
|
+
function getComplexityRating(complexity) {
|
|
125
|
+
if (complexity <= 5)
|
|
126
|
+
return 'low';
|
|
127
|
+
if (complexity <= 10)
|
|
128
|
+
return 'medium';
|
|
129
|
+
if (complexity <= 20)
|
|
130
|
+
return 'high';
|
|
131
|
+
return 'critical';
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Filter files exceeding thresholds
|
|
135
|
+
*/
|
|
136
|
+
function filterComplex(results, thresholds = exports.DEFAULT_THRESHOLDS) {
|
|
137
|
+
return results.filter(r => exceedsThresholds(r, thresholds));
|
|
138
|
+
}
|
|
139
|
+
exports.default = {
|
|
140
|
+
DEFAULT_THRESHOLDS: exports.DEFAULT_THRESHOLDS,
|
|
141
|
+
analyzeFile,
|
|
142
|
+
analyzeFiles,
|
|
143
|
+
exceedsThresholds,
|
|
144
|
+
getComplexityRating,
|
|
145
|
+
filterComplex,
|
|
146
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Analysis Module - Consolidated code analysis utilities
|
|
3
|
+
*
|
|
4
|
+
* Single source of truth for:
|
|
5
|
+
* - Security scanning
|
|
6
|
+
* - Complexity analysis
|
|
7
|
+
* - Pattern extraction
|
|
8
|
+
*/
|
|
9
|
+
export * from './security';
|
|
10
|
+
export * from './complexity';
|
|
11
|
+
export * from './patterns';
|
|
12
|
+
export { default as security } from './security';
|
|
13
|
+
export { default as complexity } from './complexity';
|
|
14
|
+
export { default as patterns } from './patterns';
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|