@syke1/mcp-server 1.6.1 → 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/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.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 +2 -3
- 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 _0x3b4bd9=_0x188c;(function(_0x2c0528,_0x41092b){const _0x2faf51={_0x694f3:0x98,_0x10b402:0xa8,_0x1dd178:0xd2,_0x3505b8:0x9a,_0x141d55:0xa5,_0x57ab82:0xb9},_0x5c5aae=_0x188c,_0x19cfcd=_0x2c0528();while(!![]){try{const _0x125e2d=parseInt(_0x5c5aae(_0x2faf51._0x694f3))/0x1*(parseInt(_0x5c5aae(0xcc))/0x2)+-parseInt(_0x5c5aae(_0x2faf51._0x10b402))/0x3+parseInt(_0x5c5aae(_0x2faf51._0x1dd178))/0x4*(parseInt(_0x5c5aae(_0x2faf51._0x3505b8))/0x5)+parseInt(_0x5c5aae(0xd0))/0x6*(-parseInt(_0x5c5aae(_0x2faf51._0x141d55))/0x7)+-parseInt(_0x5c5aae(_0x2faf51._0x57ab82))/0x8+-parseInt(_0x5c5aae(0xd6))/0x9*(parseInt(_0x5c5aae(0x9b))/0xa)+parseInt(_0x5c5aae(0xaf))/0xb;if(_0x125e2d===_0x41092b)break;else _0x19cfcd['push'](_0x19cfcd['shift']());}catch(_0x404de9){_0x19cfcd['push'](_0x19cfcd['shift']());}}}(_0x43fb,0x4e7fe));var __createBinding=this&&this[_0x3b4bd9(0xac)]||(Object[_0x3b4bd9(0xc8)]?function(_0xbd017b,_0x396cd1,_0x197628,_0x33d19a){const _0x35637b={_0x341761:0x96,_0xa9d995:0xd9,_0x4a65a6:0xbe},_0x54a12e=_0x3b4bd9,_0x45542a={};_0x45542a['FUHUE']=function(_0x25da74,_0x60eec1){return _0x25da74===_0x60eec1;};const _0x330f84=_0x45542a;if(_0x330f84['FUHUE'](_0x33d19a,undefined))_0x33d19a=_0x197628;var _0xdc8187=Object[_0x54a12e(_0x35637b._0x341761)](_0x396cd1,_0x197628);if(!_0xdc8187||('get'in _0xdc8187?!_0x396cd1['__esModule']:_0xdc8187[_0x54a12e(_0x35637b._0xa9d995)]||_0xdc8187[_0x54a12e(0x9d)])){const _0x243e89={};_0x243e89['enumerable']=!![],_0x243e89[_0x54a12e(0xb0)]=function(){return _0x396cd1[_0x197628];},_0xdc8187=_0x243e89;}Object[_0x54a12e(_0x35637b._0x4a65a6)](_0xbd017b,_0x33d19a,_0xdc8187);}:function(_0x1d5923,_0x567314,_0x55cb21,_0x31fd43){if(_0x31fd43===undefined)_0x31fd43=_0x55cb21;_0x1d5923[_0x31fd43]=_0x567314[_0x55cb21];}),__setModuleDefault=this&&this['__setModuleDefault']||(Object['create']?function(_0x47077f,_0x3848d7){const _0x38447d=_0x3b4bd9,_0x38d209={};_0x38d209[_0x38447d(0xa2)]=!![],_0x38d209[_0x38447d(0xcb)]=_0x3848d7,Object['defineProperty'](_0x47077f,'default',_0x38d209);}:function(_0x2509d1,_0x23d73c){const _0x54041e=_0x3b4bd9,_0x368922={};_0x368922[_0x54041e(0x97)]=_0x54041e(0x9c);const _0x7db487=_0x368922;_0x2509d1[_0x7db487['xUvLY']]=_0x23d73c;}),__importStar=this&&this[_0x3b4bd9(0xc9)]||(function(){const _0x367625={_0x33e383:0xa7,_0x1e647a:0xd1,_0x181f6d:0xb3},_0x57e01d={_0x5419ce:0xbc},_0x29df7f=_0x3b4bd9,_0x5c3247={'vUJFM':_0x29df7f(0xb5),'bZANs':function(_0x334013,_0x122ebe){return _0x334013!=_0x122ebe;},'LqtVk':function(_0x4a9616,_0x1ad3b9){return _0x4a9616(_0x1ad3b9);},'VHWSb':function(_0xe0561,_0x589f26){return _0xe0561<_0x589f26;},'uczbg':function(_0x3ffe33,_0x9c9108){return _0x3ffe33!==_0x9c9108;},'GEftR':function(_0x1aa4f0,_0x4de556,_0x45d0dc,_0x21055b){return _0x1aa4f0(_0x4de556,_0x45d0dc,_0x21055b);},'dxmLQ':function(_0x44bb3f,_0x212cb5,_0x580ea3){return _0x44bb3f(_0x212cb5,_0x580ea3);}};var _0x342378=function(_0x4f5979){const _0x2dc709=_0x29df7f;return _0x342378=Object[_0x2dc709(0x9e)]||function(_0x4136cd){const _0x54dd61=_0x2dc709;var _0x426630=[];for(var _0x13ebd1 in _0x4136cd)if(Object[_0x54dd61(_0x57e01d._0x5419ce)]['hasOwnProperty']['call'](_0x4136cd,_0x13ebd1))_0x426630[_0x426630['length']]=_0x13ebd1;return _0x426630;},_0x342378(_0x4f5979);};return function(_0x35268d){const _0x46f65c=_0x29df7f,_0x72afe4=_0x5c3247[_0x46f65c(0xca)]['split']('|');let _0x4ee77d=0x0;while(!![]){switch(_0x72afe4[_0x4ee77d++]){case'0':if(_0x5c3247[_0x46f65c(_0x367625._0x33e383)](_0x35268d,null)){for(var _0x4f9154=_0x5c3247['LqtVk'](_0x342378,_0x35268d),_0x41394a=0x0;_0x5c3247[_0x46f65c(_0x367625._0x1e647a)](_0x41394a,_0x4f9154['length']);_0x41394a++)if(_0x5c3247[_0x46f65c(_0x367625._0x181f6d)](_0x4f9154[_0x41394a],_0x46f65c(0x9c)))_0x5c3247[_0x46f65c(0xc3)](__createBinding,_0x2c1bca,_0x35268d,_0x4f9154[_0x41394a]);}continue;case'1':var _0x2c1bca={};continue;case'2':return _0x2c1bca;case'3':_0x5c3247['dxmLQ'](__setModuleDefault,_0x2c1bca,_0x35268d);continue;case'4':if(_0x35268d&&_0x35268d['__esModule'])return _0x35268d;continue;}break;}};}());const _0x475210={};_0x475210['value']=!![],Object[_0x3b4bd9(0xbe)](exports,_0x3b4bd9(0xd7),_0x475210),exports['buildGraph']=buildGraph,exports[_0x3b4bd9(0x9f)]=getGraph,exports[_0x3b4bd9(0xcd)]=rebuildGraph;const path=__importStar(require(_0x3b4bd9(0xd5))),plugin_1=require(_0x3b4bd9(0xb6)),typescript_1=require('./languages/typescript'),scc_1=require(_0x3b4bd9(0xae)),risk_scorer_1=require('./scoring/risk-scorer'),pagerank_1=require(_0x3b4bd9(0xbd)),memo_cache_1=require(_0x3b4bd9(0xd3));let cachedGraph=null;function buildGraph(_0x58ff0e,_0x33b409,_0xd70d6){const _0x2ca28d={_0x5f5a7c:0xd4,_0xeb9a4a:0xa4,_0x8aea80:0xb4,_0x264f02:0xce,_0xe0ebf8:0xab,_0x23641d:0xad,_0x5f57ea:0xba,_0x2d9e07:0xb2,_0x55c462:0xdc,_0x2df3ef:0xc0,_0x515e03:0xa9,_0x46ee78:0xc7,_0x26b219:0xb8,_0x49f165:0xcf,_0x20d01a:0xdb,_0xc5b9f6:0xc6,_0xbe74a3:0x99,_0x4f72a1:0xc1,_0x711d66:0xa3},_0x3b03b0=_0x3b4bd9,_0x33fc88=(0x0,plugin_1[_0x3b03b0(0xd8)])(_0x58ff0e),_0x30f5b8=_0x33fc88[_0x3b03b0(0xc4)](_0x1cd9e8=>_0x1cd9e8['id']),_0x553d5a=new Map(),_0x376905=new Map(),_0x2eb1e4=new Set(),_0xfb86e6=[];let _0x28c179=0x0,_0x40533b=![];for(const _0x3127de of _0x33fc88){const _0x2a5eab=_0x3127de['getSourceDirs'](_0x58ff0e);console['error'](_0x3b03b0(_0x2ca28d._0x5f5a7c)+_0x3127de['id']+_0x3b03b0(0xc2)+_0x58ff0e+')\x20=>\x20'+_0x2a5eab[_0x3b03b0(0xad)]+_0x3b03b0(_0x2ca28d._0xeb9a4a)+_0x2a5eab[_0x3b03b0(_0x2ca28d._0x8aea80)](',\x20'));for(const _0x139438 of _0x2a5eab){if(!_0xfb86e6['includes'](_0x139438))_0xfb86e6[_0x3b03b0(_0x2ca28d._0x264f02)](_0x139438);const _0x35935d=_0x3127de['discoverFiles'](_0x139438);console[_0x3b03b0(0xb1)](_0x3b03b0(0xd4)+_0x3127de['id']+_0x3b03b0(_0x2ca28d._0xe0ebf8)+_0x139438+')\x20=>\x20'+_0x35935d[_0x3b03b0(_0x2ca28d._0x23641d)]+_0x3b03b0(_0x2ca28d._0x5f57ea)),_0x28c179+=_0x35935d[_0x3b03b0(0xad)];for(const _0x555a09 of _0x35935d){if(_0xd70d6&&_0x2eb1e4[_0x3b03b0(_0x2ca28d._0x2d9e07)]>=_0xd70d6){_0x40533b=!![];break;}_0x2eb1e4['add'](_0x555a09);if(!_0x553d5a['has'](_0x555a09))_0x553d5a[_0x3b03b0(_0x2ca28d._0x55c462)](_0x555a09,[]);}for(const _0x571587 of _0x35935d){if(!_0x2eb1e4['has'](_0x571587))continue;const _0x11e6b2=_0x3127de['parseImports'](_0x571587,_0x58ff0e,_0x139438),_0x4b0a22=[];for(const _0x5a30b2 of _0x11e6b2){if(!_0x2eb1e4[_0x3b03b0(0xc5)](_0x5a30b2))continue;_0x4b0a22['push'](_0x5a30b2);const _0x4f3915=_0x376905['get'](_0x5a30b2)||[];_0x4f3915['push'](_0x571587),_0x376905['set'](_0x5a30b2,_0x4f3915);}_0x553d5a[_0x3b03b0(_0x2ca28d._0x55c462)](_0x571587,_0x4b0a22);}}}_0x40533b&&console['error'](_0x3b03b0(_0x2ca28d._0x2df3ef)+_0x2eb1e4['size']+'/'+_0x28c179+'\x20files\x20(limit:\x20'+_0xd70d6+').\x20Upgrade\x20to\x20Pro\x20for\x20unlimited.');const _0x5f1e2d=_0xfb86e6[0x0]||path['join'](_0x58ff0e,'src'),_0xee3770={};_0xee3770[_0x3b03b0(_0x2ca28d._0x515e03)]=_0x553d5a,_0xee3770['reverse']=_0x376905,_0xee3770[_0x3b03b0(0xa1)]=_0x2eb1e4,_0xee3770[_0x3b03b0(0xa0)]=_0x58ff0e,_0xee3770[_0x3b03b0(_0x2ca28d._0x46ee78)]=_0x30f5b8,_0xee3770[_0x3b03b0(0xaa)]=_0xfb86e6,_0xee3770[_0x3b03b0(0xbb)]=_0x5f1e2d;const _0x42ce74=_0xee3770;(0x0,memo_cache_1['resetMemoCache'])();const _0x1cca7e=(0x0,scc_1[_0x3b03b0(_0x2ca28d._0x26b219)])(_0x42ce74);_0x42ce74[_0x3b03b0(_0x2ca28d._0x49f165)]=_0x1cca7e,(0x0,pagerank_1['invalidatePageRank'])(),_0x42ce74[_0x3b03b0(_0x2ca28d._0x20d01a)]=(0x0,pagerank_1['computePageRank'])(_0x42ce74);const _0x1c52a9=_0x1cca7e[_0x3b03b0(0xbf)][_0x3b03b0(_0x2ca28d._0xc5b9f6)][_0x3b03b0(_0x2ca28d._0xbe74a3)](_0x2de8c4=>_0x2de8c4['isCyclic'])['length'];return cachedGraph=_0x42ce74,console[_0x3b03b0(0xb1)]('[syke]\x20Graph\x20built\x20('+_0x30f5b8['join']('+')+'):\x20'+_0x2eb1e4['size']+_0x3b03b0(0xda)+countEdges(_0x553d5a)+_0x3b03b0(_0x2ca28d._0x4f72a1)+_0x1cca7e['components']['length']+_0x3b03b0(0xb7)+_0x1c52a9+_0x3b03b0(_0x2ca28d._0x711d66)),_0x42ce74;}function countEdges(_0x1e96df){const _0x330607=_0x3b4bd9;let _0x455619=0x0;for(const _0x55f5b2 of _0x1e96df['values']()){_0x455619+=_0x55f5b2[_0x330607(0xad)];}return _0x455619;}function getGraph(_0x3e3ce3,_0x1c39bd,_0x43b75f){if(cachedGraph&&cachedGraph['projectRoot']===_0x3e3ce3)return cachedGraph;return buildGraph(_0x3e3ce3,_0x1c39bd,_0x43b75f);}function _0x188c(_0x129ae3,_0x31be1b){_0x129ae3=_0x129ae3-0x96;const _0x43fbdd=_0x43fb();let _0x188c84=_0x43fbdd[_0x129ae3];if(_0x188c['FFNybA']===undefined){var _0x540bfc=function(_0x46c724){const _0x1b4d7a='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x5a92bc='',_0x1f6dcc='';for(let _0x444bde=0x0,_0xcced06,_0x3d7a13,_0xb2f484=0x0;_0x3d7a13=_0x46c724['charAt'](_0xb2f484++);~_0x3d7a13&&(_0xcced06=_0x444bde%0x4?_0xcced06*0x40+_0x3d7a13:_0x3d7a13,_0x444bde++%0x4)?_0x5a92bc+=String['fromCharCode'](0xff&_0xcced06>>(-0x2*_0x444bde&0x6)):0x0){_0x3d7a13=_0x1b4d7a['indexOf'](_0x3d7a13);}for(let _0x3a3e1a=0x0,_0x19620b=_0x5a92bc['length'];_0x3a3e1a<_0x19620b;_0x3a3e1a++){_0x1f6dcc+='%'+('00'+_0x5a92bc['charCodeAt'](_0x3a3e1a)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x1f6dcc);};_0x188c['vZFfEH']=_0x540bfc,_0x188c['BxQLpo']={},_0x188c['FFNybA']=!![];}const _0x245119=_0x43fbdd[0x0],_0x5e2e20=_0x129ae3+_0x245119,_0x1dfbee=_0x188c['BxQLpo'][_0x5e2e20];return!_0x1dfbee?(_0x188c84=_0x188c['vZFfEH'](_0x188c84),_0x188c['BxQLpo'][_0x5e2e20]=_0x188c84):_0x188c84=_0x1dfbee,_0x188c84;}function rebuildGraph(_0x4336ab,_0x6f0263,_0x2f7cf3){const _0x457259=_0x3b4bd9;return cachedGraph=null,(0x0,typescript_1['clearAliasCache'])(),(0x0,risk_scorer_1['invalidateProjectMetrics'])(),(0x0,pagerank_1['invalidatePageRank'])(),(0x0,memo_cache_1[_0x457259(0xa6)])(),buildGraph(_0x4336ab,_0x6f0263,_0x2f7cf3);}function _0x43fb(){const _0x3ed616=['zM9YD2fYza','C291CMnLrgLYCW','igrPC2nVDMvYrMLSzxmO','x19JCMvHDgvcAw5KAw5N','BgvUz3rO','lI9NCMfWAc9Zy2m','mta0mdi2mJnHAKzjsLK','z2v0','zxjYB3i','C2L6zq','Dwn6yMC','AM9PBG','nhWXFdb8m3WY','lI9Syw5NDwfNzxmVCgX1z2LU','ifndq3mGka','y29TChv0zvndqW','mZq1nZa0A1zKs1zR','igzPBgvZ','C291CMnLrgLY','ChjVDg90ExbL','lI9Zy29YAw5Nl3bHz2vYyw5R','zgvMAw5LuhjVCgvYDhK','y29UzgvUC2vK','w3n5A2vDiezYzwuGDgLLCJOGBg9HzgvKia','igvKz2vZlca','igDLDfnVDxjJzurPCNmO','r0vMDfi','BwfW','AgfZ','BM9Kzxm','BgfUz3vHz2vZ','y3jLyxrL','x19PBxbVCNrtDgfY','DLvkrK0','DMfSDwu','mtbZDhDkvMu','CMvIDwLSzeDYyxbO','ChvZAa','C2nJ','mZzdq1nADxu','vKHxu2i','ntCXndH2C2zsDLO','lI9NCMfWAc9Tzw1VlwnHy2HL','w3n5A2u6zgvIDwDDia','Cgf0Aa','ntm1mdCWn0LJDNzcta','x19LC01VzhvSzq','zgv0zwn0tgfUz3vHz2vZ','D3jPDgfIBgu','igzPBgvZlca','CgfNzvjHBMS','C2v0','z2v0t3DUuhjVCgvYDhLezxnJCMLWDg9Y','Efv2tfK','otC0mtvVCwf2D3y','zMLSDgvY','mta1BwrtEwrl','mtbPDujAsuq','zgvMyxvSDa','y29UzMLNDxjHyMXL','z2v0t3DUuhjVCgvYDhLoyw1LCW','z2v0r3jHCgG','ChjVAMvJDfjVB3q','zMLSzxm','zw51BwvYywjSzq','ign5y2XPyYK','igrPCNm6ia','mZuXodi3u3ndC3vs','CMvZzxrnzw1Vq2fJAgu','yLPbtNm','mtqXntG3n2zPq3LIqG'];_0x43fb=function(){return _0x3ed616;};return _0x43fb();}
|
|
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
|
+
}
|