@syke1/mcp-server 1.6.1 → 1.7.1
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 +813 -1
- package/dist/license/validator.js +344 -1
- package/dist/remote/proxy.d.ts +30 -0
- package/dist/remote/proxy.js +192 -0
- package/dist/remote/types.d.ts +70 -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
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Remote proxy for SYKE Pro tools.
|
|
4
|
+
*
|
|
5
|
+
* Serializes the local dependency graph and sends it to Firebase Cloud Functions
|
|
6
|
+
* for server-side Pro analysis. The user experience is transparent — same tools,
|
|
7
|
+
* same output format, just executed on the server.
|
|
8
|
+
*/
|
|
9
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
12
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
13
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
14
|
+
}
|
|
15
|
+
Object.defineProperty(o, k2, desc);
|
|
16
|
+
}) : (function(o, m, k, k2) {
|
|
17
|
+
if (k2 === undefined) k2 = k;
|
|
18
|
+
o[k2] = m[k];
|
|
19
|
+
}));
|
|
20
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
21
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
22
|
+
}) : function(o, v) {
|
|
23
|
+
o["default"] = v;
|
|
24
|
+
});
|
|
25
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
26
|
+
var ownKeys = function(o) {
|
|
27
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
28
|
+
var ar = [];
|
|
29
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
30
|
+
return ar;
|
|
31
|
+
};
|
|
32
|
+
return ownKeys(o);
|
|
33
|
+
};
|
|
34
|
+
return function (mod) {
|
|
35
|
+
if (mod && mod.__esModule) return mod;
|
|
36
|
+
var result = {};
|
|
37
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
38
|
+
__setModuleDefault(result, mod);
|
|
39
|
+
return result;
|
|
40
|
+
};
|
|
41
|
+
})();
|
|
42
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
|
+
exports.serializeGraph = serializeGraph;
|
|
44
|
+
exports.remoteAnalyzeImpact = remoteAnalyzeImpact;
|
|
45
|
+
exports.remoteGetHubFiles = remoteGetHubFiles;
|
|
46
|
+
exports.remoteValidateLicense = remoteValidateLicense;
|
|
47
|
+
const https = __importStar(require("https"));
|
|
48
|
+
const path = __importStar(require("path"));
|
|
49
|
+
const config_1 = require("../config");
|
|
50
|
+
// ── Constants ──
|
|
51
|
+
const BASE_URL = "https://us-central1-syke-cloud.cloudfunctions.net";
|
|
52
|
+
const ENDPOINTS = {
|
|
53
|
+
analyzeImpact: `${BASE_URL}/proAnalyzeImpact`,
|
|
54
|
+
getHubFiles: `${BASE_URL}/proGetHubFiles`,
|
|
55
|
+
};
|
|
56
|
+
// ── Graph Serialization ──
|
|
57
|
+
/**
|
|
58
|
+
* Serialize a DependencyGraph into a GraphBundle for transmission.
|
|
59
|
+
* Converts absolute paths to relative paths (relative to sourceDir)
|
|
60
|
+
* to minimize payload size and avoid leaking local paths.
|
|
61
|
+
*/
|
|
62
|
+
function serializeGraph(graph) {
|
|
63
|
+
const toRel = (f) => path.relative(graph.sourceDir, f).replace(/\\/g, "/");
|
|
64
|
+
const files = [];
|
|
65
|
+
for (const f of graph.files) {
|
|
66
|
+
files.push(toRel(f));
|
|
67
|
+
}
|
|
68
|
+
const forward = {};
|
|
69
|
+
for (const [file, deps] of graph.forward) {
|
|
70
|
+
const rel = toRel(file);
|
|
71
|
+
forward[rel] = deps.map(toRel);
|
|
72
|
+
}
|
|
73
|
+
const reverse = {};
|
|
74
|
+
for (const [file, deps] of graph.reverse) {
|
|
75
|
+
const rel = toRel(file);
|
|
76
|
+
reverse[rel] = deps.map(toRel);
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
files,
|
|
80
|
+
forward,
|
|
81
|
+
reverse,
|
|
82
|
+
languages: graph.languages,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
// ── HTTP Client ──
|
|
86
|
+
function postJSON(url, body) {
|
|
87
|
+
return new Promise((resolve, reject) => {
|
|
88
|
+
const data = JSON.stringify(body);
|
|
89
|
+
const parsed = new URL(url);
|
|
90
|
+
const options = {
|
|
91
|
+
hostname: parsed.hostname,
|
|
92
|
+
port: 443,
|
|
93
|
+
path: parsed.pathname + parsed.search,
|
|
94
|
+
method: "POST",
|
|
95
|
+
headers: {
|
|
96
|
+
"Content-Type": "application/json",
|
|
97
|
+
"Content-Length": Buffer.byteLength(data),
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
const req = https.request(options, (res) => {
|
|
101
|
+
let responseData = "";
|
|
102
|
+
res.on("data", (chunk) => { responseData += chunk; });
|
|
103
|
+
res.on("end", () => {
|
|
104
|
+
try {
|
|
105
|
+
const json = JSON.parse(responseData);
|
|
106
|
+
if (res.statusCode && res.statusCode >= 400) {
|
|
107
|
+
reject(new Error(json.error || `HTTP ${res.statusCode}`));
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
resolve(json);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
reject(new Error(`Invalid response: ${responseData.substring(0, 200)}`));
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
req.on("error", reject);
|
|
119
|
+
req.setTimeout(60000, () => {
|
|
120
|
+
req.destroy();
|
|
121
|
+
reject(new Error("Request timeout (60s)"));
|
|
122
|
+
});
|
|
123
|
+
req.write(data);
|
|
124
|
+
req.end();
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
// ── License + Device Info ──
|
|
128
|
+
function getLicenseKey() {
|
|
129
|
+
return (0, config_1.getConfig)("licenseKey", "SYKE_LICENSE_KEY");
|
|
130
|
+
}
|
|
131
|
+
function getDeviceId() {
|
|
132
|
+
const os = require("os");
|
|
133
|
+
const crypto = require("crypto");
|
|
134
|
+
const raw = `${os.hostname()}:${os.userInfo().username}:${process.platform}:${os.arch()}`;
|
|
135
|
+
return crypto.createHash("sha256").update(raw).digest("hex").substring(0, 16);
|
|
136
|
+
}
|
|
137
|
+
// ── Public API ──
|
|
138
|
+
/**
|
|
139
|
+
* Remote analyze_impact: sends graph + target file to server.
|
|
140
|
+
*/
|
|
141
|
+
async function remoteAnalyzeImpact(graph, resolvedFilePath, options) {
|
|
142
|
+
const licenseKey = getLicenseKey();
|
|
143
|
+
if (!licenseKey) {
|
|
144
|
+
throw new Error("No license key configured");
|
|
145
|
+
}
|
|
146
|
+
const graphBundle = serializeGraph(graph);
|
|
147
|
+
const targetFile = path.relative(graph.sourceDir, resolvedFilePath).replace(/\\/g, "/");
|
|
148
|
+
const result = await postJSON(ENDPOINTS.analyzeImpact, {
|
|
149
|
+
licenseKey,
|
|
150
|
+
deviceId: getDeviceId(),
|
|
151
|
+
graphBundle,
|
|
152
|
+
targetFile,
|
|
153
|
+
options: { includeRiskScore: options?.includeRiskScore !== false },
|
|
154
|
+
});
|
|
155
|
+
return result;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Remote get_hub_files: sends graph to server for PageRank analysis.
|
|
159
|
+
*/
|
|
160
|
+
async function remoteGetHubFiles(graph, topN = 10) {
|
|
161
|
+
const licenseKey = getLicenseKey();
|
|
162
|
+
if (!licenseKey) {
|
|
163
|
+
throw new Error("No license key configured");
|
|
164
|
+
}
|
|
165
|
+
const graphBundle = serializeGraph(graph);
|
|
166
|
+
const result = await postJSON(ENDPOINTS.getHubFiles, {
|
|
167
|
+
licenseKey,
|
|
168
|
+
deviceId: getDeviceId(),
|
|
169
|
+
graphBundle,
|
|
170
|
+
topN,
|
|
171
|
+
});
|
|
172
|
+
return result;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Remote license validation only (for refresh_graph, check_warnings).
|
|
176
|
+
* Returns true if the license is valid Pro.
|
|
177
|
+
*/
|
|
178
|
+
async function remoteValidateLicense() {
|
|
179
|
+
const licenseKey = getLicenseKey();
|
|
180
|
+
if (!licenseKey)
|
|
181
|
+
return false;
|
|
182
|
+
try {
|
|
183
|
+
const result = await postJSON(`${BASE_URL}/validateLicenseKey`, {
|
|
184
|
+
key: licenseKey,
|
|
185
|
+
deviceId: getDeviceId(),
|
|
186
|
+
});
|
|
187
|
+
return result.valid === true;
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for SYKE Remote Pro Analysis.
|
|
3
|
+
*
|
|
4
|
+
* GraphBundle is the serialization format sent from the local MCP server
|
|
5
|
+
* to Firebase Cloud Functions for server-side Pro analysis.
|
|
6
|
+
*/
|
|
7
|
+
export interface GraphBundle {
|
|
8
|
+
/** Relative file paths (relative to project root) */
|
|
9
|
+
files: string[];
|
|
10
|
+
/** Forward dependencies: file → files it imports */
|
|
11
|
+
forward: Record<string, string[]>;
|
|
12
|
+
/** Reverse dependencies: file → files that import it */
|
|
13
|
+
reverse: Record<string, string[]>;
|
|
14
|
+
/** Detected language plugin IDs */
|
|
15
|
+
languages: string[];
|
|
16
|
+
}
|
|
17
|
+
export interface RemoteAnalyzeImpactRequest {
|
|
18
|
+
licenseKey: string;
|
|
19
|
+
deviceId: string;
|
|
20
|
+
graphBundle: GraphBundle;
|
|
21
|
+
targetFile: string;
|
|
22
|
+
options?: {
|
|
23
|
+
includeRiskScore?: boolean;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export interface RemoteAnalyzeImpactResponse {
|
|
27
|
+
riskLevel: string;
|
|
28
|
+
totalImpacted: number;
|
|
29
|
+
directDependents: string[];
|
|
30
|
+
transitiveDependents: string[];
|
|
31
|
+
cascadeLevels?: Record<string, number>;
|
|
32
|
+
circularCluster?: string[];
|
|
33
|
+
sccCount?: number;
|
|
34
|
+
cyclicSCCs?: number;
|
|
35
|
+
riskScore?: {
|
|
36
|
+
composite: number;
|
|
37
|
+
fanIn: number;
|
|
38
|
+
fanOut: number;
|
|
39
|
+
transitiveFanIn: number;
|
|
40
|
+
instability: number;
|
|
41
|
+
complexity: number;
|
|
42
|
+
normalizedComplexity: number;
|
|
43
|
+
cascadeDepth: number;
|
|
44
|
+
riskLevel: string;
|
|
45
|
+
pageRank?: number;
|
|
46
|
+
pageRankPercentile?: number;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
export interface RemoteGetHubFilesRequest {
|
|
50
|
+
licenseKey: string;
|
|
51
|
+
deviceId: string;
|
|
52
|
+
graphBundle: GraphBundle;
|
|
53
|
+
topN?: number;
|
|
54
|
+
}
|
|
55
|
+
export interface RemoteGetHubFilesResponse {
|
|
56
|
+
hubs: Array<{
|
|
57
|
+
relativePath: string;
|
|
58
|
+
dependentCount: number;
|
|
59
|
+
riskLevel: string;
|
|
60
|
+
pageRank?: number;
|
|
61
|
+
pageRankPercentile?: number;
|
|
62
|
+
riskScore?: number;
|
|
63
|
+
riskScoreLevel?: string;
|
|
64
|
+
}>;
|
|
65
|
+
totalFiles: number;
|
|
66
|
+
}
|
|
67
|
+
export interface RemoteError {
|
|
68
|
+
error: string;
|
|
69
|
+
code?: string;
|
|
70
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Types for SYKE Remote Pro Analysis.
|
|
4
|
+
*
|
|
5
|
+
* GraphBundle is the serialization format sent from the local MCP server
|
|
6
|
+
* to Firebase Cloud Functions for server-side Pro analysis.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { DependencyGraph } from "../graph";
|
|
2
|
-
import { RiskScore } from "../scoring/risk-scorer";
|
|
3
2
|
import { MemoCache } from "../graph/memo-cache";
|
|
4
3
|
export type RiskLevel = "HIGH" | "MEDIUM" | "LOW" | "NONE";
|
|
5
4
|
export interface CoupledFileInfo {
|
|
@@ -23,8 +22,6 @@ export interface ImpactResult {
|
|
|
23
22
|
sccCount?: number;
|
|
24
23
|
/** Number of SCCs with more than one file (circular dependencies) */
|
|
25
24
|
cyclicSCCs?: number;
|
|
26
|
-
/** Composite risk score (0-1) combining multiple signals */
|
|
27
|
-
riskScore?: RiskScore;
|
|
28
25
|
/** Files that historically co-change but may not be in the dependency graph */
|
|
29
26
|
coupledFiles?: CoupledFileInfo[];
|
|
30
27
|
/** True if the BFS result came from the memo cache (fast path) */
|
|
@@ -38,9 +35,12 @@ export interface ImpactResult {
|
|
|
38
35
|
* Optionally computes a composite risk score when `includeRiskScore` is true.
|
|
39
36
|
* Optionally computes historical change coupling when `includeCoupling` is true.
|
|
40
37
|
*/
|
|
38
|
+
/**
|
|
39
|
+
* Local BFS impact analysis — used by BYOK ai_analyze and web dashboard.
|
|
40
|
+
* Risk scoring is now server-side (Pro). This function provides basic
|
|
41
|
+
* BFS traversal and SCC-enhanced cascade analysis.
|
|
42
|
+
*/
|
|
41
43
|
export declare function analyzeImpact(filePath: string, graph: DependencyGraph, options?: {
|
|
42
|
-
includeRiskScore?: boolean;
|
|
43
|
-
fileContent?: string | null;
|
|
44
44
|
includeCoupling?: boolean;
|
|
45
45
|
}): Promise<ImpactResult>;
|
|
46
46
|
/**
|
|
@@ -1 +1,326 @@
|
|
|
1
|
-
'use strict';function _0x1634(_0x4bd50d,_0x4193ff){_0x4bd50d=_0x4bd50d-0xd3;const _0x2475af=_0x2475();let _0x163490=_0x2475af[_0x4bd50d];if(_0x1634['MPKLOu']===undefined){var _0x58954c=function(_0x3007c0){const _0x2a78c8='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x42c67a='',_0x383edb='';for(let _0x4cb433=0x0,_0x3b99a0,_0x227d70,_0x185ccb=0x0;_0x227d70=_0x3007c0['charAt'](_0x185ccb++);~_0x227d70&&(_0x3b99a0=_0x4cb433%0x4?_0x3b99a0*0x40+_0x227d70:_0x227d70,_0x4cb433++%0x4)?_0x42c67a+=String['fromCharCode'](0xff&_0x3b99a0>>(-0x2*_0x4cb433&0x6)):0x0){_0x227d70=_0x2a78c8['indexOf'](_0x227d70);}for(let _0xef5e8c=0x0,_0x374aef=_0x42c67a['length'];_0xef5e8c<_0x374aef;_0xef5e8c++){_0x383edb+='%'+('00'+_0x42c67a['charCodeAt'](_0xef5e8c)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x383edb);};_0x1634['NhOvth']=_0x58954c,_0x1634['sYEQis']={},_0x1634['MPKLOu']=!![];}const _0x3b011b=_0x2475af[0x0],_0x3eabc7=_0x4bd50d+_0x3b011b,_0x5d0f2e=_0x1634['sYEQis'][_0x3eabc7];return!_0x5d0f2e?(_0x163490=_0x1634['NhOvth'](_0x163490),_0x1634['sYEQis'][_0x3eabc7]=_0x163490):_0x163490=_0x5d0f2e,_0x163490;}const _0x1294da=_0x1634;(function(_0x29a63e,_0x5ec2df){const _0x3276e5={_0x4caf1d:0xf7,_0x1e9b97:0xda,_0x5c49ce:0x117},_0x4b8e80=_0x1634,_0x20fc03=_0x29a63e();while(!![]){try{const _0x5c2c47=parseInt(_0x4b8e80(0x134))/0x1*(-parseInt(_0x4b8e80(0x131))/0x2)+-parseInt(_0x4b8e80(_0x3276e5._0x4caf1d))/0x3+parseInt(_0x4b8e80(0xeb))/0x4*(-parseInt(_0x4b8e80(_0x3276e5._0x1e9b97))/0x5)+-parseInt(_0x4b8e80(_0x3276e5._0x5c49ce))/0x6*(parseInt(_0x4b8e80(0x127))/0x7)+-parseInt(_0x4b8e80(0xe7))/0x8*(parseInt(_0x4b8e80(0xed))/0x9)+parseInt(_0x4b8e80(0x114))/0xa+parseInt(_0x4b8e80(0xe3))/0xb;if(_0x5c2c47===_0x5ec2df)break;else _0x20fc03['push'](_0x20fc03['shift']());}catch(_0x46c493){_0x20fc03['push'](_0x20fc03['shift']());}}}(_0x2475,0x644bb));var __createBinding=this&&this[_0x1294da(0xe0)]||(Object['create']?function(_0x2d3461,_0xb61f7d,_0xe6e9e6,_0x1093d0){const _0x4f0548={_0x501652:0x125,_0x34dbfb:0xfe,_0x3fd92a:0x12d,_0x96804b:0x102},_0x108440=_0x1294da,_0x49b1bf={};_0x49b1bf[_0x108440(_0x4f0548._0x501652)]=function(_0x10db8a,_0x299a95){return _0x10db8a in _0x299a95;},_0x49b1bf[_0x108440(_0x4f0548._0x34dbfb)]=_0x108440(_0x4f0548._0x3fd92a);const _0x110f72=_0x49b1bf;if(_0x1093d0===undefined)_0x1093d0=_0xe6e9e6;var _0x1be1a7=Object[_0x108440(0xfd)](_0xb61f7d,_0xe6e9e6);if(!_0x1be1a7||(_0x110f72['EWypJ'](_0x110f72['EIGbx'],_0x1be1a7)?!_0xb61f7d['__esModule']:_0x1be1a7[_0x108440(0xef)]||_0x1be1a7[_0x108440(0x103)])){const _0x222c4f={};_0x222c4f[_0x108440(_0x4f0548._0x96804b)]=!![],_0x222c4f[_0x108440(0x12d)]=function(){return _0xb61f7d[_0xe6e9e6];},_0x1be1a7=_0x222c4f;}Object[_0x108440(0x123)](_0x2d3461,_0x1093d0,_0x1be1a7);}:function(_0x16f7f5,_0x501d33,_0x449705,_0x3f4293){if(_0x3f4293===undefined)_0x3f4293=_0x449705;_0x16f7f5[_0x3f4293]=_0x501d33[_0x449705];}),__setModuleDefault=this&&this[_0x1294da(0x110)]||(Object['create']?function(_0x3efbbe,_0x15d755){const _0x139712={_0x207c00:0xd5,_0x4a8aa2:0x12a},_0x4fd1fa=_0x1294da,_0x5907da={};_0x5907da['vIUxv']=_0x4fd1fa(_0x139712._0x207c00);const _0x3a127b=_0x5907da,_0xfb4e08={};_0xfb4e08[_0x4fd1fa(0x102)]=!![],_0xfb4e08[_0x4fd1fa(0x12e)]=_0x15d755,Object['defineProperty'](_0x3efbbe,_0x3a127b[_0x4fd1fa(_0x139712._0x4a8aa2)],_0xfb4e08);}:function(_0x256c31,_0x311352){const _0x364824={_0x56d408:0xd5,_0x15759d:0x129},_0x32caad=_0x1294da,_0xfab62f={};_0xfab62f['yeAhB']=_0x32caad(_0x364824._0x56d408);const _0x19b034=_0xfab62f;_0x256c31[_0x19b034[_0x32caad(_0x364824._0x15759d)]]=_0x311352;}),__importStar=this&&this[_0x1294da(0x126)]||(function(){const _0x36fa8a={_0x99597f:0xd6,_0x271954:0x128,_0x1d7987:0xfb},_0x1a3051={_0x133753:0x10a},_0x1b626b={_0x2e6731:0xd9},_0x50237a=_0x1294da,_0x3ebf6a={'zhljh':function(_0x59faf8,_0x226877){return _0x59faf8(_0x226877);},'lMzeX':_0x50237a(0x104),'xPFbo':function(_0x5585f0,_0x1b65d6){return _0x5585f0!=_0x1b65d6;},'kmJKJ':function(_0x3b0edf,_0x24b848){return _0x3b0edf<_0x24b848;},'FyVmt':function(_0x1de626,_0x19beab,_0x3db281,_0x438a39){return _0x1de626(_0x19beab,_0x3db281,_0x438a39);},'Pctmg':function(_0x261d0b,_0x4529c3,_0xf7d019){return _0x261d0b(_0x4529c3,_0xf7d019);}};var _0x1e84f4=function(_0x142d40){const _0x58a70c=_0x50237a;return _0x1e84f4=Object[_0x58a70c(_0x1a3051._0x133753)]||function(_0x5d26fd){const _0x432862=_0x58a70c;var _0x330357=[];for(var _0x1b4213 in _0x5d26fd)if(Object[_0x432862(_0x1b626b._0x2e6731)]['hasOwnProperty']['call'](_0x5d26fd,_0x1b4213))_0x330357[_0x330357[_0x432862(0x128)]]=_0x1b4213;return _0x330357;},_0x3ebf6a[_0x58a70c(0xde)](_0x1e84f4,_0x142d40);};return function(_0x51ea04){const _0x3fcf9a=_0x50237a,_0x4c49d3=_0x3ebf6a[_0x3fcf9a(0x11d)][_0x3fcf9a(0xdc)]('|');let _0x12b746=0x0;while(!![]){switch(_0x4c49d3[_0x12b746++]){case'0':return _0x2131c7;case'1':var _0x2131c7={};continue;case'2':if(_0x3ebf6a['xPFbo'](_0x51ea04,null)){for(var _0x240971=_0x1e84f4(_0x51ea04),_0x6a0004=0x0;_0x3ebf6a[_0x3fcf9a(_0x36fa8a._0x99597f)](_0x6a0004,_0x240971[_0x3fcf9a(_0x36fa8a._0x271954)]);_0x6a0004++)if(_0x240971[_0x6a0004]!==_0x3fcf9a(0xd5))_0x3ebf6a[_0x3fcf9a(_0x36fa8a._0x1d7987)](__createBinding,_0x2131c7,_0x51ea04,_0x240971[_0x6a0004]);}continue;case'3':_0x3ebf6a['Pctmg'](__setModuleDefault,_0x2131c7,_0x51ea04);continue;case'4':if(_0x51ea04&&_0x51ea04[_0x3fcf9a(0x10d)])return _0x51ea04;continue;}break;}};}());const _0x36cbbc={};_0x36cbbc['value']=!![],Object[_0x1294da(0x123)](exports,_0x1294da(0x10d),_0x36cbbc),exports['analyzeImpact']=analyzeImpact,exports['getImpactMemoCache']=getImpactMemoCache,exports['classifyRisk']=classifyRisk,exports[_0x1294da(0x115)]=getHubFiles;const path=__importStar(require(_0x1294da(0xf8))),risk_scorer_1=require(_0x1294da(0xd4)),change_coupling_1=require('../git/change-coupling'),memo_cache_1=require('../graph/memo-cache');async function analyzeImpact(_0x15a971,_0x8e8880,_0x123145){const _0x1442c6={_0x5488cf:0x12d,_0x16beb3:0x133,_0x173049:0x10c,_0x50b227:0x10e,_0x5602c2:0xdf,_0x183f94:0x101,_0x5322c1:0x112,_0x521d0b:0xf0,_0x3bfcdf:0x128,_0x66f3e7:0x12b,_0x191503:0x11a},_0x744fc9=_0x1294da,_0x55b34f={'sfbXf':function(_0xe9ac16,_0x474994){return _0xe9ac16+_0x474994;},'ZXaWy':function(_0x57e924,_0xaedfd,_0x4cc761){return _0x57e924(_0xaedfd,_0x4cc761);},'ioofi':function(_0x44f71b,_0x565be7){return _0x44f71b>_0x565be7;},'pfrBE':function(_0x40b857,_0x426bdb){return _0x40b857(_0x426bdb);},'FmYWY':function(_0x14e35a,_0x296e8a,_0x29a707,_0x59c474){return _0x14e35a(_0x296e8a,_0x29a707,_0x59c474);}},_0x22cc7b=path[_0x744fc9(0x106)](_0x15a971),_0x27b093=_0x4eadb9=>path['relative'](_0x8e8880[_0x744fc9(0xd7)],_0x4eadb9)['replace'](/\\/g,'/'),_0x44e708=(0x0,memo_cache_1['getMemoCache'])(),_0x1edbb7=_0x44e708[_0x744fc9(_0x1442c6._0x5488cf)](_0x22cc7b);if(_0x1edbb7){const _0x32b403=(_0x8e8880['reverse'][_0x744fc9(0x12d)](_0x22cc7b)||[])[_0x744fc9(0x124)](_0x27b093),_0xdbfed=new Set(_0x32b403),_0x438f4c=_0x1edbb7['impactSet']['map'](_0x4b9e01=>_0x27b093(_0x4b9e01))[_0x744fc9(_0x1442c6._0x16beb3)](_0xc16286=>!_0xdbfed['has'](_0xc16286));let _0x5c62ff={'filePath':_0x22cc7b,'relativePath':_0x27b093(_0x22cc7b),'riskLevel':_0x1edbb7[_0x744fc9(0x12b)],'directDependents':_0x32b403,'transitiveDependents':_0x438f4c,'totalImpacted':_0x55b34f[_0x744fc9(_0x1442c6._0x173049)](_0x1edbb7['directCount'],_0x1edbb7[_0x744fc9(0xd8)]),'cascadeLevels':_0x1edbb7[_0x744fc9(_0x1442c6._0x50b227)],'fromCache':!![]};if(_0x123145?.[_0x744fc9(_0x1442c6._0x5602c2)]&&_0x8e8880[_0x744fc9(0x10f)]['has'](_0x22cc7b))try{(0x0,risk_scorer_1[_0x744fc9(_0x1442c6._0x183f94)])(_0x8e8880);const _0x374bb3=(0x0,risk_scorer_1['getRiskScore'])(_0x22cc7b,_0x8e8880,_0x123145[_0x744fc9(0x118)]??null);_0x5c62ff[_0x744fc9(_0x1442c6._0x5322c1)]=_0x374bb3;const _0x14282c=_0x374bb3['riskLevel'];_0x55b34f['ZXaWy'](isHigherRisk,_0x14282c,_0x5c62ff['riskLevel'])&&(_0x5c62ff['riskLevel']=mapCompositeToLegacy(_0x14282c));}catch(_0x4c74ce){console[_0x744fc9(0x100)]('[syke:scoring]\x20Failed\x20to\x20compute\x20risk\x20score\x20for\x20'+_0x15a971+':\x20'+_0x4c74ce);}if(_0x123145?.[_0x744fc9(0x121)])try{const _0x1d02d1=await computeCoupledFiles(_0x22cc7b,_0x8e8880,_0x27b093);_0x55b34f['ioofi'](_0x1d02d1[_0x744fc9(0x128)],0x0)&&(_0x5c62ff['coupledFiles']=_0x1d02d1);}catch(_0x35ed5c){console['error']('[syke:coupling]\x20Failed\x20to\x20compute\x20change\x20coupling\x20for\x20'+_0x15a971+':\x20'+_0x35ed5c);}return _0x5c62ff;}let _0x17bbf4;_0x8e8880['scc']?_0x17bbf4=analyzeImpactWithSCC(_0x22cc7b,_0x8e8880,_0x27b093):_0x17bbf4=analyzeImpactBFS(_0x22cc7b,_0x8e8880,_0x27b093);const _0x61dd91=[..._0x17bbf4[_0x744fc9(0xfc)],..._0x17bbf4['transitiveDependents']][_0x744fc9(0x124)](_0x39fe3c=>path['normalize'](path['join'](_0x8e8880['sourceDir'],_0x39fe3c)));_0x44e708['set'](_0x22cc7b,{'impactSet':_0x61dd91,'directCount':_0x17bbf4['directDependents']['length'],'transitiveCount':_0x17bbf4[_0x744fc9(_0x1442c6._0x521d0b)][_0x744fc9(_0x1442c6._0x3bfcdf)],'riskLevel':_0x17bbf4['riskLevel'],'cascadeLevels':_0x17bbf4['cascadeLevels'],'computedAt':Date['now']()});if(_0x123145?.['includeRiskScore']&&_0x8e8880[_0x744fc9(0x10f)]['has'](_0x22cc7b))try{(0x0,risk_scorer_1[_0x744fc9(0x101)])(_0x8e8880);const _0x320c2c=(0x0,risk_scorer_1['getRiskScore'])(_0x22cc7b,_0x8e8880,_0x123145['fileContent']??null);_0x17bbf4[_0x744fc9(0x112)]=_0x320c2c;const _0xd0bae=_0x320c2c[_0x744fc9(_0x1442c6._0x66f3e7)];_0x55b34f[_0x744fc9(0x132)](isHigherRisk,_0xd0bae,_0x17bbf4[_0x744fc9(_0x1442c6._0x66f3e7)])&&(_0x17bbf4['riskLevel']=_0x55b34f['pfrBE'](mapCompositeToLegacy,_0xd0bae));}catch(_0x3829cc){console['error']('[syke:scoring]\x20Failed\x20to\x20compute\x20risk\x20score\x20for\x20'+_0x15a971+':\x20'+_0x3829cc);}if(_0x123145?.[_0x744fc9(0x121)])try{const _0x1d6ee9=await _0x55b34f[_0x744fc9(_0x1442c6._0x191503)](computeCoupledFiles,_0x22cc7b,_0x8e8880,_0x27b093);_0x1d6ee9[_0x744fc9(0x128)]>0x0&&(_0x17bbf4['coupledFiles']=_0x1d6ee9);}catch(_0x541bc7){console['error']('[syke:coupling]\x20Failed\x20to\x20compute\x20change\x20coupling\x20for\x20'+_0x15a971+':\x20'+_0x541bc7);}return _0x17bbf4;}async function computeCoupledFiles(_0x557e7a,_0x42e0d9,_0x55e965){const _0x455a29={_0x25a591:0x107,_0x433358:0x113,_0x39e211:0x120,_0x2853e6:0x12d,_0x5aade9:0xf2,_0x3b5824:0x130,_0x737437:0xe9,_0x2eeff9:0x106,_0x37a706:0xe6,_0x4a1bd5:0x119,_0x53aa89:0x119,_0x2e1986:0x133},_0x3215f6=_0x1294da,_0x641657={};_0x641657[_0x3215f6(0xdb)]=function(_0x1bc030,_0x121606){return _0x1bc030===_0x121606;};const _0x509e54=_0x641657,_0x5253ac=await(0x0,change_coupling_1[_0x3215f6(_0x455a29._0x25a591)])(_0x42e0d9[_0x3215f6(0xf2)]);if(_0x5253ac['totalCommitsAnalyzed']===0x0)return[];const _0x875172=path['relative'](_0x42e0d9[_0x3215f6(0xf2)],_0x557e7a)['replace'](/\\/g,'/'),_0x563e6f=(0x0,change_coupling_1[_0x3215f6(_0x455a29._0x433358)])(_0x875172,_0x5253ac);if(_0x509e54['KIQoF'](_0x563e6f['length'],0x0))return[];const _0x138f2b=new Set(),_0x107865=_0x42e0d9['forward']['get'](_0x557e7a)||[];for(const _0x34f212 of _0x107865){_0x138f2b[_0x3215f6(0xf1)](path[_0x3215f6(0x11b)](_0x42e0d9['projectRoot'],_0x34f212)[_0x3215f6(_0x455a29._0x39e211)](/\\/g,'/'));}const _0x4b731b=_0x42e0d9['reverse'][_0x3215f6(_0x455a29._0x2853e6)](_0x557e7a)||[];for(const _0x69c5e2 of _0x4b731b){_0x138f2b['add'](path[_0x3215f6(0x11b)](_0x42e0d9[_0x3215f6(_0x455a29._0x5aade9)],_0x69c5e2)['replace'](/\\/g,'/'));}const _0x18d51e=[];for(const _0x5f2fd8 of _0x563e6f){const _0x20bb1b=_0x5f2fd8['file1']===_0x875172?_0x5f2fd8[_0x3215f6(_0x455a29._0x3b5824)]:_0x5f2fd8[_0x3215f6(_0x455a29._0x737437)],_0x19593b=_0x138f2b['has'](_0x20bb1b),_0x9b4ce0=path[_0x3215f6(_0x455a29._0x2eeff9)](path['join'](_0x42e0d9['projectRoot'],_0x20bb1b)),_0x4da5a6=_0x55e965(_0x9b4ce0),_0x558a99={};_0x558a99[_0x3215f6(_0x455a29._0x37a706)]=_0x4da5a6,_0x558a99[_0x3215f6(_0x455a29._0x4a1bd5)]=_0x5f2fd8[_0x3215f6(_0x455a29._0x53aa89)],_0x558a99['coChangeCount']=_0x5f2fd8['coChangeCount'],_0x558a99['inDependencyGraph']=_0x19593b,_0x18d51e['push'](_0x558a99);}const _0x1d4f89=_0x18d51e[_0x3215f6(_0x455a29._0x2e1986)](_0x115be4=>!_0x115be4['inDependencyGraph']);return _0x1d4f89['slice'](0x0,0x5);}function _0x2475(){const _0x2fc2a2=['zgvMAw5LuhjVCgvYDhK','BwfW','rvD5CeO','x19PBxbVCNrtDgfY','ndeXndGZmu5oELHZwG','BgvUz3rO','EwvbAei','DKLvEhy','CMLZA0XLDMvS','C2L6zq','z2v0','DMfSDwu','tK9orq','zMLSzti','mKPTs01SzW','wLHHv3K','zMLSDgvY','ntG5nda1twPurgHi','vNzdzee','lI4VC2nVCMLUzY9YAxnRlxnJB3jLCG','zgvMyxvSDa','A21ks0O','C291CMnLrgLY','DhjHBNnPDgL2zunVDw50','ChjVDg90ExbL','otqZnZC1rhjqtuve','s0LrB0y','C3bSAxq','BMnYs1K','EMHSAMG','Aw5JBhvKzvjPC2Tty29Yzq','x19JCMvHDgvcAw5KAw5N','zMLSzq','AxndEwnSAwm','mZeWmZe5mdjVv05NtLO','te9x','D1Pwzuy','CMvSyxrPDMvqyxrO','ohjszhjPvG','q1jjveLdquW','zMLSzte','vwHUzxG','mtzotgjRC3a','BM9Kzxm','nJeYmdeXn2D4qKTVzq','seLhsa','D3jPDgfIBgu','DhjHBNnPDgL2zurLCgvUzgvUDhm','ywrK','ChjVAMvJDfjVB3q','vgnICfq','CLDqqKW','y291BNq','z2v0twvTB0nHy2HL','mtC5mde4muzpBKn3uG','Cgf0Aa','C2v0','u0fgrq','rNLwBxq','zgLYzwn0rgvWzw5Kzw50CW','z2v0t3DUuhjVCgvYDhLezxnJCMLWDg9Y','ruLhyNG','C2XPy2u','zxjYB3i','y29TChv0zvbYB2PLy3rnzxrYAwnZ','zw51BwvYywjSzq','y29UzMLNDxjHyMXL','nhWXFdj8m3WW','B1j5uM4','BM9YBwfSAxPL','BwLUzuDPDeHPC3rVCNK','AgfZ','CvDrte0','z2v0t3DUuhjVCgvYDhLoyw1LCW','CMv2zxjZzq','C2zIwgy','x19LC01VzhvSzq','y2fZy2fKzuXLDMvSCW','zMLSzxm','x19ZzxrnB2r1BgvezwzHDwX0','DxP0y1C','CMLZA1nJB3jL','z2v0q291CgXLzezPBgvZ','nZK4nZi3mfDStxbYCa','z2v0shvIrMLSzxm','uMDsvfa','nNjgt0zPta','zMLSzunVBNrLBNq','y29UzMLKzw5Jzq','rM1zv1K','CMvSyxrPDMu','DxrzrMi','Be16zvG','tuvesvvn','uvngB1a','CMvWBgfJzq','Aw5JBhvKzunVDxbSAw5N','C2HPzNq'];_0x2475=function(){return _0x2fc2a2;};return _0x2475();}function isHigherRisk(_0x37aa96,_0x1b83c4){const _0x47d13a={_0x2cb7b6:0xee,_0x3c2a1f:0x11e,_0x588d81:0xe5},_0x2484ac=_0x1294da,_0x2c78fa={};_0x2c78fa['wZVeF']=function(_0x39efeb,_0x528bfe){return _0x39efeb>_0x528bfe;};const _0x3246bf=_0x2c78fa,_0x598fa5={};_0x598fa5[_0x2484ac(0xe8)]=0x4,_0x598fa5['HIGH']=0x3,_0x598fa5[_0x2484ac(0x11e)]=0x2,_0x598fa5['LOW']=0x1,_0x598fa5['SAFE']=0x0;const _0x406e55=_0x598fa5,_0x51b441={};_0x51b441[_0x2484ac(_0x47d13a._0x2cb7b6)]=0x3,_0x51b441[_0x2484ac(_0x47d13a._0x3c2a1f)]=0x2,_0x51b441[_0x2484ac(0xe4)]=0x1,_0x51b441[_0x2484ac(0x12f)]=0x0;const _0x33fdc2=_0x51b441;return _0x3246bf[_0x2484ac(_0x47d13a._0x588d81)](_0x406e55[_0x37aa96]||0x0,_0x33fdc2[_0x1b83c4]||0x0);}function mapCompositeToLegacy(_0x26004c){const _0xcbef6d={_0x8dfc5:0xf3,_0x15d7d9:0x105,_0x2895ba:0xee,_0x5a04aa:0xf3,_0x2c1ac4:0xe4},_0x271cd0=_0x1294da,_0x2d47d9={};_0x2d47d9[_0x271cd0(0x109)]=_0x271cd0(0xe8),_0x2d47d9[_0x271cd0(_0xcbef6d._0x8dfc5)]='MEDIUM',_0x2d47d9[_0x271cd0(_0xcbef6d._0x15d7d9)]='LOW',_0x2d47d9['vGuLZ']='NONE';const _0x51acd9=_0x2d47d9;switch(_0x26004c){case _0x51acd9['qWQLM']:return _0x271cd0(_0xcbef6d._0x2895ba);case _0x271cd0(0xee):return'HIGH';case'MEDIUM':return _0x51acd9[_0x271cd0(_0xcbef6d._0x5a04aa)];case _0x271cd0(_0xcbef6d._0x2c1ac4):return _0x51acd9['oRyRn'];case _0x271cd0(0xfa):return _0x51acd9['vGuLZ'];}}function analyzeImpactBFS(_0x2e5491,_0x3afd83,_0x5d0ae5){const _0x3b7236={_0x2e2987:0x122,_0x39abc6:0xea,_0xea9465:0xf1,_0x16ba9b:0x12c},_0x236289=_0x1294da,_0x2aff5e={'aFBYB':function(_0xf2e3a5,_0x48fc2c){return _0xf2e3a5>_0x48fc2c;},'Uhnex':function(_0x569b08,_0x1d64a2){return _0x569b08!==_0x1d64a2;},'rWPBL':function(_0x14b4c1,_0x460f21){return _0x14b4c1(_0x460f21);}},_0x3fdc78=_0x3afd83['reverse']['get'](_0x2e5491)||[],_0x572431=new Set(),_0x3fbd9c=[..._0x3fdc78];for(const _0x7f78b7 of _0x3fdc78){_0x572431['add'](_0x7f78b7);}while(_0x2aff5e['aFBYB'](_0x3fbd9c['length'],0x0)){const _0x19836a=_0x3fbd9c[_0x236289(_0x3b7236._0x2e2987)](),_0x2c6da4=_0x3afd83['reverse']['get'](_0x19836a)||[];for(const _0x55e632 of _0x2c6da4){!_0x572431[_0x236289(0x108)](_0x55e632)&&_0x2aff5e[_0x236289(_0x3b7236._0x39abc6)](_0x55e632,_0x2e5491)&&(_0x572431[_0x236289(_0x3b7236._0xea9465)](_0x55e632),_0x3fbd9c['push'](_0x55e632));}}const _0x149ab3=_0x572431[_0x236289(_0x3b7236._0x16ba9b)],_0x45fa79=new Set(_0x3fdc78),_0x9d54c1=[..._0x572431]['filter'](_0x13eb71=>!_0x45fa79['has'](_0x13eb71)),_0x367277=_0x2aff5e[_0x236289(0xf4)](classifyRisk,_0x149ab3);return{'filePath':_0x2e5491,'relativePath':_0x5d0ae5(_0x2e5491),'riskLevel':_0x367277,'directDependents':_0x3fdc78['map'](_0x5d0ae5),'transitiveDependents':_0x9d54c1['map'](_0x5d0ae5),'totalImpacted':_0x149ab3};}function analyzeImpactWithSCC(_0x3e901e,_0x44d4ba,_0x1738bb){const _0x56cb4e={_0x21af99:0x10f,_0x31a5dd:0x124,_0x358c5d:0xf9,_0x4da7ba:0xdd,_0x1c9a3f:0xf1,_0x1d0e01:0x10b,_0x58584f:0xe2,_0x3d317f:0xf1,_0x556dfe:0x133},_0x947677=_0x1294da,_0x62e10d={'rEwgK':function(_0x57a507,_0x32b9bd,_0x1857d7,_0x57beda){return _0x57a507(_0x32b9bd,_0x1857d7,_0x57beda);},'ncrKY':function(_0x14f7d0,_0x111e49){return _0x14f7d0>_0x111e49;},'RgRTP':function(_0x35b82b,_0x55f349){return _0x35b82b+_0x55f349;},'rupTL':function(_0x41fbd6,_0x4efe1d){return _0x41fbd6(_0x4efe1d);},'QSFoP':function(_0x5c2932,_0x1e38c2){return _0x5c2932(_0x1e38c2);}},_0x10ace9=_0x44d4ba['scc'],{nodeToComponent:_0xd90ce6,condensed:_0x344cdb}=_0x10ace9,_0x561c54=_0xd90ce6[_0x947677(0x12d)](_0x3e901e);if(_0x561c54===undefined)return _0x62e10d['rEwgK'](analyzeImpactBFS,_0x3e901e,_0x44d4ba,_0x1738bb);const _0x438add=_0x344cdb['nodes'][_0x561c54],_0x2f94b9=_0x438add[_0x947677(0xe2)]?_0x438add[_0x947677(_0x56cb4e._0x21af99)][_0x947677(0x133)](_0x4ac7e2=>_0x4ac7e2!==_0x3e901e)[_0x947677(_0x56cb4e._0x31a5dd)](_0x1738bb):undefined,_0x57a21a=new Map();_0x57a21a[_0x947677(_0x56cb4e._0x358c5d)](_0x561c54,0x0);const _0x469b45={};_0x469b45['sccIdx']=_0x561c54,_0x469b45['level']=0x0;const _0x51cb9e=[_0x469b45];while(_0x62e10d[_0x947677(_0x56cb4e._0x4da7ba)](_0x51cb9e[_0x947677(0x128)],0x0)){const {sccIdx:_0x60fc90,level:_0x3d516f}=_0x51cb9e['shift'](),_0x573cb4=_0x344cdb[_0x947677(0x10b)]['get'](_0x60fc90)||[];for(const _0x12c47a of _0x573cb4){!_0x57a21a['has'](_0x12c47a)&&(_0x57a21a[_0x947677(0xf9)](_0x12c47a,_0x62e10d[_0x947677(0x116)](_0x3d516f,0x1)),_0x51cb9e['push']({'sccIdx':_0x12c47a,'level':_0x62e10d[_0x947677(0x116)](_0x3d516f,0x1)}));}}const _0x3e4f39=new Map(),_0x2bf85f=new Set();for(const [_0x148e5f,_0x96b778]of _0x57a21a){const _0x3396bf=_0x344cdb['nodes'][_0x148e5f];for(const _0x4db86c of _0x3396bf['files']){if(_0x4db86c===_0x3e901e)continue;_0x2bf85f[_0x947677(_0x56cb4e._0x1c9a3f)](_0x4db86c),_0x3e4f39['set'](_0x4db86c,_0x96b778);}}const _0x2b8067=_0x44d4ba[_0x947677(_0x56cb4e._0x1d0e01)][_0x947677(0x12d)](_0x3e901e)||[],_0x592bdf=new Set(_0x2b8067);if(_0x438add[_0x947677(_0x56cb4e._0x58584f)])for(const _0x59c875 of _0x438add[_0x947677(0x10f)]){_0x59c875!==_0x3e901e&&_0x592bdf[_0x947677(_0x56cb4e._0x3d317f)](_0x59c875);}const _0x41662f=[..._0x2bf85f]['filter'](_0x53df76=>_0x592bdf[_0x947677(0x108)](_0x53df76)),_0x3fa0b2=[..._0x2bf85f]['filter'](_0xccc659=>!_0x592bdf['has'](_0xccc659)),_0x5099ac=_0x2bf85f[_0x947677(0x12c)],_0x368aa2=_0x62e10d['rupTL'](classifyRisk,_0x5099ac),_0x4636d0=new Map();for(const [_0x173587,_0x4b45f6]of _0x3e4f39){_0x4636d0[_0x947677(_0x56cb4e._0x358c5d)](_0x1738bb(_0x173587),_0x4b45f6);}return{'filePath':_0x3e901e,'relativePath':_0x62e10d[_0x947677(0x11f)](_0x1738bb,_0x3e901e),'riskLevel':_0x368aa2,'directDependents':_0x41662f['map'](_0x1738bb),'transitiveDependents':_0x3fa0b2[_0x947677(_0x56cb4e._0x31a5dd)](_0x1738bb),'totalImpacted':_0x5099ac,'cascadeLevels':_0x4636d0,'circularCluster':_0x2f94b9,'sccCount':_0x344cdb[_0x947677(0xec)][_0x947677(0x128)],'cyclicSCCs':_0x344cdb[_0x947677(0xec)][_0x947677(_0x56cb4e._0x556dfe)](_0x17983a=>_0x17983a[_0x947677(0xe2)])['length']};}function getImpactMemoCache(){const _0x196378=_0x1294da;return(0x0,memo_cache_1[_0x196378(0xf6)])();}function classifyRisk(_0x1560bc){const _0x2003c9={_0x3a7bcc:0x11c,_0x577e8a:0x111},_0x21bc11=_0x1294da,_0x5129d2={};_0x5129d2['uztcW']=function(_0x164d2b,_0x5bbebc){return _0x164d2b>=_0x5bbebc;},_0x5129d2['VvCdA']=_0x21bc11(0x11e),_0x5129d2['LYunX']='LOW',_0x5129d2[_0x21bc11(_0x2003c9._0x3a7bcc)]='NONE';const _0x31ed45=_0x5129d2;if(_0x31ed45[_0x21bc11(_0x2003c9._0x577e8a)](_0x1560bc,0xa))return'HIGH';if(_0x1560bc>=0x5)return _0x31ed45[_0x21bc11(0xd3)];if(_0x1560bc>=0x1)return _0x31ed45['LYunX'];return _0x31ed45[_0x21bc11(_0x2003c9._0x3a7bcc)];}function getHubFiles(_0x1a23f9,_0x398691=0xa){const _0x1e0c42={_0x4e1825:0x10b,_0x2d5feb:0xf5,_0x3d2b91:0x128,_0x1d9a96:0xff,_0x27eeb:0x124},_0x408948=_0x1294da,_0x429b2=[];for(const _0x222fff of _0x1a23f9['files']){const _0x2188d9=_0x1a23f9[_0x408948(_0x1e0c42._0x4e1825)]['get'](_0x222fff)||[],_0x3aaafc={};_0x3aaafc['file']=_0x222fff,_0x3aaafc[_0x408948(_0x1e0c42._0x2d5feb)]=_0x2188d9[_0x408948(_0x1e0c42._0x3d2b91)],_0x429b2['push'](_0x3aaafc);}return _0x429b2['sort']((_0x56d75d,_0x5b1140)=>_0x5b1140[_0x408948(0xf5)]-_0x56d75d['count']),_0x429b2[_0x408948(_0x1e0c42._0x1d9a96)](0x0,_0x398691)[_0x408948(_0x1e0c42._0x27eeb)](_0xad88fb=>({'relativePath':path['relative'](_0x1a23f9['sourceDir'],_0xad88fb[_0x408948(0xe1)])[_0x408948(0x120)](/\\/g,'/'),'dependentCount':_0xad88fb['count'],'riskLevel':classifyRisk(_0xad88fb[_0x408948(0xf5)])}));}
|
|
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.analyzeImpact = analyzeImpact;
|
|
37
|
+
exports.getImpactMemoCache = getImpactMemoCache;
|
|
38
|
+
exports.classifyRisk = classifyRisk;
|
|
39
|
+
exports.getHubFiles = getHubFiles;
|
|
40
|
+
const path = __importStar(require("path"));
|
|
41
|
+
const change_coupling_1 = require("../git/change-coupling");
|
|
42
|
+
const memo_cache_1 = require("../graph/memo-cache");
|
|
43
|
+
/**
|
|
44
|
+
* BFS reverse traversal to find all files impacted by modifying `filePath`.
|
|
45
|
+
* When SCC data is available, uses the condensed DAG for more accurate
|
|
46
|
+
* cascade-level analysis and circular dependency detection.
|
|
47
|
+
*
|
|
48
|
+
* Optionally computes a composite risk score when `includeRiskScore` is true.
|
|
49
|
+
* Optionally computes historical change coupling when `includeCoupling` is true.
|
|
50
|
+
*/
|
|
51
|
+
/**
|
|
52
|
+
* Local BFS impact analysis — used by BYOK ai_analyze and web dashboard.
|
|
53
|
+
* Risk scoring is now server-side (Pro). This function provides basic
|
|
54
|
+
* BFS traversal and SCC-enhanced cascade analysis.
|
|
55
|
+
*/
|
|
56
|
+
async function analyzeImpact(filePath, graph, options) {
|
|
57
|
+
const normalized = path.normalize(filePath);
|
|
58
|
+
const toRelative = (f) => path.relative(graph.sourceDir, f).replace(/\\/g, "/");
|
|
59
|
+
// Check memo cache for a cached BFS result (fast path)
|
|
60
|
+
const memoCache = (0, memo_cache_1.getMemoCache)();
|
|
61
|
+
const cached = memoCache.get(normalized);
|
|
62
|
+
if (cached) {
|
|
63
|
+
const directDependents = (graph.reverse.get(normalized) || []).map(toRelative);
|
|
64
|
+
const directSet = new Set(directDependents);
|
|
65
|
+
const transitiveDependents = cached.impactSet
|
|
66
|
+
.map(f => toRelative(f))
|
|
67
|
+
.filter(rel => !directSet.has(rel));
|
|
68
|
+
let result = {
|
|
69
|
+
filePath: normalized,
|
|
70
|
+
relativePath: toRelative(normalized),
|
|
71
|
+
riskLevel: cached.riskLevel,
|
|
72
|
+
directDependents,
|
|
73
|
+
transitiveDependents,
|
|
74
|
+
totalImpacted: cached.directCount + cached.transitiveCount,
|
|
75
|
+
cascadeLevels: cached.cascadeLevels,
|
|
76
|
+
fromCache: true,
|
|
77
|
+
};
|
|
78
|
+
if (options?.includeCoupling) {
|
|
79
|
+
try {
|
|
80
|
+
const coupledFiles = await computeCoupledFiles(normalized, graph, toRelative);
|
|
81
|
+
if (coupledFiles.length > 0) {
|
|
82
|
+
result.coupledFiles = coupledFiles;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
console.error(`[syke:coupling] Failed to compute change coupling for ${filePath}: ${err}`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return result;
|
|
90
|
+
}
|
|
91
|
+
// Cache miss: run full BFS analysis
|
|
92
|
+
let result;
|
|
93
|
+
if (graph.scc) {
|
|
94
|
+
result = analyzeImpactWithSCC(normalized, graph, toRelative);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
result = analyzeImpactBFS(normalized, graph, toRelative);
|
|
98
|
+
}
|
|
99
|
+
// Store BFS result in memo cache
|
|
100
|
+
const allImpactedAbsPaths = [
|
|
101
|
+
...result.directDependents,
|
|
102
|
+
...result.transitiveDependents,
|
|
103
|
+
].map(rel => path.normalize(path.join(graph.sourceDir, rel)));
|
|
104
|
+
memoCache.set(normalized, {
|
|
105
|
+
impactSet: allImpactedAbsPaths,
|
|
106
|
+
directCount: result.directDependents.length,
|
|
107
|
+
transitiveCount: result.transitiveDependents.length,
|
|
108
|
+
riskLevel: result.riskLevel,
|
|
109
|
+
cascadeLevels: result.cascadeLevels,
|
|
110
|
+
computedAt: Date.now(),
|
|
111
|
+
});
|
|
112
|
+
// Compute historical change coupling if requested
|
|
113
|
+
if (options?.includeCoupling) {
|
|
114
|
+
try {
|
|
115
|
+
const coupledFiles = await computeCoupledFiles(normalized, graph, toRelative);
|
|
116
|
+
if (coupledFiles.length > 0) {
|
|
117
|
+
result.coupledFiles = coupledFiles;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
console.error(`[syke:coupling] Failed to compute change coupling for ${filePath}: ${err}`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return result;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Compute historical change coupling for a file, filtering to only show
|
|
128
|
+
* couplings that are NOT already in the dependency graph ("hidden" dependencies).
|
|
129
|
+
* Returns at most 5 coupled files, sorted by confidence.
|
|
130
|
+
*/
|
|
131
|
+
async function computeCoupledFiles(normalizedPath, graph, toRelative) {
|
|
132
|
+
const couplingResult = await (0, change_coupling_1.mineGitHistory)(graph.projectRoot);
|
|
133
|
+
if (couplingResult.totalCommitsAnalyzed === 0) {
|
|
134
|
+
return [];
|
|
135
|
+
}
|
|
136
|
+
// Convert file path to git-relative format (forward slashes, relative to project root)
|
|
137
|
+
const gitRelPath = path.relative(graph.projectRoot, normalizedPath).replace(/\\/g, "/");
|
|
138
|
+
const couplings = (0, change_coupling_1.getCoupledFiles)(gitRelPath, couplingResult);
|
|
139
|
+
if (couplings.length === 0) {
|
|
140
|
+
return [];
|
|
141
|
+
}
|
|
142
|
+
// Build a set of all files in the dependency graph (both direct and transitive)
|
|
143
|
+
const graphDeps = new Set();
|
|
144
|
+
// Forward dependencies of this file
|
|
145
|
+
const forwardDeps = graph.forward.get(normalizedPath) || [];
|
|
146
|
+
for (const d of forwardDeps) {
|
|
147
|
+
graphDeps.add(path.relative(graph.projectRoot, d).replace(/\\/g, "/"));
|
|
148
|
+
}
|
|
149
|
+
// Reverse dependents of this file
|
|
150
|
+
const reverseDeps = graph.reverse.get(normalizedPath) || [];
|
|
151
|
+
for (const d of reverseDeps) {
|
|
152
|
+
graphDeps.add(path.relative(graph.projectRoot, d).replace(/\\/g, "/"));
|
|
153
|
+
}
|
|
154
|
+
const results = [];
|
|
155
|
+
for (const coupling of couplings) {
|
|
156
|
+
// Determine which file is the "other" file in the pair
|
|
157
|
+
const otherFile = coupling.file1 === gitRelPath ? coupling.file2 : coupling.file1;
|
|
158
|
+
const inGraph = graphDeps.has(otherFile);
|
|
159
|
+
// Convert to source-dir-relative path for display
|
|
160
|
+
const otherAbsolute = path.normalize(path.join(graph.projectRoot, otherFile));
|
|
161
|
+
const displayPath = toRelative(otherAbsolute);
|
|
162
|
+
results.push({
|
|
163
|
+
relativePath: displayPath,
|
|
164
|
+
confidence: coupling.confidence,
|
|
165
|
+
coChangeCount: coupling.coChangeCount,
|
|
166
|
+
inDependencyGraph: inGraph,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
// Filter to only hidden dependencies (not in graph) and limit to top 5
|
|
170
|
+
const hidden = results.filter((r) => !r.inDependencyGraph);
|
|
171
|
+
return hidden.slice(0, 5);
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Original BFS-based impact analysis (no SCC data).
|
|
175
|
+
*/
|
|
176
|
+
function analyzeImpactBFS(normalized, graph, toRelative) {
|
|
177
|
+
// Direct dependents (depth 1)
|
|
178
|
+
const directDependents = graph.reverse.get(normalized) || [];
|
|
179
|
+
// BFS for transitive dependents (all depths)
|
|
180
|
+
const visited = new Set();
|
|
181
|
+
const queue = [...directDependents];
|
|
182
|
+
for (const d of directDependents) {
|
|
183
|
+
visited.add(d);
|
|
184
|
+
}
|
|
185
|
+
while (queue.length > 0) {
|
|
186
|
+
const current = queue.shift();
|
|
187
|
+
const dependents = graph.reverse.get(current) || [];
|
|
188
|
+
for (const dep of dependents) {
|
|
189
|
+
if (!visited.has(dep) && dep !== normalized) {
|
|
190
|
+
visited.add(dep);
|
|
191
|
+
queue.push(dep);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
const totalImpacted = visited.size;
|
|
196
|
+
// Transitive-only = all visited minus direct
|
|
197
|
+
const directSet = new Set(directDependents);
|
|
198
|
+
const transitiveDependents = [...visited].filter((f) => !directSet.has(f));
|
|
199
|
+
const riskLevel = classifyRisk(totalImpacted);
|
|
200
|
+
return {
|
|
201
|
+
filePath: normalized,
|
|
202
|
+
relativePath: toRelative(normalized),
|
|
203
|
+
riskLevel,
|
|
204
|
+
directDependents: directDependents.map(toRelative),
|
|
205
|
+
transitiveDependents: transitiveDependents.map(toRelative),
|
|
206
|
+
totalImpacted,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* SCC-enhanced impact analysis using the condensed DAG.
|
|
211
|
+
*
|
|
212
|
+
* 1. If the changed file is in a cyclic SCC (size > 1), ALL files in that SCC
|
|
213
|
+
* are immediately marked as affected at cascade level 0.
|
|
214
|
+
* 2. BFS on the condensed DAG (using reverse edges = dependents) to find
|
|
215
|
+
* all impacted SCCs with correct cascade levels.
|
|
216
|
+
* 3. Each file inherits the cascade level of its SCC.
|
|
217
|
+
*/
|
|
218
|
+
function analyzeImpactWithSCC(normalized, graph, toRelative) {
|
|
219
|
+
const scc = graph.scc;
|
|
220
|
+
const { nodeToComponent, condensed } = scc;
|
|
221
|
+
const sccIndex = nodeToComponent.get(normalized);
|
|
222
|
+
// File not found in SCC mapping — fall back to BFS
|
|
223
|
+
if (sccIndex === undefined) {
|
|
224
|
+
return analyzeImpactBFS(normalized, graph, toRelative);
|
|
225
|
+
}
|
|
226
|
+
const startNode = condensed.nodes[sccIndex];
|
|
227
|
+
// Collect circular cluster info
|
|
228
|
+
const circularCluster = startNode.isCyclic
|
|
229
|
+
? startNode.files.filter(f => f !== normalized).map(toRelative)
|
|
230
|
+
: undefined;
|
|
231
|
+
// BFS on condensed DAG reverse edges to find all impacted SCCs
|
|
232
|
+
// Level 0 = the SCC containing the changed file
|
|
233
|
+
// Level 1 = SCCs that directly depend on the changed SCC
|
|
234
|
+
// Level N = SCCs at distance N in the condensed DAG
|
|
235
|
+
const visitedSCCs = new Map(); // SCC index -> cascade level
|
|
236
|
+
visitedSCCs.set(sccIndex, 0);
|
|
237
|
+
const queue = [
|
|
238
|
+
{ sccIdx: sccIndex, level: 0 },
|
|
239
|
+
];
|
|
240
|
+
while (queue.length > 0) {
|
|
241
|
+
const { sccIdx, level } = queue.shift();
|
|
242
|
+
// Get SCCs that depend on this SCC (reverse edges in condensed DAG)
|
|
243
|
+
const dependentSCCs = condensed.reverse.get(sccIdx) || [];
|
|
244
|
+
for (const depSCC of dependentSCCs) {
|
|
245
|
+
if (!visitedSCCs.has(depSCC)) {
|
|
246
|
+
visitedSCCs.set(depSCC, level + 1);
|
|
247
|
+
queue.push({ sccIdx: depSCC, level: level + 1 });
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
// Expand SCC indices back to individual files
|
|
252
|
+
const cascadeLevels = new Map();
|
|
253
|
+
const allImpactedFiles = new Set();
|
|
254
|
+
for (const [sccIdx, level] of visitedSCCs) {
|
|
255
|
+
const node = condensed.nodes[sccIdx];
|
|
256
|
+
for (const file of node.files) {
|
|
257
|
+
if (file === normalized)
|
|
258
|
+
continue; // Exclude the changed file itself
|
|
259
|
+
allImpactedFiles.add(file);
|
|
260
|
+
cascadeLevels.set(file, level);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
// Separate into direct (level 1 from raw graph) and transitive
|
|
264
|
+
const rawDirectDependents = graph.reverse.get(normalized) || [];
|
|
265
|
+
const directSet = new Set(rawDirectDependents);
|
|
266
|
+
// Files in the same cyclic SCC are also considered "direct" dependents
|
|
267
|
+
if (startNode.isCyclic) {
|
|
268
|
+
for (const f of startNode.files) {
|
|
269
|
+
if (f !== normalized) {
|
|
270
|
+
directSet.add(f);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
const directDependents = [...allImpactedFiles].filter(f => directSet.has(f));
|
|
275
|
+
const transitiveDependents = [...allImpactedFiles].filter(f => !directSet.has(f));
|
|
276
|
+
const totalImpacted = allImpactedFiles.size;
|
|
277
|
+
const riskLevel = classifyRisk(totalImpacted);
|
|
278
|
+
// Convert cascade levels keys to relative paths
|
|
279
|
+
const relativeCascadeLevels = new Map();
|
|
280
|
+
for (const [file, level] of cascadeLevels) {
|
|
281
|
+
relativeCascadeLevels.set(toRelative(file), level);
|
|
282
|
+
}
|
|
283
|
+
return {
|
|
284
|
+
filePath: normalized,
|
|
285
|
+
relativePath: toRelative(normalized),
|
|
286
|
+
riskLevel,
|
|
287
|
+
directDependents: directDependents.map(toRelative),
|
|
288
|
+
transitiveDependents: transitiveDependents.map(toRelative),
|
|
289
|
+
totalImpacted,
|
|
290
|
+
cascadeLevels: relativeCascadeLevels,
|
|
291
|
+
circularCluster,
|
|
292
|
+
sccCount: condensed.nodes.length,
|
|
293
|
+
cyclicSCCs: condensed.nodes.filter(n => n.isCyclic).length,
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Get the memo cache instance for diagnostics (cache stats, etc.).
|
|
298
|
+
*/
|
|
299
|
+
function getImpactMemoCache() {
|
|
300
|
+
return (0, memo_cache_1.getMemoCache)();
|
|
301
|
+
}
|
|
302
|
+
function classifyRisk(count) {
|
|
303
|
+
if (count >= 10)
|
|
304
|
+
return "HIGH";
|
|
305
|
+
if (count >= 5)
|
|
306
|
+
return "MEDIUM";
|
|
307
|
+
if (count >= 1)
|
|
308
|
+
return "LOW";
|
|
309
|
+
return "NONE";
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Rank files by number of reverse dependents (hub score).
|
|
313
|
+
*/
|
|
314
|
+
function getHubFiles(graph, topN = 10) {
|
|
315
|
+
const entries = [];
|
|
316
|
+
for (const file of graph.files) {
|
|
317
|
+
const revDeps = graph.reverse.get(file) || [];
|
|
318
|
+
entries.push({ file, count: revDeps.length });
|
|
319
|
+
}
|
|
320
|
+
entries.sort((a, b) => b.count - a.count);
|
|
321
|
+
return entries.slice(0, topN).map((e) => ({
|
|
322
|
+
relativePath: path.relative(graph.sourceDir, e.file).replace(/\\/g, "/"),
|
|
323
|
+
dependentCount: e.count,
|
|
324
|
+
riskLevel: classifyRisk(e.count),
|
|
325
|
+
}));
|
|
326
|
+
}
|