@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
|
@@ -0,0 +1,214 @@
|
|
|
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.remoteAIAnalyze = remoteAIAnalyze;
|
|
47
|
+
exports.remoteValidateLicense = remoteValidateLicense;
|
|
48
|
+
const https = __importStar(require("https"));
|
|
49
|
+
const path = __importStar(require("path"));
|
|
50
|
+
const config_1 = require("../config");
|
|
51
|
+
// ── Constants ──
|
|
52
|
+
const BASE_URL = "https://us-central1-syke-cloud.cloudfunctions.net";
|
|
53
|
+
const ENDPOINTS = {
|
|
54
|
+
analyzeImpact: `${BASE_URL}/proAnalyzeImpact`,
|
|
55
|
+
getHubFiles: `${BASE_URL}/proGetHubFiles`,
|
|
56
|
+
aiAnalyze: `${BASE_URL}/proAIAnalyze`,
|
|
57
|
+
};
|
|
58
|
+
// ── Graph Serialization ──
|
|
59
|
+
/**
|
|
60
|
+
* Serialize a DependencyGraph into a GraphBundle for transmission.
|
|
61
|
+
* Converts absolute paths to relative paths (relative to sourceDir)
|
|
62
|
+
* to minimize payload size and avoid leaking local paths.
|
|
63
|
+
*/
|
|
64
|
+
function serializeGraph(graph) {
|
|
65
|
+
const toRel = (f) => path.relative(graph.sourceDir, f).replace(/\\/g, "/");
|
|
66
|
+
const files = [];
|
|
67
|
+
for (const f of graph.files) {
|
|
68
|
+
files.push(toRel(f));
|
|
69
|
+
}
|
|
70
|
+
const forward = {};
|
|
71
|
+
for (const [file, deps] of graph.forward) {
|
|
72
|
+
const rel = toRel(file);
|
|
73
|
+
forward[rel] = deps.map(toRel);
|
|
74
|
+
}
|
|
75
|
+
const reverse = {};
|
|
76
|
+
for (const [file, deps] of graph.reverse) {
|
|
77
|
+
const rel = toRel(file);
|
|
78
|
+
reverse[rel] = deps.map(toRel);
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
files,
|
|
82
|
+
forward,
|
|
83
|
+
reverse,
|
|
84
|
+
languages: graph.languages,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
// ── HTTP Client ──
|
|
88
|
+
function postJSON(url, body) {
|
|
89
|
+
return new Promise((resolve, reject) => {
|
|
90
|
+
const data = JSON.stringify(body);
|
|
91
|
+
const parsed = new URL(url);
|
|
92
|
+
const options = {
|
|
93
|
+
hostname: parsed.hostname,
|
|
94
|
+
port: 443,
|
|
95
|
+
path: parsed.pathname + parsed.search,
|
|
96
|
+
method: "POST",
|
|
97
|
+
headers: {
|
|
98
|
+
"Content-Type": "application/json",
|
|
99
|
+
"Content-Length": Buffer.byteLength(data),
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
const req = https.request(options, (res) => {
|
|
103
|
+
let responseData = "";
|
|
104
|
+
res.on("data", (chunk) => { responseData += chunk; });
|
|
105
|
+
res.on("end", () => {
|
|
106
|
+
try {
|
|
107
|
+
const json = JSON.parse(responseData);
|
|
108
|
+
if (res.statusCode && res.statusCode >= 400) {
|
|
109
|
+
reject(new Error(json.error || `HTTP ${res.statusCode}`));
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
resolve(json);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
reject(new Error(`Invalid response: ${responseData.substring(0, 200)}`));
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
req.on("error", reject);
|
|
121
|
+
req.setTimeout(60000, () => {
|
|
122
|
+
req.destroy();
|
|
123
|
+
reject(new Error("Request timeout (60s)"));
|
|
124
|
+
});
|
|
125
|
+
req.write(data);
|
|
126
|
+
req.end();
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
// ── License + Device Info ──
|
|
130
|
+
function getLicenseKey() {
|
|
131
|
+
return (0, config_1.getConfig)("licenseKey", "SYKE_LICENSE_KEY");
|
|
132
|
+
}
|
|
133
|
+
function getDeviceId() {
|
|
134
|
+
const os = require("os");
|
|
135
|
+
const crypto = require("crypto");
|
|
136
|
+
const raw = `${os.hostname()}:${os.userInfo().username}:${process.platform}:${os.arch()}`;
|
|
137
|
+
return crypto.createHash("sha256").update(raw).digest("hex").substring(0, 16);
|
|
138
|
+
}
|
|
139
|
+
// ── Public API ──
|
|
140
|
+
/**
|
|
141
|
+
* Remote analyze_impact: sends graph + target file to server.
|
|
142
|
+
*/
|
|
143
|
+
async function remoteAnalyzeImpact(graph, resolvedFilePath, options) {
|
|
144
|
+
const licenseKey = getLicenseKey();
|
|
145
|
+
if (!licenseKey) {
|
|
146
|
+
throw new Error("No license key configured");
|
|
147
|
+
}
|
|
148
|
+
const graphBundle = serializeGraph(graph);
|
|
149
|
+
const targetFile = path.relative(graph.sourceDir, resolvedFilePath).replace(/\\/g, "/");
|
|
150
|
+
const result = await postJSON(ENDPOINTS.analyzeImpact, {
|
|
151
|
+
licenseKey,
|
|
152
|
+
deviceId: getDeviceId(),
|
|
153
|
+
graphBundle,
|
|
154
|
+
targetFile,
|
|
155
|
+
options: { includeRiskScore: options?.includeRiskScore !== false },
|
|
156
|
+
});
|
|
157
|
+
return result;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Remote get_hub_files: sends graph to server for PageRank analysis.
|
|
161
|
+
*/
|
|
162
|
+
async function remoteGetHubFiles(graph, topN = 10) {
|
|
163
|
+
const licenseKey = getLicenseKey();
|
|
164
|
+
if (!licenseKey) {
|
|
165
|
+
throw new Error("No license key configured");
|
|
166
|
+
}
|
|
167
|
+
const graphBundle = serializeGraph(graph);
|
|
168
|
+
const result = await postJSON(ENDPOINTS.getHubFiles, {
|
|
169
|
+
licenseKey,
|
|
170
|
+
deviceId: getDeviceId(),
|
|
171
|
+
graphBundle,
|
|
172
|
+
topN,
|
|
173
|
+
});
|
|
174
|
+
return result;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Remote ai_analyze: sends graph + file contents to server for AI analysis.
|
|
178
|
+
*/
|
|
179
|
+
async function remoteAIAnalyze(graph, resolvedFilePath, fileContents) {
|
|
180
|
+
const licenseKey = getLicenseKey();
|
|
181
|
+
if (!licenseKey) {
|
|
182
|
+
throw new Error("No license key configured");
|
|
183
|
+
}
|
|
184
|
+
const graphBundle = serializeGraph(graph);
|
|
185
|
+
const targetFile = path.relative(graph.sourceDir, resolvedFilePath).replace(/\\/g, "/");
|
|
186
|
+
const result = await postJSON(ENDPOINTS.aiAnalyze, {
|
|
187
|
+
licenseKey,
|
|
188
|
+
deviceId: getDeviceId(),
|
|
189
|
+
graphBundle,
|
|
190
|
+
targetFile,
|
|
191
|
+
fileContents,
|
|
192
|
+
languages: graph.languages,
|
|
193
|
+
});
|
|
194
|
+
return result;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Remote license validation only (for refresh_graph, check_warnings).
|
|
198
|
+
* Returns true if the license is valid Pro.
|
|
199
|
+
*/
|
|
200
|
+
async function remoteValidateLicense() {
|
|
201
|
+
const licenseKey = getLicenseKey();
|
|
202
|
+
if (!licenseKey)
|
|
203
|
+
return false;
|
|
204
|
+
try {
|
|
205
|
+
const result = await postJSON(`${BASE_URL}/validateLicenseKey`, {
|
|
206
|
+
key: licenseKey,
|
|
207
|
+
deviceId: getDeviceId(),
|
|
208
|
+
});
|
|
209
|
+
return result.valid === true;
|
|
210
|
+
}
|
|
211
|
+
catch {
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
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 RemoteAIAnalyzeRequest {
|
|
68
|
+
licenseKey: string;
|
|
69
|
+
deviceId: string;
|
|
70
|
+
graphBundle: GraphBundle;
|
|
71
|
+
targetFile: string;
|
|
72
|
+
fileContents: string;
|
|
73
|
+
languages: string[];
|
|
74
|
+
}
|
|
75
|
+
export interface RemoteAIAnalyzeResponse {
|
|
76
|
+
analysis: string;
|
|
77
|
+
}
|
|
78
|
+
export interface RemoteError {
|
|
79
|
+
error: string;
|
|
80
|
+
code?: string;
|
|
81
|
+
}
|
|
@@ -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
|
/**
|