@syke1/mcp-server 1.6.0 → 1.7.0
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/LICENSE +13 -57
- package/README.md +18 -21
- package/dist/ai/analyzer.js +112 -1
- package/dist/ai/context-extractor.js +224 -1
- package/dist/ai/provider.js +186 -1
- package/dist/ai/realtime-analyzer.js +253 -1
- package/dist/config.js +121 -1
- package/dist/git/change-coupling.js +250 -1
- package/dist/graph/incremental.js +313 -1
- package/dist/graph/memo-cache.js +176 -1
- package/dist/graph/scc.js +206 -1
- package/dist/graph.d.ts +0 -3
- package/dist/graph.js +130 -1
- package/dist/index.js +825 -1
- package/dist/license/validator.d.ts +0 -3
- package/dist/license/validator.js +344 -1
- package/dist/remote/proxy.d.ts +34 -0
- package/dist/remote/proxy.js +214 -0
- package/dist/remote/types.d.ts +81 -0
- package/dist/remote/types.js +8 -0
- package/dist/tools/analyze-impact.d.ts +5 -5
- package/dist/tools/analyze-impact.js +326 -1
- package/dist/tools/gate-build.d.ts +0 -3
- package/dist/tools/gate-build.js +361 -1
- package/dist/watcher/file-cache.js +281 -1
- package/dist/web/server.js +925 -1
- package/package.json +52 -69
- package/dist/scoring/pagerank.d.ts +0 -67
- package/dist/scoring/pagerank.js +0 -1
- package/dist/scoring/risk-scorer.d.ts +0 -99
- package/dist/scoring/risk-scorer.js +0 -1
package/dist/graph/memo-cache.js
CHANGED
|
@@ -1 +1,176 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Memoized BFS Result Cache for SYKE.
|
|
4
|
+
*
|
|
5
|
+
* Caches impact analysis results (BFS reverse traversals) so that
|
|
6
|
+
* repeated queries for the same file return instantly.
|
|
7
|
+
*
|
|
8
|
+
* Smart invalidation: when a file changes, only cache entries that
|
|
9
|
+
* could be affected are evicted. A reverse index maps each file to
|
|
10
|
+
* the set of cache keys whose impactSet contains it, making
|
|
11
|
+
* invalidation O(affected) instead of O(cache_size).
|
|
12
|
+
*
|
|
13
|
+
* Uses LRU eviction when the cache exceeds maxSize.
|
|
14
|
+
*/
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.createMemoCache = createMemoCache;
|
|
17
|
+
exports.getMemoCache = getMemoCache;
|
|
18
|
+
exports.resetMemoCache = resetMemoCache;
|
|
19
|
+
// ── Implementation ──
|
|
20
|
+
/**
|
|
21
|
+
* Create a new MemoCache with LRU eviction and reverse-index invalidation.
|
|
22
|
+
*
|
|
23
|
+
* @param maxSize Maximum number of cached entries (default 500).
|
|
24
|
+
*/
|
|
25
|
+
function createMemoCache(maxSize = 500) {
|
|
26
|
+
// Main cache: filePath -> MemoEntry
|
|
27
|
+
const cache = new Map();
|
|
28
|
+
// LRU tracking: most recently accessed key moves to the end
|
|
29
|
+
const accessOrder = [];
|
|
30
|
+
// Reverse index: maps each file to the set of cache keys whose
|
|
31
|
+
// impactSet contains that file. Used for O(affected) invalidation.
|
|
32
|
+
const reverseIndex = new Map();
|
|
33
|
+
// Stats
|
|
34
|
+
let hits = 0;
|
|
35
|
+
let misses = 0;
|
|
36
|
+
/**
|
|
37
|
+
* Move a key to the end of the access order (most recently used).
|
|
38
|
+
*/
|
|
39
|
+
function touchKey(key) {
|
|
40
|
+
const idx = accessOrder.indexOf(key);
|
|
41
|
+
if (idx !== -1) {
|
|
42
|
+
accessOrder.splice(idx, 1);
|
|
43
|
+
}
|
|
44
|
+
accessOrder.push(key);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Remove a single entry from the cache and clean up the reverse index.
|
|
48
|
+
*/
|
|
49
|
+
function removeEntry(key) {
|
|
50
|
+
const entry = cache.get(key);
|
|
51
|
+
if (!entry)
|
|
52
|
+
return;
|
|
53
|
+
// Remove from reverse index
|
|
54
|
+
for (const file of entry.impactSet) {
|
|
55
|
+
const keys = reverseIndex.get(file);
|
|
56
|
+
if (keys) {
|
|
57
|
+
keys.delete(key);
|
|
58
|
+
if (keys.size === 0) {
|
|
59
|
+
reverseIndex.delete(file);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Also remove the key itself from the reverse index
|
|
64
|
+
const selfKeys = reverseIndex.get(key);
|
|
65
|
+
if (selfKeys) {
|
|
66
|
+
selfKeys.delete(key);
|
|
67
|
+
if (selfKeys.size === 0) {
|
|
68
|
+
reverseIndex.delete(key);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
cache.delete(key);
|
|
72
|
+
const orderIdx = accessOrder.indexOf(key);
|
|
73
|
+
if (orderIdx !== -1) {
|
|
74
|
+
accessOrder.splice(orderIdx, 1);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Evict the least recently used entry when cache exceeds maxSize.
|
|
79
|
+
*/
|
|
80
|
+
function evictLRU() {
|
|
81
|
+
while (cache.size > maxSize && accessOrder.length > 0) {
|
|
82
|
+
const lruKey = accessOrder.shift();
|
|
83
|
+
removeEntry(lruKey);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Add a file -> cacheKey mapping to the reverse index.
|
|
88
|
+
*/
|
|
89
|
+
function addToReverseIndex(file, cacheKey) {
|
|
90
|
+
let keys = reverseIndex.get(file);
|
|
91
|
+
if (!keys) {
|
|
92
|
+
keys = new Set();
|
|
93
|
+
reverseIndex.set(file, keys);
|
|
94
|
+
}
|
|
95
|
+
keys.add(cacheKey);
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
get(filePath) {
|
|
99
|
+
const entry = cache.get(filePath);
|
|
100
|
+
if (entry) {
|
|
101
|
+
hits++;
|
|
102
|
+
touchKey(filePath);
|
|
103
|
+
return entry;
|
|
104
|
+
}
|
|
105
|
+
misses++;
|
|
106
|
+
return undefined;
|
|
107
|
+
},
|
|
108
|
+
set(filePath, entry) {
|
|
109
|
+
// If already cached, remove old reverse index entries first
|
|
110
|
+
if (cache.has(filePath)) {
|
|
111
|
+
removeEntry(filePath);
|
|
112
|
+
}
|
|
113
|
+
// Store the entry
|
|
114
|
+
cache.set(filePath, entry);
|
|
115
|
+
touchKey(filePath);
|
|
116
|
+
// Build reverse index: map each file in impactSet -> this cache key
|
|
117
|
+
for (const file of entry.impactSet) {
|
|
118
|
+
addToReverseIndex(file, filePath);
|
|
119
|
+
}
|
|
120
|
+
// Also index the key itself (if the queried file changes, its own
|
|
121
|
+
// cached result is stale)
|
|
122
|
+
addToReverseIndex(filePath, filePath);
|
|
123
|
+
// Evict LRU if over capacity
|
|
124
|
+
evictLRU();
|
|
125
|
+
},
|
|
126
|
+
invalidate(affectedFiles) {
|
|
127
|
+
const keysToInvalidate = new Set();
|
|
128
|
+
for (const file of affectedFiles) {
|
|
129
|
+
// Find all cache keys whose impactSet contains this file
|
|
130
|
+
const keys = reverseIndex.get(file);
|
|
131
|
+
if (keys) {
|
|
132
|
+
for (const key of keys) {
|
|
133
|
+
keysToInvalidate.add(key);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// Remove all identified entries
|
|
138
|
+
for (const key of keysToInvalidate) {
|
|
139
|
+
removeEntry(key);
|
|
140
|
+
}
|
|
141
|
+
return keysToInvalidate.size;
|
|
142
|
+
},
|
|
143
|
+
invalidateAll() {
|
|
144
|
+
cache.clear();
|
|
145
|
+
accessOrder.length = 0;
|
|
146
|
+
reverseIndex.clear();
|
|
147
|
+
// Do NOT reset hits/misses — they are cumulative diagnostics
|
|
148
|
+
},
|
|
149
|
+
stats() {
|
|
150
|
+
return {
|
|
151
|
+
size: cache.size,
|
|
152
|
+
hits,
|
|
153
|
+
misses,
|
|
154
|
+
};
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
// ── Singleton Instance ──
|
|
159
|
+
let globalMemoCache = null;
|
|
160
|
+
/**
|
|
161
|
+
* Get the global memo cache instance (lazy initialization).
|
|
162
|
+
*/
|
|
163
|
+
function getMemoCache() {
|
|
164
|
+
if (!globalMemoCache) {
|
|
165
|
+
globalMemoCache = createMemoCache();
|
|
166
|
+
}
|
|
167
|
+
return globalMemoCache;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Reset the global memo cache (e.g., on full graph rebuild).
|
|
171
|
+
*/
|
|
172
|
+
function resetMemoCache() {
|
|
173
|
+
if (globalMemoCache) {
|
|
174
|
+
globalMemoCache.invalidateAll();
|
|
175
|
+
}
|
|
176
|
+
}
|
package/dist/graph/scc.js
CHANGED
|
@@ -1 +1,206 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Strongly Connected Components (SCC) via Tarjan's algorithm,
|
|
4
|
+
* graph condensation into a DAG, and topological sort via Kahn's algorithm.
|
|
5
|
+
*
|
|
6
|
+
* Used to detect circular dependencies and provide accurate cascade-level
|
|
7
|
+
* impact analysis on the condensed (acyclic) dependency graph.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.computeSCC = computeSCC;
|
|
11
|
+
exports.condenseGraph = condenseGraph;
|
|
12
|
+
exports.topologicalSort = topologicalSort;
|
|
13
|
+
// ── Tarjan's SCC Algorithm ──
|
|
14
|
+
/**
|
|
15
|
+
* Compute all Strongly Connected Components of the dependency graph
|
|
16
|
+
* using Tarjan's algorithm. Returns SCCs, a file-to-SCC mapping,
|
|
17
|
+
* and the condensed DAG with topological ordering.
|
|
18
|
+
*/
|
|
19
|
+
function computeSCC(graph) {
|
|
20
|
+
// Handle empty graph
|
|
21
|
+
if (graph.files.size === 0) {
|
|
22
|
+
const emptyDAG = {
|
|
23
|
+
nodes: [],
|
|
24
|
+
forward: new Map(),
|
|
25
|
+
reverse: new Map(),
|
|
26
|
+
topologicalOrder: [],
|
|
27
|
+
};
|
|
28
|
+
return {
|
|
29
|
+
components: [],
|
|
30
|
+
nodeToComponent: new Map(),
|
|
31
|
+
condensed: emptyDAG,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
const components = [];
|
|
35
|
+
// Tarjan state
|
|
36
|
+
let indexCounter = 0;
|
|
37
|
+
const nodeIndex = new Map();
|
|
38
|
+
const nodeLowlink = new Map();
|
|
39
|
+
const onStack = new Set();
|
|
40
|
+
const stack = [];
|
|
41
|
+
function strongConnect(node) {
|
|
42
|
+
nodeIndex.set(node, indexCounter);
|
|
43
|
+
nodeLowlink.set(node, indexCounter);
|
|
44
|
+
indexCounter++;
|
|
45
|
+
stack.push(node);
|
|
46
|
+
onStack.add(node);
|
|
47
|
+
const successors = graph.forward.get(node) || [];
|
|
48
|
+
for (const successor of successors) {
|
|
49
|
+
// Only process nodes that exist in the graph
|
|
50
|
+
if (!graph.files.has(successor))
|
|
51
|
+
continue;
|
|
52
|
+
if (!nodeIndex.has(successor)) {
|
|
53
|
+
// Successor not yet visited — recurse
|
|
54
|
+
strongConnect(successor);
|
|
55
|
+
nodeLowlink.set(node, Math.min(nodeLowlink.get(node), nodeLowlink.get(successor)));
|
|
56
|
+
}
|
|
57
|
+
else if (onStack.has(successor)) {
|
|
58
|
+
// Successor is on the stack — part of current SCC
|
|
59
|
+
nodeLowlink.set(node, Math.min(nodeLowlink.get(node), nodeIndex.get(successor)));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// If node is a root of an SCC, pop the stack to form a component
|
|
63
|
+
if (nodeLowlink.get(node) === nodeIndex.get(node)) {
|
|
64
|
+
const component = [];
|
|
65
|
+
let w;
|
|
66
|
+
do {
|
|
67
|
+
w = stack.pop();
|
|
68
|
+
onStack.delete(w);
|
|
69
|
+
component.push(w);
|
|
70
|
+
} while (w !== node);
|
|
71
|
+
components.push(component);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// Visit all nodes (handles disconnected components)
|
|
75
|
+
for (const file of graph.files) {
|
|
76
|
+
if (!nodeIndex.has(file)) {
|
|
77
|
+
strongConnect(file);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// Build file-to-component mapping
|
|
81
|
+
const nodeToComponent = new Map();
|
|
82
|
+
for (let i = 0; i < components.length; i++) {
|
|
83
|
+
for (const file of components[i]) {
|
|
84
|
+
nodeToComponent.set(file, i);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// Build the condensed DAG
|
|
88
|
+
const condensed = condenseGraph(graph, components, nodeToComponent);
|
|
89
|
+
return { components, nodeToComponent, condensed };
|
|
90
|
+
}
|
|
91
|
+
// ── Graph Condensation ──
|
|
92
|
+
/**
|
|
93
|
+
* Build a DAG where each node represents one SCC.
|
|
94
|
+
* Edges between SCCs are derived from the original graph's edges
|
|
95
|
+
* between files belonging to different SCCs.
|
|
96
|
+
*/
|
|
97
|
+
function condenseGraph(graph, components, nodeToComponent) {
|
|
98
|
+
const numComponents = components.length;
|
|
99
|
+
// Build condensed nodes
|
|
100
|
+
const nodes = components.map((files, index) => ({
|
|
101
|
+
index,
|
|
102
|
+
files,
|
|
103
|
+
size: files.length,
|
|
104
|
+
isCyclic: files.length > 1,
|
|
105
|
+
}));
|
|
106
|
+
// Build forward and reverse edges between SCCs (deduplicated)
|
|
107
|
+
const forwardSets = new Map();
|
|
108
|
+
const reverseSets = new Map();
|
|
109
|
+
for (let i = 0; i < numComponents; i++) {
|
|
110
|
+
forwardSets.set(i, new Set());
|
|
111
|
+
reverseSets.set(i, new Set());
|
|
112
|
+
}
|
|
113
|
+
for (const [file, deps] of graph.forward) {
|
|
114
|
+
const srcSCC = nodeToComponent.get(file);
|
|
115
|
+
if (srcSCC === undefined)
|
|
116
|
+
continue;
|
|
117
|
+
for (const dep of deps) {
|
|
118
|
+
const dstSCC = nodeToComponent.get(dep);
|
|
119
|
+
if (dstSCC === undefined)
|
|
120
|
+
continue;
|
|
121
|
+
// Skip self-edges (within the same SCC)
|
|
122
|
+
if (srcSCC === dstSCC)
|
|
123
|
+
continue;
|
|
124
|
+
forwardSets.get(srcSCC).add(dstSCC);
|
|
125
|
+
reverseSets.get(dstSCC).add(srcSCC);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// Convert sets to arrays
|
|
129
|
+
const forward = new Map();
|
|
130
|
+
const reverse = new Map();
|
|
131
|
+
for (const [key, set] of forwardSets) {
|
|
132
|
+
forward.set(key, [...set]);
|
|
133
|
+
}
|
|
134
|
+
for (const [key, set] of reverseSets) {
|
|
135
|
+
reverse.set(key, [...set]);
|
|
136
|
+
}
|
|
137
|
+
const dag = {
|
|
138
|
+
nodes,
|
|
139
|
+
forward,
|
|
140
|
+
reverse,
|
|
141
|
+
topologicalOrder: [],
|
|
142
|
+
};
|
|
143
|
+
// Compute topological order
|
|
144
|
+
dag.topologicalOrder = topologicalSort(dag);
|
|
145
|
+
return dag;
|
|
146
|
+
}
|
|
147
|
+
// ── Topological Sort (Kahn's Algorithm) ──
|
|
148
|
+
/**
|
|
149
|
+
* Compute a topological ordering of the condensed DAG using Kahn's algorithm.
|
|
150
|
+
* The condensed graph is guaranteed to be acyclic after SCC condensation.
|
|
151
|
+
*
|
|
152
|
+
* Returns SCC indices in dependency order: dependencies come before dependents.
|
|
153
|
+
* This uses the `forward` edges (file A imports B means A -> B in forward),
|
|
154
|
+
* so we process nodes with no incoming forward edges first (leaf dependencies).
|
|
155
|
+
*/
|
|
156
|
+
function topologicalSort(dag) {
|
|
157
|
+
const numNodes = dag.nodes.length;
|
|
158
|
+
if (numNodes === 0)
|
|
159
|
+
return [];
|
|
160
|
+
// In-degree = number of dependencies (forward edges out of each node).
|
|
161
|
+
// forward[A] = [B] means A imports B, so A depends on B.
|
|
162
|
+
// For "dependencies first" ordering, nodes with zero dependencies come first.
|
|
163
|
+
const inDegree = new Map();
|
|
164
|
+
for (let i = 0; i < numNodes; i++) {
|
|
165
|
+
inDegree.set(i, 0);
|
|
166
|
+
}
|
|
167
|
+
for (const [src, dsts] of dag.forward) {
|
|
168
|
+
inDegree.set(src, (inDegree.get(src) || 0) + dsts.length);
|
|
169
|
+
}
|
|
170
|
+
// Start with nodes that have no dependencies (in-degree 0 in forward)
|
|
171
|
+
const queue = [];
|
|
172
|
+
for (const [node, degree] of inDegree) {
|
|
173
|
+
if (degree === 0) {
|
|
174
|
+
queue.push(node);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
const order = [];
|
|
178
|
+
while (queue.length > 0) {
|
|
179
|
+
const current = queue.shift();
|
|
180
|
+
order.push(current);
|
|
181
|
+
// current has no remaining dependencies.
|
|
182
|
+
// For all nodes that depend on current (reverse edges: who imports current),
|
|
183
|
+
// decrement their in-degree.
|
|
184
|
+
const dependents = dag.reverse.get(current) || [];
|
|
185
|
+
for (const dependent of dependents) {
|
|
186
|
+
const newDegree = (inDegree.get(dependent) || 0) - 1;
|
|
187
|
+
inDegree.set(dependent, newDegree);
|
|
188
|
+
if (newDegree === 0) {
|
|
189
|
+
queue.push(dependent);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
// If order doesn't contain all nodes, there's a bug (shouldn't happen after SCC condensation)
|
|
194
|
+
if (order.length !== numNodes) {
|
|
195
|
+
console.error(`[syke:scc] WARNING: Topological sort produced ${order.length}/${numNodes} nodes. ` +
|
|
196
|
+
`This indicates a bug in SCC condensation.`);
|
|
197
|
+
// Add remaining nodes at the end
|
|
198
|
+
const ordered = new Set(order);
|
|
199
|
+
for (let i = 0; i < numNodes; i++) {
|
|
200
|
+
if (!ordered.has(i)) {
|
|
201
|
+
order.push(i);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return order;
|
|
206
|
+
}
|
package/dist/graph.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { SCCResult } from "./graph/scc";
|
|
2
|
-
import { PageRankResult } from "./scoring/pagerank";
|
|
3
2
|
export interface DependencyGraph {
|
|
4
3
|
forward: Map<string, string[]>;
|
|
5
4
|
reverse: Map<string, string[]>;
|
|
@@ -11,8 +10,6 @@ export interface DependencyGraph {
|
|
|
11
10
|
sourceDir: string;
|
|
12
11
|
/** Strongly Connected Components — computed after graph build */
|
|
13
12
|
scc?: SCCResult;
|
|
14
|
-
/** PageRank importance scores — computed after graph build */
|
|
15
|
-
pageRank?: PageRankResult;
|
|
16
13
|
}
|
|
17
14
|
export declare function buildGraph(projectRoot: string, packageName?: string, maxFiles?: number): DependencyGraph;
|
|
18
15
|
export declare function getGraph(projectRoot: string, packageName?: string, maxFiles?: number): DependencyGraph;
|
package/dist/graph.js
CHANGED
|
@@ -1 +1,130 @@
|
|
|
1
|
-
'use strict';const _0x5c54c1=_0x5bfe;(function(_0x25f668,_0x362444){const _0x3ef357={_0x29471:0x1b8,_0x429269:0x1ba,_0x40b157:0x1a2,_0x6da95a:0x1b5,_0x59595a:0x1bf},_0x29323e=_0x5bfe,_0x13ff04=_0x25f668();while(!![]){try{const _0x5c7abf=parseInt(_0x29323e(0x1cf))/0x1*(parseInt(_0x29323e(_0x3ef357._0x29471))/0x2)+-parseInt(_0x29323e(_0x3ef357._0x429269))/0x3+parseInt(_0x29323e(_0x3ef357._0x40b157))/0x4+parseInt(_0x29323e(0x1ae))/0x5+-parseInt(_0x29323e(_0x3ef357._0x6da95a))/0x6+-parseInt(_0x29323e(0x1a3))/0x7*(-parseInt(_0x29323e(0x1c0))/0x8)+-parseInt(_0x29323e(_0x3ef357._0x59595a))/0x9*(-parseInt(_0x29323e(0x1b2))/0xa);if(_0x5c7abf===_0x362444)break;else _0x13ff04['push'](_0x13ff04['shift']());}catch(_0x36974e){_0x13ff04['push'](_0x13ff04['shift']());}}}(_0x3803,0xe8aa3));function _0x5bfe(_0x2774fa,_0x2f7661){_0x2774fa=_0x2774fa-0x1a2;const _0x380365=_0x3803();let _0x5bfe78=_0x380365[_0x2774fa];if(_0x5bfe['lUsreh']===undefined){var _0x511b41=function(_0x1e694e){const _0x4e3c5b='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x4d3dcc='',_0xf9e95f='';for(let _0x31a682=0x0,_0x4e95e4,_0x4ea1cb,_0x54a624=0x0;_0x4ea1cb=_0x1e694e['charAt'](_0x54a624++);~_0x4ea1cb&&(_0x4e95e4=_0x31a682%0x4?_0x4e95e4*0x40+_0x4ea1cb:_0x4ea1cb,_0x31a682++%0x4)?_0x4d3dcc+=String['fromCharCode'](0xff&_0x4e95e4>>(-0x2*_0x31a682&0x6)):0x0){_0x4ea1cb=_0x4e3c5b['indexOf'](_0x4ea1cb);}for(let _0x290b1c=0x0,_0x1c33a3=_0x4d3dcc['length'];_0x290b1c<_0x1c33a3;_0x290b1c++){_0xf9e95f+='%'+('00'+_0x4d3dcc['charCodeAt'](_0x290b1c)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0xf9e95f);};_0x5bfe['PBpyrD']=_0x511b41,_0x5bfe['ieYGnx']={},_0x5bfe['lUsreh']=!![];}const _0x40a6a8=_0x380365[0x0],_0x36fb22=_0x2774fa+_0x40a6a8,_0x47861c=_0x5bfe['ieYGnx'][_0x36fb22];return!_0x47861c?(_0x5bfe78=_0x5bfe['PBpyrD'](_0x5bfe78),_0x5bfe['ieYGnx'][_0x36fb22]=_0x5bfe78):_0x5bfe78=_0x47861c,_0x5bfe78;}var __createBinding=this&&this[_0x5c54c1(0x1b3)]||(Object['create']?function(_0x4fe668,_0x4f5932,_0x51164c,_0xde319a){const _0x8dfb32={_0x360098:0x1c3},_0x50e3f7=_0x5c54c1,_0x285466={};_0x285466[_0x50e3f7(_0x8dfb32._0x360098)]='get';const _0x2dcf85=_0x285466;if(_0xde319a===undefined)_0xde319a=_0x51164c;var _0x320c00=Object['getOwnPropertyDescriptor'](_0x4f5932,_0x51164c);if(!_0x320c00||(_0x2dcf85['kkJpr']in _0x320c00?!_0x4f5932['__esModule']:_0x320c00['writable']||_0x320c00['configurable'])){const _0x4fc7ef={};_0x4fc7ef['enumerable']=!![],_0x4fc7ef['get']=function(){return _0x4f5932[_0x51164c];},_0x320c00=_0x4fc7ef;}Object['defineProperty'](_0x4fe668,_0xde319a,_0x320c00);}:function(_0x8e1989,_0x1850cc,_0x23cfbf,_0x3e9e03){if(_0x3e9e03===undefined)_0x3e9e03=_0x23cfbf;_0x8e1989[_0x3e9e03]=_0x1850cc[_0x23cfbf];}),__setModuleDefault=this&&this[_0x5c54c1(0x1aa)]||(Object['create']?function(_0x1ca784,_0x4414b6){const _0x1be0d8={_0x1f9821:0x1cb},_0x59837d=_0x5c54c1,_0x38b926={};_0x38b926[_0x59837d(0x1c8)]=!![],_0x38b926['value']=_0x4414b6,Object[_0x59837d(0x1b1)](_0x1ca784,_0x59837d(_0x1be0d8._0x1f9821),_0x38b926);}:function(_0x19ab70,_0x2e7f71){const _0x1834d0={_0x30843a:0x1b6},_0x14bceb=_0x5c54c1,_0xf701a9={};_0xf701a9[_0x14bceb(_0x1834d0._0x30843a)]=_0x14bceb(0x1cb);const _0x5c7bee=_0xf701a9;_0x19ab70[_0x5c7bee[_0x14bceb(0x1b6)]]=_0x2e7f71;}),__importStar=this&&this[_0x5c54c1(0x1c5)]||(function(){const _0x53b5c3={_0x4b7c11:0x1bb},_0x1c01f1={_0x10be6d:0x1c6},_0x91ca8d={'ptvzb':function(_0x2283fc,_0x42d24d){return _0x2283fc(_0x42d24d);},'luxMW':function(_0x1be260,_0x336dac){return _0x1be260<_0x336dac;},'jgvYc':function(_0x51625b,_0x2fbfc2){return _0x51625b!==_0x2fbfc2;}};var _0x27c614=function(_0xcdb793){return _0x27c614=Object['getOwnPropertyNames']||function(_0x3bb046){const _0x435f89=_0x5bfe;var _0x40852a=[];for(var _0x19a823 in _0x3bb046)if(Object[_0x435f89(_0x1c01f1._0x10be6d)]['hasOwnProperty'][_0x435f89(0x1be)](_0x3bb046,_0x19a823))_0x40852a[_0x40852a['length']]=_0x19a823;return _0x40852a;},_0x91ca8d['ptvzb'](_0x27c614,_0xcdb793);};return function(_0x5f3fb6){const _0x2ba0e7=_0x5bfe;if(_0x5f3fb6&&_0x5f3fb6['__esModule'])return _0x5f3fb6;var _0x562c4d={};if(_0x5f3fb6!=null){for(var _0x58cc8a=_0x27c614(_0x5f3fb6),_0x3247bf=0x0;_0x91ca8d[_0x2ba0e7(_0x53b5c3._0x4b7c11)](_0x3247bf,_0x58cc8a['length']);_0x3247bf++)if(_0x91ca8d['jgvYc'](_0x58cc8a[_0x3247bf],_0x2ba0e7(0x1cb)))__createBinding(_0x562c4d,_0x5f3fb6,_0x58cc8a[_0x3247bf]);}return __setModuleDefault(_0x562c4d,_0x5f3fb6),_0x562c4d;};}());const _0x3eb87d={};_0x3eb87d['value']=!![],Object[_0x5c54c1(0x1b1)](exports,'__esModule',_0x3eb87d),exports['buildGraph']=buildGraph,exports['getGraph']=getGraph,exports[_0x5c54c1(0x1ce)]=rebuildGraph;const path=__importStar(require('path')),plugin_1=require('./languages/plugin'),typescript_1=require('./languages/typescript'),scc_1=require('./graph/scc'),risk_scorer_1=require('./scoring/risk-scorer'),pagerank_1=require('./scoring/pagerank'),memo_cache_1=require(_0x5c54c1(0x1b0));let cachedGraph=null;function buildGraph(_0xf5a20c,_0x575355,_0x3248f4){const _0x7c7bfe={_0x3e0c00:0x1bd,_0x3c4c4f:0x1a8,_0x275772:0x1c9,_0x3d8164:0x1ab,_0x5bb81e:0x1c1,_0xe3a3c6:0x1b4,_0x283b10:0x1cd,_0x1591f2:0x1ca,_0x255e63:0x1a4,_0x1a5daf:0x1cc},_0x3be85c=_0x5c54c1,_0x55d3f4={'mycoI':'src','xUZDv':function(_0x45ca52,_0xf2a108){return _0x45ca52(_0xf2a108);}},_0x406dce=(0x0,plugin_1[_0x3be85c(_0x7c7bfe._0x3e0c00)])(_0xf5a20c),_0xe69acc=_0x406dce[_0x3be85c(_0x7c7bfe._0x3c4c4f)](_0x4c0ea2=>_0x4c0ea2['id']),_0x30db4d=new Map(),_0x168a11=new Map(),_0x776905=new Set(),_0x33e1f6=[];let _0x46ccb1=0x0,_0x385482=![];for(const _0x3b7727 of _0x406dce){const _0x453e77=_0x3b7727['getSourceDirs'](_0xf5a20c);console['error'](_0x3be85c(0x1af)+_0x3b7727['id']+'\x20getSourceDirs('+_0xf5a20c+')\x20=>\x20'+_0x453e77['length']+_0x3be85c(0x1c2)+_0x453e77[_0x3be85c(0x1a9)](',\x20'));for(const _0x173e3f of _0x453e77){if(!_0x33e1f6['includes'](_0x173e3f))_0x33e1f6[_0x3be85c(_0x7c7bfe._0x275772)](_0x173e3f);const _0x2051d5=_0x3b7727['discoverFiles'](_0x173e3f);console['error']('[syke:debug]\x20'+_0x3b7727['id']+'\x20discoverFiles('+_0x173e3f+')\x20=>\x20'+_0x2051d5[_0x3be85c(0x1ab)]+'\x20files'),_0x46ccb1+=_0x2051d5[_0x3be85c(_0x7c7bfe._0x3d8164)];for(const _0x8f67b2 of _0x2051d5){if(_0x3248f4&&_0x776905[_0x3be85c(0x1a4)]>=_0x3248f4){_0x385482=!![];break;}_0x776905[_0x3be85c(0x1b9)](_0x8f67b2);if(!_0x30db4d['has'](_0x8f67b2))_0x30db4d['set'](_0x8f67b2,[]);}for(const _0xef2676 of _0x2051d5){if(!_0x776905['has'](_0xef2676))continue;const _0x3685b1=_0x3b7727['parseImports'](_0xef2676,_0xf5a20c,_0x173e3f),_0x53b0dd=[];for(const _0x5d0c5f of _0x3685b1){if(!_0x776905[_0x3be85c(0x1a5)](_0x5d0c5f))continue;_0x53b0dd['push'](_0x5d0c5f);const _0x32e616=_0x168a11['get'](_0x5d0c5f)||[];_0x32e616[_0x3be85c(0x1c9)](_0xef2676),_0x168a11['set'](_0x5d0c5f,_0x32e616);}_0x30db4d[_0x3be85c(_0x7c7bfe._0x5bb81e)](_0xef2676,_0x53b0dd);}}}_0x385482&&console['error'](_0x3be85c(_0x7c7bfe._0xe3a3c6)+_0x776905[_0x3be85c(0x1a4)]+'/'+_0x46ccb1+'\x20files\x20(limit:\x20'+_0x3248f4+').\x20Upgrade\x20to\x20Pro\x20for\x20unlimited.');const _0x2baf31=_0x33e1f6[0x0]||path['join'](_0xf5a20c,_0x55d3f4['mycoI']),_0x4d02d6={};_0x4d02d6['forward']=_0x30db4d,_0x4d02d6['reverse']=_0x168a11,_0x4d02d6['files']=_0x776905,_0x4d02d6[_0x3be85c(0x1ac)]=_0xf5a20c,_0x4d02d6[_0x3be85c(_0x7c7bfe._0x283b10)]=_0xe69acc,_0x4d02d6['sourceDirs']=_0x33e1f6,_0x4d02d6['sourceDir']=_0x2baf31;const _0x1324b6=_0x4d02d6;(0x0,memo_cache_1['resetMemoCache'])();const _0x14a567=(0x0,scc_1['computeSCC'])(_0x1324b6);_0x1324b6['scc']=_0x14a567,(0x0,pagerank_1['invalidatePageRank'])(),_0x1324b6['pageRank']=(0x0,pagerank_1[_0x3be85c(_0x7c7bfe._0x1591f2)])(_0x1324b6);const _0x350265=_0x14a567['condensed']['nodes']['filter'](_0x28101e=>_0x28101e['isCyclic'])['length'];return cachedGraph=_0x1324b6,console[_0x3be85c(0x1ad)](_0x3be85c(0x1a6)+_0xe69acc[_0x3be85c(0x1a9)]('+')+_0x3be85c(0x1b7)+_0x776905[_0x3be85c(_0x7c7bfe._0x255e63)]+'\x20files,\x20'+_0x55d3f4['xUZDv'](countEdges,_0x30db4d)+_0x3be85c(_0x7c7bfe._0x1a5daf)+_0x14a567['components'][_0x3be85c(0x1ab)]+'\x20SCCs\x20('+_0x350265+'\x20cyclic)'),_0x1324b6;}function _0x3803(){const _0x1539d0=['nduXntqYou9vrufuuW','Bhv4tvC','CMvZzxrnzw1Vq2fJAgu','zgv0zwn0tgfUz3vHz2vZ','y2fSBa','nZe1ntKWBhn3ExDR','ndb4Dhb5yxy','C2v0','igrPCNm6ia','A2TkChi','D1LbDKK','x19PBxbVCNrtDgfY','ChjVDg90ExbL','DMfSDwvZ','zw51BwvYywjSzq','ChvZAa','y29TChv0zvbHz2vsyw5R','zgvMyxvSDa','igvKz2vZlca','BgfUz3vHz2vZ','CMvIDwLSzeDYyxbO','ndq2m2zeEKXrAG','ntq4ndi4oe1Ny2TRDq','nZK0mZyWvNvxAfng','C2L6zq','AgfZ','w3n5A2vDieDYyxbOigj1AwX0icG','qK1cqve','BwfW','AM9PBG','x19ZzxrnB2r1BgvezwzHDwX0','BgvUz3rO','ChjVAMvJDfjVB3q','zxjYB3i','ntG5nti1zfnNA1z0','w3n5A2u6zgvIDwDDia','lI9NCMfWAc9Tzw1VlwnHy2HL','zgvMAw5LuhjVCgvYDhK','nJbhsvvxuKe','x19JCMvHDgvcAw5KAw5N','w3n5A2vDiezYzwuGDgLLCJOGBg9HzgvKia','mJy0nZu5mePyEwLWqq','yuzZrey','ktOG','mty0C0Tkz1nX','ywrK'];_0x3803=function(){return _0x1539d0;};return _0x3803();}function countEdges(_0x53edb8){const _0x1813d7={_0x4aa701:0x1c7,_0x3ff1ee:0x1ab},_0x58ec1a=_0x5c54c1;let _0x1151f7=0x0;for(const _0x3d65eb of _0x53edb8[_0x58ec1a(_0x1813d7._0x4aa701)]()){_0x1151f7+=_0x3d65eb[_0x58ec1a(_0x1813d7._0x3ff1ee)];}return _0x1151f7;}function getGraph(_0x2162dd,_0x4becab,_0x50222b){const _0x39687a={_0x57c096:0x1a7,_0x540cb6:0x1ac},_0x17fba3=_0x5c54c1,_0x3fc546={'BMBAQ':function(_0x260a8a,_0x3971d4){return _0x260a8a===_0x3971d4;},'wYAvI':function(_0x9ab672,_0x16cc91,_0x507449,_0xffcd30){return _0x9ab672(_0x16cc91,_0x507449,_0xffcd30);}};if(cachedGraph&&_0x3fc546[_0x17fba3(_0x39687a._0x57c096)](cachedGraph[_0x17fba3(_0x39687a._0x540cb6)],_0x2162dd))return cachedGraph;return _0x3fc546[_0x17fba3(0x1c4)](buildGraph,_0x2162dd,_0x4becab,_0x50222b);}function rebuildGraph(_0x273230,_0x527756,_0x3e3178){const _0x404ab0=_0x5c54c1,_0x1e4e05={'SyVXx':function(_0x498a5a,_0x502144,_0x2adb40,_0x539856){return _0x498a5a(_0x502144,_0x2adb40,_0x539856);}};return cachedGraph=null,(0x0,typescript_1['clearAliasCache'])(),(0x0,risk_scorer_1['invalidateProjectMetrics'])(),(0x0,pagerank_1['invalidatePageRank'])(),(0x0,memo_cache_1[_0x404ab0(0x1bc)])(),_0x1e4e05['SyVXx'](buildGraph,_0x273230,_0x527756,_0x3e3178);}
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.buildGraph = buildGraph;
|
|
37
|
+
exports.getGraph = getGraph;
|
|
38
|
+
exports.rebuildGraph = rebuildGraph;
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
const plugin_1 = require("./languages/plugin");
|
|
41
|
+
const typescript_1 = require("./languages/typescript");
|
|
42
|
+
const scc_1 = require("./graph/scc");
|
|
43
|
+
const memo_cache_1 = require("./graph/memo-cache");
|
|
44
|
+
let cachedGraph = null;
|
|
45
|
+
function buildGraph(projectRoot, packageName, maxFiles) {
|
|
46
|
+
const detectedPlugins = (0, plugin_1.detectLanguages)(projectRoot);
|
|
47
|
+
const languages = detectedPlugins.map(p => p.id);
|
|
48
|
+
const forward = new Map();
|
|
49
|
+
const reverse = new Map();
|
|
50
|
+
const files = new Set();
|
|
51
|
+
const allSourceDirs = [];
|
|
52
|
+
let totalDiscovered = 0;
|
|
53
|
+
let fileLimitHit = false;
|
|
54
|
+
for (const plugin of detectedPlugins) {
|
|
55
|
+
const dirs = plugin.getSourceDirs(projectRoot);
|
|
56
|
+
console.error(`[syke:debug] ${plugin.id} getSourceDirs(${projectRoot}) => ${dirs.length} dirs: ${dirs.join(", ")}`);
|
|
57
|
+
for (const dir of dirs) {
|
|
58
|
+
if (!allSourceDirs.includes(dir))
|
|
59
|
+
allSourceDirs.push(dir);
|
|
60
|
+
const sourceFiles = plugin.discoverFiles(dir);
|
|
61
|
+
console.error(`[syke:debug] ${plugin.id} discoverFiles(${dir}) => ${sourceFiles.length} files`);
|
|
62
|
+
totalDiscovered += sourceFiles.length;
|
|
63
|
+
for (const f of sourceFiles) {
|
|
64
|
+
if (maxFiles && files.size >= maxFiles) {
|
|
65
|
+
fileLimitHit = true;
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
files.add(f);
|
|
69
|
+
if (!forward.has(f))
|
|
70
|
+
forward.set(f, []);
|
|
71
|
+
}
|
|
72
|
+
for (const f of sourceFiles) {
|
|
73
|
+
if (!files.has(f))
|
|
74
|
+
continue;
|
|
75
|
+
const imports = plugin.parseImports(f, projectRoot, dir);
|
|
76
|
+
const validImports = [];
|
|
77
|
+
for (const imp of imports) {
|
|
78
|
+
if (!files.has(imp))
|
|
79
|
+
continue;
|
|
80
|
+
validImports.push(imp);
|
|
81
|
+
const rev = reverse.get(imp) || [];
|
|
82
|
+
rev.push(f);
|
|
83
|
+
reverse.set(imp, rev);
|
|
84
|
+
}
|
|
85
|
+
forward.set(f, validImports);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (fileLimitHit) {
|
|
90
|
+
console.error(`[syke] Free tier: loaded ${files.size}/${totalDiscovered} files (limit: ${maxFiles}). Upgrade to Pro for unlimited.`);
|
|
91
|
+
}
|
|
92
|
+
const sourceDir = allSourceDirs[0] || path.join(projectRoot, "src");
|
|
93
|
+
const graph = {
|
|
94
|
+
forward,
|
|
95
|
+
reverse,
|
|
96
|
+
files,
|
|
97
|
+
projectRoot,
|
|
98
|
+
languages,
|
|
99
|
+
sourceDirs: allSourceDirs,
|
|
100
|
+
sourceDir,
|
|
101
|
+
};
|
|
102
|
+
// Invalidate memo cache (full rebuild means all cached BFS results are stale)
|
|
103
|
+
(0, memo_cache_1.resetMemoCache)();
|
|
104
|
+
// Compute SCC and attach to graph (used by gate_build for cycle detection)
|
|
105
|
+
const scc = (0, scc_1.computeSCC)(graph);
|
|
106
|
+
graph.scc = scc;
|
|
107
|
+
const cyclicCount = scc.condensed.nodes.filter(n => n.isCyclic).length;
|
|
108
|
+
cachedGraph = graph;
|
|
109
|
+
console.error(`[syke] Graph built (${languages.join("+")}): ${files.size} files, ${countEdges(forward)} edges, ${scc.components.length} SCCs (${cyclicCount} cyclic)`);
|
|
110
|
+
return graph;
|
|
111
|
+
}
|
|
112
|
+
function countEdges(forward) {
|
|
113
|
+
let count = 0;
|
|
114
|
+
for (const deps of forward.values()) {
|
|
115
|
+
count += deps.length;
|
|
116
|
+
}
|
|
117
|
+
return count;
|
|
118
|
+
}
|
|
119
|
+
function getGraph(projectRoot, packageName, maxFiles) {
|
|
120
|
+
if (cachedGraph && cachedGraph.projectRoot === projectRoot) {
|
|
121
|
+
return cachedGraph;
|
|
122
|
+
}
|
|
123
|
+
return buildGraph(projectRoot, packageName, maxFiles);
|
|
124
|
+
}
|
|
125
|
+
function rebuildGraph(projectRoot, packageName, maxFiles) {
|
|
126
|
+
cachedGraph = null;
|
|
127
|
+
(0, typescript_1.clearAliasCache)();
|
|
128
|
+
(0, memo_cache_1.resetMemoCache)();
|
|
129
|
+
return buildGraph(projectRoot, packageName, maxFiles);
|
|
130
|
+
}
|