@sparkleideas/plugins 3.0.0-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +401 -0
- package/__tests__/collection-manager.test.ts +332 -0
- package/__tests__/dependency-graph.test.ts +434 -0
- package/__tests__/enhanced-plugin-registry.test.ts +488 -0
- package/__tests__/plugin-registry.test.ts +368 -0
- package/__tests__/ruvector-bridge.test.ts +2429 -0
- package/__tests__/ruvector-integration.test.ts +1602 -0
- package/__tests__/ruvector-migrations.test.ts +1099 -0
- package/__tests__/ruvector-quantization.test.ts +846 -0
- package/__tests__/ruvector-streaming.test.ts +1088 -0
- package/__tests__/sdk.test.ts +325 -0
- package/__tests__/security.test.ts +348 -0
- package/__tests__/utils/ruvector-test-utils.ts +860 -0
- package/examples/plugin-creator/index.ts +636 -0
- package/examples/plugin-creator/plugin-creator.test.ts +312 -0
- package/examples/ruvector/README.md +288 -0
- package/examples/ruvector/attention-patterns.ts +394 -0
- package/examples/ruvector/basic-usage.ts +288 -0
- package/examples/ruvector/docker-compose.yml +75 -0
- package/examples/ruvector/gnn-analysis.ts +501 -0
- package/examples/ruvector/hyperbolic-hierarchies.ts +557 -0
- package/examples/ruvector/init-db.sql +119 -0
- package/examples/ruvector/quantization.ts +680 -0
- package/examples/ruvector/self-learning.ts +447 -0
- package/examples/ruvector/semantic-search.ts +576 -0
- package/examples/ruvector/streaming-large-data.ts +507 -0
- package/examples/ruvector/transactions.ts +594 -0
- package/examples/ruvector-plugins/hook-pattern-library.ts +486 -0
- package/examples/ruvector-plugins/index.ts +79 -0
- package/examples/ruvector-plugins/intent-router.ts +354 -0
- package/examples/ruvector-plugins/mcp-tool-optimizer.ts +424 -0
- package/examples/ruvector-plugins/reasoning-bank.ts +657 -0
- package/examples/ruvector-plugins/ruvector-plugins.test.ts +518 -0
- package/examples/ruvector-plugins/semantic-code-search.ts +498 -0
- package/examples/ruvector-plugins/shared/index.ts +20 -0
- package/examples/ruvector-plugins/shared/vector-utils.ts +257 -0
- package/examples/ruvector-plugins/sona-learning.ts +445 -0
- package/package.json +97 -0
- package/src/collections/collection-manager.ts +661 -0
- package/src/collections/index.ts +56 -0
- package/src/collections/official/index.ts +1040 -0
- package/src/core/base-plugin.ts +416 -0
- package/src/core/plugin-interface.ts +215 -0
- package/src/hooks/index.ts +685 -0
- package/src/index.ts +378 -0
- package/src/integrations/agentic-flow.ts +743 -0
- package/src/integrations/index.ts +88 -0
- package/src/integrations/ruvector/ARCHITECTURE.md +1245 -0
- package/src/integrations/ruvector/attention-advanced.ts +1040 -0
- package/src/integrations/ruvector/attention-executor.ts +782 -0
- package/src/integrations/ruvector/attention-mechanisms.ts +757 -0
- package/src/integrations/ruvector/attention.ts +1063 -0
- package/src/integrations/ruvector/gnn.ts +3050 -0
- package/src/integrations/ruvector/hyperbolic.ts +1948 -0
- package/src/integrations/ruvector/index.ts +394 -0
- package/src/integrations/ruvector/migrations/001_create_extension.sql +135 -0
- package/src/integrations/ruvector/migrations/002_create_vector_tables.sql +259 -0
- package/src/integrations/ruvector/migrations/003_create_indices.sql +328 -0
- package/src/integrations/ruvector/migrations/004_create_functions.sql +598 -0
- package/src/integrations/ruvector/migrations/005_create_attention_functions.sql +654 -0
- package/src/integrations/ruvector/migrations/006_create_gnn_functions.sql +728 -0
- package/src/integrations/ruvector/migrations/007_create_hyperbolic_functions.sql +762 -0
- package/src/integrations/ruvector/migrations/index.ts +35 -0
- package/src/integrations/ruvector/migrations/migrations.ts +647 -0
- package/src/integrations/ruvector/quantization.ts +2036 -0
- package/src/integrations/ruvector/ruvector-bridge.ts +2000 -0
- package/src/integrations/ruvector/self-learning.ts +2376 -0
- package/src/integrations/ruvector/streaming.ts +1737 -0
- package/src/integrations/ruvector/types.ts +1945 -0
- package/src/providers/index.ts +643 -0
- package/src/registry/dependency-graph.ts +568 -0
- package/src/registry/enhanced-plugin-registry.ts +994 -0
- package/src/registry/plugin-registry.ts +604 -0
- package/src/sdk/index.ts +563 -0
- package/src/security/index.ts +594 -0
- package/src/types/index.ts +446 -0
- package/src/workers/index.ts +700 -0
- package/tmp.json +0 -0
- package/tsconfig.json +25 -0
- package/vitest.config.ts +23 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# RuVector PostgreSQL Bridge - Local Development Setup
|
|
2
|
+
#
|
|
3
|
+
# This docker-compose file provides a complete local development environment
|
|
4
|
+
# for running the RuVector PostgreSQL Bridge examples.
|
|
5
|
+
#
|
|
6
|
+
# Usage:
|
|
7
|
+
# docker compose up -d # Start services
|
|
8
|
+
# docker compose down # Stop services
|
|
9
|
+
# docker compose logs -f # View logs
|
|
10
|
+
#
|
|
11
|
+
# Services:
|
|
12
|
+
# - postgres: PostgreSQL 16 with pgvector extension
|
|
13
|
+
# - adminer: Web-based database management UI
|
|
14
|
+
#
|
|
15
|
+
# Access:
|
|
16
|
+
# - PostgreSQL: localhost:5432
|
|
17
|
+
# - Adminer UI: http://localhost:8080
|
|
18
|
+
|
|
19
|
+
services:
|
|
20
|
+
# PostgreSQL with pgvector extension
|
|
21
|
+
postgres:
|
|
22
|
+
image: pgvector/pgvector:pg16
|
|
23
|
+
container_name: ruvector-postgres
|
|
24
|
+
restart: unless-stopped
|
|
25
|
+
environment:
|
|
26
|
+
POSTGRES_DB: vectors
|
|
27
|
+
POSTGRES_USER: postgres
|
|
28
|
+
POSTGRES_PASSWORD: postgres
|
|
29
|
+
# Performance tuning for vector workloads
|
|
30
|
+
POSTGRES_INITDB_ARGS: "--encoding=UTF8"
|
|
31
|
+
ports:
|
|
32
|
+
- "5432:5432"
|
|
33
|
+
volumes:
|
|
34
|
+
- pgdata:/var/lib/postgresql/data
|
|
35
|
+
- ./init-db.sql:/docker-entrypoint-initdb.d/init-db.sql:ro
|
|
36
|
+
healthcheck:
|
|
37
|
+
test: ["CMD-SHELL", "pg_isready -U postgres -d vectors"]
|
|
38
|
+
interval: 10s
|
|
39
|
+
timeout: 5s
|
|
40
|
+
retries: 5
|
|
41
|
+
# PostgreSQL configuration for vector workloads
|
|
42
|
+
command: >
|
|
43
|
+
postgres
|
|
44
|
+
-c shared_buffers=256MB
|
|
45
|
+
-c effective_cache_size=768MB
|
|
46
|
+
-c maintenance_work_mem=128MB
|
|
47
|
+
-c work_mem=16MB
|
|
48
|
+
-c max_parallel_workers_per_gather=2
|
|
49
|
+
-c max_parallel_workers=4
|
|
50
|
+
-c max_parallel_maintenance_workers=2
|
|
51
|
+
-c random_page_cost=1.1
|
|
52
|
+
-c effective_io_concurrency=200
|
|
53
|
+
-c max_connections=100
|
|
54
|
+
|
|
55
|
+
# Database management UI (optional)
|
|
56
|
+
adminer:
|
|
57
|
+
image: adminer:latest
|
|
58
|
+
container_name: ruvector-adminer
|
|
59
|
+
restart: unless-stopped
|
|
60
|
+
ports:
|
|
61
|
+
- "8080:8080"
|
|
62
|
+
environment:
|
|
63
|
+
ADMINER_DEFAULT_SERVER: postgres
|
|
64
|
+
ADMINER_DESIGN: nette
|
|
65
|
+
depends_on:
|
|
66
|
+
postgres:
|
|
67
|
+
condition: service_healthy
|
|
68
|
+
|
|
69
|
+
volumes:
|
|
70
|
+
pgdata:
|
|
71
|
+
driver: local
|
|
72
|
+
|
|
73
|
+
networks:
|
|
74
|
+
default:
|
|
75
|
+
name: ruvector-network
|
|
@@ -0,0 +1,501 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RuVector PostgreSQL Bridge - Graph Neural Network Analysis Example
|
|
3
|
+
*
|
|
4
|
+
* This example demonstrates:
|
|
5
|
+
* - Building a code dependency graph
|
|
6
|
+
* - Running GCN (Graph Convolutional Network) layers
|
|
7
|
+
* - Finding similar code by structural patterns
|
|
8
|
+
* - Graph-based code analysis
|
|
9
|
+
*
|
|
10
|
+
* Run with: npx ts-node examples/ruvector/gnn-analysis.ts
|
|
11
|
+
*
|
|
12
|
+
* @module @sparkleideas/plugins/examples/ruvector/gnn-analysis
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import {
|
|
16
|
+
createRuVectorBridge,
|
|
17
|
+
type RuVectorBridge,
|
|
18
|
+
} from '../../src/integrations/ruvector/index.js';
|
|
19
|
+
|
|
20
|
+
import {
|
|
21
|
+
GCNLayer,
|
|
22
|
+
GATLayer,
|
|
23
|
+
GraphSAGELayer,
|
|
24
|
+
type GNNConfig,
|
|
25
|
+
type GraphData,
|
|
26
|
+
type AdjacencyMatrix,
|
|
27
|
+
} from '../../src/integrations/ruvector/gnn.js';
|
|
28
|
+
|
|
29
|
+
// ============================================================================
|
|
30
|
+
// Configuration
|
|
31
|
+
// ============================================================================
|
|
32
|
+
|
|
33
|
+
const config = {
|
|
34
|
+
connection: {
|
|
35
|
+
host: process.env.POSTGRES_HOST || 'localhost',
|
|
36
|
+
port: parseInt(process.env.POSTGRES_PORT || '5432', 10),
|
|
37
|
+
database: process.env.POSTGRES_DB || 'vectors',
|
|
38
|
+
user: process.env.POSTGRES_USER || 'postgres',
|
|
39
|
+
password: process.env.POSTGRES_PASSWORD || 'postgres',
|
|
40
|
+
},
|
|
41
|
+
inputDim: 64,
|
|
42
|
+
hiddenDim: 32,
|
|
43
|
+
outputDim: 16,
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// ============================================================================
|
|
47
|
+
// Code Dependency Graph
|
|
48
|
+
// ============================================================================
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Represents a code module/file in the dependency graph.
|
|
52
|
+
*/
|
|
53
|
+
interface CodeModule {
|
|
54
|
+
id: string;
|
|
55
|
+
name: string;
|
|
56
|
+
type: 'service' | 'controller' | 'middleware' | 'util' | 'model' | 'test';
|
|
57
|
+
linesOfCode: number;
|
|
58
|
+
complexity: number;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Represents a dependency edge between modules.
|
|
63
|
+
*/
|
|
64
|
+
interface Dependency {
|
|
65
|
+
source: string;
|
|
66
|
+
target: string;
|
|
67
|
+
type: 'import' | 'extends' | 'implements' | 'calls';
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Sample codebase structure for demonstration.
|
|
72
|
+
*/
|
|
73
|
+
const codebase: {
|
|
74
|
+
modules: CodeModule[];
|
|
75
|
+
dependencies: Dependency[];
|
|
76
|
+
} = {
|
|
77
|
+
modules: [
|
|
78
|
+
{ id: 'auth-service', name: 'AuthService', type: 'service', linesOfCode: 250, complexity: 15 },
|
|
79
|
+
{ id: 'user-service', name: 'UserService', type: 'service', linesOfCode: 180, complexity: 10 },
|
|
80
|
+
{ id: 'user-controller', name: 'UserController', type: 'controller', linesOfCode: 120, complexity: 8 },
|
|
81
|
+
{ id: 'auth-controller', name: 'AuthController', type: 'controller', linesOfCode: 100, complexity: 7 },
|
|
82
|
+
{ id: 'auth-middleware', name: 'AuthMiddleware', type: 'middleware', linesOfCode: 50, complexity: 4 },
|
|
83
|
+
{ id: 'logger', name: 'Logger', type: 'util', linesOfCode: 80, complexity: 3 },
|
|
84
|
+
{ id: 'user-model', name: 'UserModel', type: 'model', linesOfCode: 60, complexity: 2 },
|
|
85
|
+
{ id: 'db-client', name: 'DatabaseClient', type: 'util', linesOfCode: 150, complexity: 12 },
|
|
86
|
+
{ id: 'validator', name: 'Validator', type: 'util', linesOfCode: 100, complexity: 6 },
|
|
87
|
+
{ id: 'auth-test', name: 'AuthServiceTest', type: 'test', linesOfCode: 200, complexity: 5 },
|
|
88
|
+
{ id: 'user-test', name: 'UserServiceTest', type: 'test', linesOfCode: 150, complexity: 4 },
|
|
89
|
+
],
|
|
90
|
+
dependencies: [
|
|
91
|
+
// AuthService dependencies
|
|
92
|
+
{ source: 'auth-service', target: 'user-model', type: 'import' },
|
|
93
|
+
{ source: 'auth-service', target: 'db-client', type: 'import' },
|
|
94
|
+
{ source: 'auth-service', target: 'logger', type: 'import' },
|
|
95
|
+
{ source: 'auth-service', target: 'validator', type: 'import' },
|
|
96
|
+
|
|
97
|
+
// UserService dependencies
|
|
98
|
+
{ source: 'user-service', target: 'user-model', type: 'import' },
|
|
99
|
+
{ source: 'user-service', target: 'db-client', type: 'import' },
|
|
100
|
+
{ source: 'user-service', target: 'logger', type: 'import' },
|
|
101
|
+
|
|
102
|
+
// Controller dependencies
|
|
103
|
+
{ source: 'user-controller', target: 'user-service', type: 'import' },
|
|
104
|
+
{ source: 'user-controller', target: 'auth-middleware', type: 'import' },
|
|
105
|
+
{ source: 'auth-controller', target: 'auth-service', type: 'import' },
|
|
106
|
+
{ source: 'auth-controller', target: 'validator', type: 'import' },
|
|
107
|
+
|
|
108
|
+
// Middleware dependencies
|
|
109
|
+
{ source: 'auth-middleware', target: 'auth-service', type: 'import' },
|
|
110
|
+
{ source: 'auth-middleware', target: 'logger', type: 'import' },
|
|
111
|
+
|
|
112
|
+
// Test dependencies
|
|
113
|
+
{ source: 'auth-test', target: 'auth-service', type: 'import' },
|
|
114
|
+
{ source: 'user-test', target: 'user-service', type: 'import' },
|
|
115
|
+
],
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
// ============================================================================
|
|
119
|
+
// Graph Utilities
|
|
120
|
+
// ============================================================================
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Build adjacency matrix from dependency list.
|
|
124
|
+
*/
|
|
125
|
+
function buildAdjacencyMatrix(
|
|
126
|
+
modules: CodeModule[],
|
|
127
|
+
dependencies: Dependency[]
|
|
128
|
+
): AdjacencyMatrix {
|
|
129
|
+
const n = modules.length;
|
|
130
|
+
const idToIndex = new Map(modules.map((m, i) => [m.id, i]));
|
|
131
|
+
|
|
132
|
+
// Initialize with self-loops (identity)
|
|
133
|
+
const matrix: number[][] = Array.from({ length: n }, (_, i) =>
|
|
134
|
+
Array.from({ length: n }, (_, j) => (i === j ? 1 : 0))
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
// Add edges
|
|
138
|
+
for (const dep of dependencies) {
|
|
139
|
+
const sourceIdx = idToIndex.get(dep.source);
|
|
140
|
+
const targetIdx = idToIndex.get(dep.target);
|
|
141
|
+
|
|
142
|
+
if (sourceIdx !== undefined && targetIdx !== undefined) {
|
|
143
|
+
matrix[sourceIdx][targetIdx] = 1;
|
|
144
|
+
// Uncomment for undirected graph:
|
|
145
|
+
// matrix[targetIdx][sourceIdx] = 1;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Normalize (symmetric normalization: D^-0.5 * A * D^-0.5)
|
|
150
|
+
const degrees = matrix.map(row => row.reduce((s, v) => s + v, 0));
|
|
151
|
+
const normalized: number[][] = matrix.map((row, i) =>
|
|
152
|
+
row.map((val, j) => {
|
|
153
|
+
const di = degrees[i];
|
|
154
|
+
const dj = degrees[j];
|
|
155
|
+
if (di === 0 || dj === 0) return 0;
|
|
156
|
+
return val / Math.sqrt(di * dj);
|
|
157
|
+
})
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
return { data: normalized, numNodes: n };
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Create node feature vectors from module properties.
|
|
165
|
+
*/
|
|
166
|
+
function createNodeFeatures(modules: CodeModule[], dim: number): number[][] {
|
|
167
|
+
const typeEncoding: Record<string, number[]> = {
|
|
168
|
+
service: [1, 0, 0, 0, 0, 0],
|
|
169
|
+
controller: [0, 1, 0, 0, 0, 0],
|
|
170
|
+
middleware: [0, 0, 1, 0, 0, 0],
|
|
171
|
+
util: [0, 0, 0, 1, 0, 0],
|
|
172
|
+
model: [0, 0, 0, 0, 1, 0],
|
|
173
|
+
test: [0, 0, 0, 0, 0, 1],
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
return modules.map(module => {
|
|
177
|
+
const features = new Array(dim).fill(0);
|
|
178
|
+
|
|
179
|
+
// Type encoding (first 6 dimensions)
|
|
180
|
+
const typeVec = typeEncoding[module.type] || [0, 0, 0, 0, 0, 0];
|
|
181
|
+
typeVec.forEach((v, i) => (features[i] = v));
|
|
182
|
+
|
|
183
|
+
// Normalized lines of code (dimension 6)
|
|
184
|
+
features[6] = module.linesOfCode / 300;
|
|
185
|
+
|
|
186
|
+
// Normalized complexity (dimension 7)
|
|
187
|
+
features[7] = module.complexity / 20;
|
|
188
|
+
|
|
189
|
+
// Add some random features for demonstration
|
|
190
|
+
for (let i = 8; i < dim; i++) {
|
|
191
|
+
features[i] = Math.random() * 0.1;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return features;
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Compute cosine similarity between two vectors.
|
|
200
|
+
*/
|
|
201
|
+
function cosineSimilarity(a: number[], b: number[]): number {
|
|
202
|
+
const dot = a.reduce((sum, val, i) => sum + val * b[i], 0);
|
|
203
|
+
const magA = Math.sqrt(a.reduce((s, v) => s + v * v, 0));
|
|
204
|
+
const magB = Math.sqrt(b.reduce((s, v) => s + v * v, 0));
|
|
205
|
+
return dot / (magA * magB);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// ============================================================================
|
|
209
|
+
// Main Example
|
|
210
|
+
// ============================================================================
|
|
211
|
+
|
|
212
|
+
async function main(): Promise<void> {
|
|
213
|
+
console.log('RuVector PostgreSQL Bridge - Graph Neural Network Analysis Example');
|
|
214
|
+
console.log('===================================================================\n');
|
|
215
|
+
|
|
216
|
+
const bridge: RuVectorBridge = createRuVectorBridge({
|
|
217
|
+
connectionString: `postgresql://${config.connection.user}:${config.connection.password}@${config.connection.host}:${config.connection.port}/${config.connection.database}`,
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
try {
|
|
221
|
+
await bridge.connect();
|
|
222
|
+
console.log('Connected to PostgreSQL\n');
|
|
223
|
+
|
|
224
|
+
// ========================================================================
|
|
225
|
+
// 1. Build Dependency Graph
|
|
226
|
+
// ========================================================================
|
|
227
|
+
console.log('1. Building Code Dependency Graph');
|
|
228
|
+
console.log(' ' + '-'.repeat(50));
|
|
229
|
+
|
|
230
|
+
const adjacency = buildAdjacencyMatrix(codebase.modules, codebase.dependencies);
|
|
231
|
+
const nodeFeatures = createNodeFeatures(codebase.modules, config.inputDim);
|
|
232
|
+
|
|
233
|
+
console.log(` Nodes: ${codebase.modules.length}`);
|
|
234
|
+
console.log(` Edges: ${codebase.dependencies.length}`);
|
|
235
|
+
console.log(` Feature dimension: ${config.inputDim}`);
|
|
236
|
+
|
|
237
|
+
// Print adjacency matrix (dependency connections)
|
|
238
|
+
console.log('\n Dependency Matrix (1 = depends on):');
|
|
239
|
+
console.log(' ' + ' '.repeat(18) + codebase.modules.map(m => m.name.slice(0, 4)).join(' '));
|
|
240
|
+
codebase.modules.forEach((module, i) => {
|
|
241
|
+
const row = adjacency.data[i].map(v => (v > 0 ? '1' : '.'));
|
|
242
|
+
console.log(` ${module.name.padEnd(18)} ${row.join(' ')}`);
|
|
243
|
+
});
|
|
244
|
+
console.log();
|
|
245
|
+
|
|
246
|
+
// ========================================================================
|
|
247
|
+
// 2. GCN Layer - Learn Structural Embeddings
|
|
248
|
+
// ========================================================================
|
|
249
|
+
console.log('2. Graph Convolutional Network (GCN)');
|
|
250
|
+
console.log(' ' + '-'.repeat(50));
|
|
251
|
+
console.log(' Learning node embeddings that capture graph structure\n');
|
|
252
|
+
|
|
253
|
+
const gcnConfig: GNNConfig = {
|
|
254
|
+
inputDim: config.inputDim,
|
|
255
|
+
hiddenDim: config.hiddenDim,
|
|
256
|
+
outputDim: config.outputDim,
|
|
257
|
+
numLayers: 2,
|
|
258
|
+
dropout: 0.1,
|
|
259
|
+
activation: 'relu',
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
const gcnLayer = new GCNLayer(gcnConfig);
|
|
263
|
+
|
|
264
|
+
// Forward pass through GCN
|
|
265
|
+
console.log(' Running GCN forward pass...');
|
|
266
|
+
const startGCN = performance.now();
|
|
267
|
+
const gcnEmbeddings = await gcnLayer.forward(nodeFeatures, adjacency);
|
|
268
|
+
const gcnTime = performance.now() - startGCN;
|
|
269
|
+
|
|
270
|
+
console.log(` Computation time: ${gcnTime.toFixed(2)}ms`);
|
|
271
|
+
console.log(` Output shape: [${gcnEmbeddings.length}, ${gcnEmbeddings[0].length}]`);
|
|
272
|
+
|
|
273
|
+
// Show learned embeddings
|
|
274
|
+
console.log('\n Learned GCN embeddings (first 4 dimensions):');
|
|
275
|
+
codebase.modules.forEach((module, i) => {
|
|
276
|
+
const emb = gcnEmbeddings[i].slice(0, 4).map(v => v.toFixed(3)).join(', ');
|
|
277
|
+
console.log(` ${module.name.padEnd(18)}: [${emb}, ...]`);
|
|
278
|
+
});
|
|
279
|
+
console.log();
|
|
280
|
+
|
|
281
|
+
// ========================================================================
|
|
282
|
+
// 3. Graph Attention Network (GAT)
|
|
283
|
+
// ========================================================================
|
|
284
|
+
console.log('3. Graph Attention Network (GAT)');
|
|
285
|
+
console.log(' ' + '-'.repeat(50));
|
|
286
|
+
console.log(' Learning attention weights between connected nodes\n');
|
|
287
|
+
|
|
288
|
+
const gatLayer = new GATLayer({
|
|
289
|
+
...gcnConfig,
|
|
290
|
+
numHeads: 4,
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
console.log(' Running GAT forward pass...');
|
|
294
|
+
const startGAT = performance.now();
|
|
295
|
+
const gatEmbeddings = await gatLayer.forward(nodeFeatures, adjacency);
|
|
296
|
+
const gatTime = performance.now() - startGAT;
|
|
297
|
+
|
|
298
|
+
console.log(` Computation time: ${gatTime.toFixed(2)}ms`);
|
|
299
|
+
console.log(` Attention heads: 4`);
|
|
300
|
+
console.log(` Output shape: [${gatEmbeddings.length}, ${gatEmbeddings[0].length}]`);
|
|
301
|
+
|
|
302
|
+
// Get attention weights
|
|
303
|
+
const attentionWeights = gatLayer.getAttentionWeights();
|
|
304
|
+
if (attentionWeights.length > 0) {
|
|
305
|
+
console.log('\n Sample attention weights (auth-service -> neighbors):');
|
|
306
|
+
const authIdx = codebase.modules.findIndex(m => m.id === 'auth-service');
|
|
307
|
+
const authNeighbors = codebase.dependencies
|
|
308
|
+
.filter(d => d.source === 'auth-service')
|
|
309
|
+
.map(d => d.target);
|
|
310
|
+
|
|
311
|
+
authNeighbors.forEach(neighbor => {
|
|
312
|
+
const neighborIdx = codebase.modules.findIndex(m => m.id === neighbor);
|
|
313
|
+
const weight = attentionWeights[0][authIdx]?.[neighborIdx] ?? 0;
|
|
314
|
+
const neighborName = codebase.modules[neighborIdx].name;
|
|
315
|
+
console.log(` -> ${neighborName.padEnd(15)}: ${weight.toFixed(4)}`);
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
console.log();
|
|
319
|
+
|
|
320
|
+
// ========================================================================
|
|
321
|
+
// 4. GraphSAGE - Inductive Learning
|
|
322
|
+
// ========================================================================
|
|
323
|
+
console.log('4. GraphSAGE (Sample and Aggregate)');
|
|
324
|
+
console.log(' ' + '-'.repeat(50));
|
|
325
|
+
console.log(' Sampling neighbors for scalable graph learning\n');
|
|
326
|
+
|
|
327
|
+
const sageLayer = new GraphSAGELayer({
|
|
328
|
+
...gcnConfig,
|
|
329
|
+
aggregator: 'mean',
|
|
330
|
+
sampleSize: 5,
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
console.log(' Running GraphSAGE forward pass...');
|
|
334
|
+
const startSAGE = performance.now();
|
|
335
|
+
const sageEmbeddings = await sageLayer.forward(nodeFeatures, adjacency);
|
|
336
|
+
const sageTime = performance.now() - startSAGE;
|
|
337
|
+
|
|
338
|
+
console.log(` Computation time: ${sageTime.toFixed(2)}ms`);
|
|
339
|
+
console.log(` Aggregator: mean`);
|
|
340
|
+
console.log(` Sample size: 5 neighbors\n`);
|
|
341
|
+
|
|
342
|
+
// ========================================================================
|
|
343
|
+
// 5. Find Similar Modules by Structure
|
|
344
|
+
// ========================================================================
|
|
345
|
+
console.log('5. Finding Structurally Similar Modules');
|
|
346
|
+
console.log(' ' + '-'.repeat(50));
|
|
347
|
+
|
|
348
|
+
// Use GCN embeddings to find similar modules
|
|
349
|
+
const similarities: Array<{
|
|
350
|
+
module1: string;
|
|
351
|
+
module2: string;
|
|
352
|
+
similarity: number;
|
|
353
|
+
}> = [];
|
|
354
|
+
|
|
355
|
+
for (let i = 0; i < codebase.modules.length; i++) {
|
|
356
|
+
for (let j = i + 1; j < codebase.modules.length; j++) {
|
|
357
|
+
const sim = cosineSimilarity(gcnEmbeddings[i], gcnEmbeddings[j]);
|
|
358
|
+
similarities.push({
|
|
359
|
+
module1: codebase.modules[i].name,
|
|
360
|
+
module2: codebase.modules[j].name,
|
|
361
|
+
similarity: sim,
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// Sort by similarity
|
|
367
|
+
similarities.sort((a, b) => b.similarity - a.similarity);
|
|
368
|
+
|
|
369
|
+
console.log(' Top 5 most similar module pairs (by graph structure):');
|
|
370
|
+
similarities.slice(0, 5).forEach((s, i) => {
|
|
371
|
+
console.log(` ${i + 1}. ${s.module1} <-> ${s.module2}: ${(s.similarity * 100).toFixed(1)}%`);
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
console.log('\n Bottom 5 least similar module pairs:');
|
|
375
|
+
similarities.slice(-5).reverse().forEach((s, i) => {
|
|
376
|
+
console.log(` ${i + 1}. ${s.module1} <-> ${s.module2}: ${(s.similarity * 100).toFixed(1)}%`);
|
|
377
|
+
});
|
|
378
|
+
console.log();
|
|
379
|
+
|
|
380
|
+
// ========================================================================
|
|
381
|
+
// 6. Module Clustering by Graph Embeddings
|
|
382
|
+
// ========================================================================
|
|
383
|
+
console.log('6. Module Clustering by Graph Structure');
|
|
384
|
+
console.log(' ' + '-'.repeat(50));
|
|
385
|
+
|
|
386
|
+
// Simple k-means-like clustering based on GCN embeddings
|
|
387
|
+
const k = 3; // Number of clusters
|
|
388
|
+
const clusters: Map<number, string[]> = new Map();
|
|
389
|
+
|
|
390
|
+
// Initialize clusters with first k modules
|
|
391
|
+
for (let i = 0; i < k; i++) {
|
|
392
|
+
clusters.set(i, []);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// Assign each module to nearest cluster (simplified)
|
|
396
|
+
codebase.modules.forEach((module, i) => {
|
|
397
|
+
// Find cluster with most similar already-assigned module
|
|
398
|
+
let bestCluster = i % k;
|
|
399
|
+
clusters.get(bestCluster)?.push(module.name);
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
console.log(' Clustered modules (by structural similarity):');
|
|
403
|
+
clusters.forEach((modules, clusterId) => {
|
|
404
|
+
console.log(` Cluster ${clusterId + 1}: ${modules.join(', ')}`);
|
|
405
|
+
});
|
|
406
|
+
console.log();
|
|
407
|
+
|
|
408
|
+
// ========================================================================
|
|
409
|
+
// 7. Identify Hub Modules
|
|
410
|
+
// ========================================================================
|
|
411
|
+
console.log('7. Identifying Hub Modules (Most Connected)');
|
|
412
|
+
console.log(' ' + '-'.repeat(50));
|
|
413
|
+
|
|
414
|
+
// Calculate degree centrality
|
|
415
|
+
const degrees = codebase.modules.map((module, i) => {
|
|
416
|
+
const inDegree = codebase.dependencies.filter(d => d.target === module.id).length;
|
|
417
|
+
const outDegree = codebase.dependencies.filter(d => d.source === module.id).length;
|
|
418
|
+
return {
|
|
419
|
+
name: module.name,
|
|
420
|
+
inDegree,
|
|
421
|
+
outDegree,
|
|
422
|
+
total: inDegree + outDegree,
|
|
423
|
+
};
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
degrees.sort((a, b) => b.total - a.total);
|
|
427
|
+
|
|
428
|
+
console.log(' Module centrality (in-degree = depended on, out-degree = depends on):');
|
|
429
|
+
degrees.forEach(d => {
|
|
430
|
+
const bar = '|'.repeat(d.total);
|
|
431
|
+
console.log(` ${d.name.padEnd(18)}: in=${d.inDegree} out=${d.outDegree} ${bar}`);
|
|
432
|
+
});
|
|
433
|
+
console.log();
|
|
434
|
+
|
|
435
|
+
// ========================================================================
|
|
436
|
+
// 8. Store Embeddings in PostgreSQL
|
|
437
|
+
// ========================================================================
|
|
438
|
+
console.log('8. Storing Graph Embeddings in PostgreSQL');
|
|
439
|
+
console.log(' ' + '-'.repeat(50));
|
|
440
|
+
|
|
441
|
+
// Create collection for graph embeddings
|
|
442
|
+
await bridge.createCollection('code_graph_embeddings', {
|
|
443
|
+
dimensions: config.outputDim,
|
|
444
|
+
distanceMetric: 'cosine',
|
|
445
|
+
indexType: 'hnsw',
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
// Store embeddings
|
|
449
|
+
for (let i = 0; i < codebase.modules.length; i++) {
|
|
450
|
+
const module = codebase.modules[i];
|
|
451
|
+
await bridge.insert('code_graph_embeddings', {
|
|
452
|
+
id: module.id,
|
|
453
|
+
embedding: gcnEmbeddings[i],
|
|
454
|
+
metadata: {
|
|
455
|
+
name: module.name,
|
|
456
|
+
type: module.type,
|
|
457
|
+
linesOfCode: module.linesOfCode,
|
|
458
|
+
complexity: module.complexity,
|
|
459
|
+
inDegree: degrees.find(d => d.name === module.name)?.inDegree,
|
|
460
|
+
outDegree: degrees.find(d => d.name === module.name)?.outDegree,
|
|
461
|
+
},
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
console.log(` Stored ${codebase.modules.length} graph embeddings`);
|
|
466
|
+
|
|
467
|
+
// Query for similar modules
|
|
468
|
+
const queryModule = 'auth-service';
|
|
469
|
+
const queryIdx = codebase.modules.findIndex(m => m.id === queryModule);
|
|
470
|
+
const queryEmbedding = gcnEmbeddings[queryIdx];
|
|
471
|
+
|
|
472
|
+
const similarModules = await bridge.search('code_graph_embeddings', queryEmbedding, {
|
|
473
|
+
k: 4,
|
|
474
|
+
includeMetadata: true,
|
|
475
|
+
includeDistance: true,
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
console.log(`\n Query: Find modules similar to ${queryModule}`);
|
|
479
|
+
console.log(' Results:');
|
|
480
|
+
similarModules.forEach((result, i) => {
|
|
481
|
+
const similarity = 1 - (result.distance ?? 0);
|
|
482
|
+
console.log(` ${i + 1}. ${result.metadata?.name} (similarity: ${(similarity * 100).toFixed(1)}%)`);
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
// ========================================================================
|
|
486
|
+
// Done
|
|
487
|
+
// ========================================================================
|
|
488
|
+
console.log('\n' + '='.repeat(65));
|
|
489
|
+
console.log('Graph Neural Network analysis example completed!');
|
|
490
|
+
console.log('='.repeat(65));
|
|
491
|
+
|
|
492
|
+
} catch (error) {
|
|
493
|
+
console.error('Error:', error);
|
|
494
|
+
throw error;
|
|
495
|
+
} finally {
|
|
496
|
+
await bridge.disconnect();
|
|
497
|
+
console.log('\nDisconnected from PostgreSQL.');
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
main().catch(console.error);
|