@ebowwa/dependency-graph-mcp 1.0.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/README.md +136 -0
- package/bun.lock +238 -0
- package/dist/cli.js +18 -0
- package/dist/index.js +13908 -0
- package/package.json +38 -0
- package/src/cli.js +31 -0
- package/src/cli.ts +26 -0
- package/src/index.js +983 -0
- package/src/index.ts +929 -0
package/src/index.js
ADDED
|
@@ -0,0 +1,983 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* Dependency Graph MCP Server
|
|
5
|
+
*
|
|
6
|
+
* Analyzes and visualizes dependency relationships in monorepos.
|
|
7
|
+
* Provides tools for:
|
|
8
|
+
* - Building dependency graphs from package.json and imports
|
|
9
|
+
* - Visualizing dependency relationships
|
|
10
|
+
* - Impact analysis for refactoring decisions
|
|
11
|
+
* - Finding circular dependencies
|
|
12
|
+
* - Identifying unused code
|
|
13
|
+
*/
|
|
14
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
15
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
16
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
17
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
18
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
19
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
20
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
24
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
25
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
26
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
27
|
+
function step(op) {
|
|
28
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
29
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
30
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
31
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
32
|
+
switch (op[0]) {
|
|
33
|
+
case 0: case 1: t = op; break;
|
|
34
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
35
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
36
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
37
|
+
default:
|
|
38
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
39
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
40
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
41
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
42
|
+
if (t[2]) _.ops.pop();
|
|
43
|
+
_.trys.pop(); continue;
|
|
44
|
+
}
|
|
45
|
+
op = body.call(thisArg, _);
|
|
46
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
47
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
51
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
52
|
+
if (ar || !(i in from)) {
|
|
53
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
54
|
+
ar[i] = from[i];
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
58
|
+
};
|
|
59
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
60
|
+
var index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
|
|
61
|
+
var stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
62
|
+
var types_js_1 = require("@modelcontextprotocol/sdk/types.js");
|
|
63
|
+
var node_fs_1 = require("node:fs");
|
|
64
|
+
var node_path_1 = require("node:path");
|
|
65
|
+
var node_url_1 = require("node:url");
|
|
66
|
+
var TOOLING_DIR = (0, node_path_1.dirname)((0, node_url_1.fileURLToPath)(import.meta.url.replace("/MCP/packages/dependency-graph", "/packages/src/tooling")));
|
|
67
|
+
// ==============
|
|
68
|
+
// Graph Builder
|
|
69
|
+
// ==============
|
|
70
|
+
var DependencyGraphBuilder = /** @class */ (function () {
|
|
71
|
+
function DependencyGraphBuilder(monorepoRoot) {
|
|
72
|
+
this.packageCache = new Map();
|
|
73
|
+
this.monorepoRoot = monorepoRoot;
|
|
74
|
+
this.graph = {
|
|
75
|
+
nodes: new Map(),
|
|
76
|
+
edges: [],
|
|
77
|
+
reverseEdges: new Map(),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Build the complete dependency graph
|
|
82
|
+
*/
|
|
83
|
+
DependencyGraphBuilder.prototype.build = function () {
|
|
84
|
+
return __awaiter(this, arguments, void 0, function (options) {
|
|
85
|
+
var _a, includeDevDependencies, _b, analyzeImports, _c, excludePatterns, packages, _i, packages_1, pkg, _d, packages_2, pkg;
|
|
86
|
+
if (options === void 0) { options = {}; }
|
|
87
|
+
return __generator(this, function (_e) {
|
|
88
|
+
switch (_e.label) {
|
|
89
|
+
case 0:
|
|
90
|
+
_a = options.includeDevDependencies, includeDevDependencies = _a === void 0 ? false : _a, _b = options.analyzeImports, analyzeImports = _b === void 0 ? true : _b, _c = options.excludePatterns, excludePatterns = _c === void 0 ? [] : _c;
|
|
91
|
+
return [4 /*yield*/, this.discoverPackages()];
|
|
92
|
+
case 1:
|
|
93
|
+
packages = _e.sent();
|
|
94
|
+
// Add nodes for all packages
|
|
95
|
+
for (_i = 0, packages_1 = packages; _i < packages_1.length; _i++) {
|
|
96
|
+
pkg = packages_1[_i];
|
|
97
|
+
this.addNode(pkg.name, pkg.path, "workspace", pkg.version);
|
|
98
|
+
}
|
|
99
|
+
_d = 0, packages_2 = packages;
|
|
100
|
+
_e.label = 2;
|
|
101
|
+
case 2:
|
|
102
|
+
if (!(_d < packages_2.length)) return [3 /*break*/, 6];
|
|
103
|
+
pkg = packages_2[_d];
|
|
104
|
+
return [4 /*yield*/, this.analyzePackageDependencies(pkg, includeDevDependencies, excludePatterns)];
|
|
105
|
+
case 3:
|
|
106
|
+
_e.sent();
|
|
107
|
+
if (!analyzeImports) return [3 /*break*/, 5];
|
|
108
|
+
return [4 /*yield*/, this.analyzeImports(pkg)];
|
|
109
|
+
case 4:
|
|
110
|
+
_e.sent();
|
|
111
|
+
_e.label = 5;
|
|
112
|
+
case 5:
|
|
113
|
+
_d++;
|
|
114
|
+
return [3 /*break*/, 2];
|
|
115
|
+
case 6:
|
|
116
|
+
// Build reverse edges for impact analysis
|
|
117
|
+
this.buildReverseEdges();
|
|
118
|
+
return [2 /*return*/, this.graph];
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
};
|
|
123
|
+
/**
|
|
124
|
+
* Discover all package.json files in the monorepo
|
|
125
|
+
*/
|
|
126
|
+
DependencyGraphBuilder.prototype.discoverPackages = function () {
|
|
127
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
128
|
+
var packages, seen, searchPaths, _i, searchPaths_1, searchPath;
|
|
129
|
+
return __generator(this, function (_a) {
|
|
130
|
+
switch (_a.label) {
|
|
131
|
+
case 0:
|
|
132
|
+
packages = [];
|
|
133
|
+
seen = new Set();
|
|
134
|
+
searchPaths = [
|
|
135
|
+
this.monorepoRoot,
|
|
136
|
+
(0, node_path_1.join)(this.monorepoRoot, "packages"),
|
|
137
|
+
(0, node_path_1.join)(this.monorepoRoot, "packages/src"),
|
|
138
|
+
(0, node_path_1.join)(this.monorepoRoot, "apps"),
|
|
139
|
+
(0, node_path_1.join)(this.monorepoRoot, "MCP/packages"),
|
|
140
|
+
];
|
|
141
|
+
_i = 0, searchPaths_1 = searchPaths;
|
|
142
|
+
_a.label = 1;
|
|
143
|
+
case 1:
|
|
144
|
+
if (!(_i < searchPaths_1.length)) return [3 /*break*/, 4];
|
|
145
|
+
searchPath = searchPaths_1[_i];
|
|
146
|
+
if (!(0, node_fs_1.existsSync)(searchPath))
|
|
147
|
+
return [3 /*break*/, 3];
|
|
148
|
+
return [4 /*yield*/, this.searchDirectory(searchPath, packages, seen, 0, 4)];
|
|
149
|
+
case 2:
|
|
150
|
+
_a.sent();
|
|
151
|
+
_a.label = 3;
|
|
152
|
+
case 3:
|
|
153
|
+
_i++;
|
|
154
|
+
return [3 /*break*/, 1];
|
|
155
|
+
case 4: return [2 /*return*/, packages];
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
};
|
|
160
|
+
/**
|
|
161
|
+
* Recursively search for package.json files
|
|
162
|
+
*/
|
|
163
|
+
DependencyGraphBuilder.prototype.searchDirectory = function (dir, packages, seen, depth, maxDepth) {
|
|
164
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
165
|
+
var entries, _i, entries_1, entry, fullPath, packageDir, relativePath, pkg, _a;
|
|
166
|
+
return __generator(this, function (_b) {
|
|
167
|
+
switch (_b.label) {
|
|
168
|
+
case 0:
|
|
169
|
+
if (depth > maxDepth)
|
|
170
|
+
return [2 /*return*/];
|
|
171
|
+
_b.label = 1;
|
|
172
|
+
case 1:
|
|
173
|
+
_b.trys.push([1, 7, , 8]);
|
|
174
|
+
entries = (0, node_fs_1.readdirSync)(dir, { withFileTypes: true });
|
|
175
|
+
_i = 0, entries_1 = entries;
|
|
176
|
+
_b.label = 2;
|
|
177
|
+
case 2:
|
|
178
|
+
if (!(_i < entries_1.length)) return [3 /*break*/, 6];
|
|
179
|
+
entry = entries_1[_i];
|
|
180
|
+
// Skip node_modules and hidden dirs
|
|
181
|
+
if (entry.name === "node_modules" || entry.name.startsWith("."))
|
|
182
|
+
return [3 /*break*/, 5];
|
|
183
|
+
if (entry.name === "dist" || entry.name === "build")
|
|
184
|
+
return [3 /*break*/, 5];
|
|
185
|
+
fullPath = (0, node_path_1.join)(dir, entry.name);
|
|
186
|
+
if (!entry.isDirectory()) return [3 /*break*/, 4];
|
|
187
|
+
return [4 /*yield*/, this.searchDirectory(fullPath, packages, seen, depth + 1, maxDepth)];
|
|
188
|
+
case 3:
|
|
189
|
+
_b.sent();
|
|
190
|
+
return [3 /*break*/, 5];
|
|
191
|
+
case 4:
|
|
192
|
+
if (entry.name === "package.json") {
|
|
193
|
+
packageDir = (0, node_path_1.dirname)(fullPath);
|
|
194
|
+
relativePath = (0, node_path_1.relative)(this.monorepoRoot, packageDir);
|
|
195
|
+
if (seen.has(relativePath))
|
|
196
|
+
return [3 /*break*/, 5];
|
|
197
|
+
seen.add(relativePath);
|
|
198
|
+
try {
|
|
199
|
+
pkg = JSON.parse((0, node_fs_1.readFileSync)(fullPath, "utf-8"));
|
|
200
|
+
if (pkg.name && !pkg.private) {
|
|
201
|
+
packages.push({
|
|
202
|
+
name: pkg.name,
|
|
203
|
+
path: relativePath,
|
|
204
|
+
version: pkg.version || "0.0.0",
|
|
205
|
+
});
|
|
206
|
+
this.packageCache.set(pkg.name, { path: relativePath, pkg: pkg });
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
catch (_c) {
|
|
210
|
+
// Invalid package.json, skip
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
_b.label = 5;
|
|
214
|
+
case 5:
|
|
215
|
+
_i++;
|
|
216
|
+
return [3 /*break*/, 2];
|
|
217
|
+
case 6: return [3 /*break*/, 8];
|
|
218
|
+
case 7:
|
|
219
|
+
_a = _b.sent();
|
|
220
|
+
return [3 /*break*/, 8];
|
|
221
|
+
case 8: return [2 /*return*/];
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
};
|
|
226
|
+
/**
|
|
227
|
+
* Analyze package.json dependencies
|
|
228
|
+
*/
|
|
229
|
+
DependencyGraphBuilder.prototype.analyzePackageDependencies = function (pkg, includeDev, excludePatterns) {
|
|
230
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
231
|
+
var pkgPath, packageJson, depTypes, _i, depTypes_1, depType, deps, _loop_1, this_1, _a, _b, _c, depName, depVersion;
|
|
232
|
+
return __generator(this, function (_d) {
|
|
233
|
+
pkgPath = (0, node_path_1.join)(this.monorepoRoot, pkg.path, "package.json");
|
|
234
|
+
if (!(0, node_fs_1.existsSync)(pkgPath))
|
|
235
|
+
return [2 /*return*/];
|
|
236
|
+
packageJson = JSON.parse((0, node_fs_1.readFileSync)(pkgPath, "utf-8"));
|
|
237
|
+
depTypes = ["dependencies"];
|
|
238
|
+
if (includeDev)
|
|
239
|
+
depTypes.push("devDependencies", "peerDependencies", "optionalDependencies");
|
|
240
|
+
for (_i = 0, depTypes_1 = depTypes; _i < depTypes_1.length; _i++) {
|
|
241
|
+
depType = depTypes_1[_i];
|
|
242
|
+
deps = packageJson[depType];
|
|
243
|
+
if (!deps)
|
|
244
|
+
continue;
|
|
245
|
+
_loop_1 = function (depName, depVersion) {
|
|
246
|
+
// Check if this matches any exclude pattern
|
|
247
|
+
if (excludePatterns.some(function (pattern) { return depName.match(pattern); }))
|
|
248
|
+
return "continue";
|
|
249
|
+
var isWorkspace = depVersion === "workspace:*" || depVersion === "workspace:^" || depVersion === "workspace:~";
|
|
250
|
+
if (isWorkspace) {
|
|
251
|
+
// This is a workspace dependency
|
|
252
|
+
// Find the actual package in our cache
|
|
253
|
+
var targetPkg = this_1.packageCache.get(depName);
|
|
254
|
+
if (targetPkg) {
|
|
255
|
+
this_1.addEdge(pkg.name, depName, "workspace");
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
else if (this_1.packageCache.has(depName)) {
|
|
259
|
+
// It's a local package but not using workspace: protocol
|
|
260
|
+
this_1.addEdge(pkg.name, depName, "workspace");
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
// External dependency
|
|
264
|
+
this_1.addNode(depName, "", "external", depVersion);
|
|
265
|
+
this_1.addEdge(pkg.name, depName, "external");
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
this_1 = this;
|
|
269
|
+
for (_a = 0, _b = Object.entries(deps); _a < _b.length; _a++) {
|
|
270
|
+
_c = _b[_a], depName = _c[0], depVersion = _c[1];
|
|
271
|
+
_loop_1(depName, depVersion);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
return [2 /*return*/];
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
};
|
|
278
|
+
/**
|
|
279
|
+
* Analyze TypeScript/JavaScript imports
|
|
280
|
+
*/
|
|
281
|
+
DependencyGraphBuilder.prototype.analyzeImports = function (pkg) {
|
|
282
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
283
|
+
var pkgDir, sourceDirs, _i, sourceDirs_1, sourceDir, searchPath;
|
|
284
|
+
return __generator(this, function (_a) {
|
|
285
|
+
switch (_a.label) {
|
|
286
|
+
case 0:
|
|
287
|
+
pkgDir = (0, node_path_1.join)(this.monorepoRoot, pkg.path);
|
|
288
|
+
sourceDirs = ["src", "lib", ""];
|
|
289
|
+
_i = 0, sourceDirs_1 = sourceDirs;
|
|
290
|
+
_a.label = 1;
|
|
291
|
+
case 1:
|
|
292
|
+
if (!(_i < sourceDirs_1.length)) return [3 /*break*/, 4];
|
|
293
|
+
sourceDir = sourceDirs_1[_i];
|
|
294
|
+
searchPath = sourceDir ? (0, node_path_1.join)(pkgDir, sourceDir) : pkgDir;
|
|
295
|
+
if (!(0, node_fs_1.existsSync)(searchPath))
|
|
296
|
+
return [3 /*break*/, 3];
|
|
297
|
+
return [4 /*yield*/, this.analyzeImportsInDirectory(pkg.name, searchPath)];
|
|
298
|
+
case 2:
|
|
299
|
+
_a.sent();
|
|
300
|
+
_a.label = 3;
|
|
301
|
+
case 3:
|
|
302
|
+
_i++;
|
|
303
|
+
return [3 /*break*/, 1];
|
|
304
|
+
case 4: return [2 /*return*/];
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
};
|
|
309
|
+
/**
|
|
310
|
+
* Recursively analyze imports in a directory
|
|
311
|
+
*/
|
|
312
|
+
DependencyGraphBuilder.prototype.analyzeImportsInDirectory = function (packageName, dir) {
|
|
313
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
314
|
+
var entries, _i, entries_2, entry, fullPath, _a;
|
|
315
|
+
return __generator(this, function (_b) {
|
|
316
|
+
switch (_b.label) {
|
|
317
|
+
case 0:
|
|
318
|
+
_b.trys.push([0, 7, , 8]);
|
|
319
|
+
entries = (0, node_fs_1.readdirSync)(dir, { withFileTypes: true });
|
|
320
|
+
_i = 0, entries_2 = entries;
|
|
321
|
+
_b.label = 1;
|
|
322
|
+
case 1:
|
|
323
|
+
if (!(_i < entries_2.length)) return [3 /*break*/, 6];
|
|
324
|
+
entry = entries_2[_i];
|
|
325
|
+
if (entry.name === "node_modules" || entry.name.startsWith("."))
|
|
326
|
+
return [3 /*break*/, 5];
|
|
327
|
+
if (entry.name === "dist" || entry.name === "build")
|
|
328
|
+
return [3 /*break*/, 5];
|
|
329
|
+
fullPath = (0, node_path_1.join)(dir, entry.name);
|
|
330
|
+
if (!entry.isDirectory()) return [3 /*break*/, 3];
|
|
331
|
+
return [4 /*yield*/, this.analyzeImportsInDirectory(packageName, fullPath)];
|
|
332
|
+
case 2:
|
|
333
|
+
_b.sent();
|
|
334
|
+
return [3 /*break*/, 5];
|
|
335
|
+
case 3:
|
|
336
|
+
if (!(entry.name.endsWith(".ts") || entry.name.endsWith(".tsx") || entry.name.endsWith(".js") || entry.name.endsWith(".jsx") || entry.name.endsWith(".mjs"))) return [3 /*break*/, 5];
|
|
337
|
+
return [4 /*yield*/, this.analyzeImportsInFile(packageName, fullPath)];
|
|
338
|
+
case 4:
|
|
339
|
+
_b.sent();
|
|
340
|
+
_b.label = 5;
|
|
341
|
+
case 5:
|
|
342
|
+
_i++;
|
|
343
|
+
return [3 /*break*/, 1];
|
|
344
|
+
case 6: return [3 /*break*/, 8];
|
|
345
|
+
case 7:
|
|
346
|
+
_a = _b.sent();
|
|
347
|
+
return [3 /*break*/, 8];
|
|
348
|
+
case 8: return [2 /*return*/];
|
|
349
|
+
}
|
|
350
|
+
});
|
|
351
|
+
});
|
|
352
|
+
};
|
|
353
|
+
/**
|
|
354
|
+
* Analyze imports in a single file
|
|
355
|
+
*/
|
|
356
|
+
DependencyGraphBuilder.prototype.analyzeImportsInFile = function (packageName, filePath) {
|
|
357
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
358
|
+
var content, importPatterns, _i, importPatterns_1, pattern, match, importPath, _a, _b, _c, pkgName, pkgData;
|
|
359
|
+
return __generator(this, function (_d) {
|
|
360
|
+
try {
|
|
361
|
+
content = (0, node_fs_1.readFileSync)(filePath, "utf-8");
|
|
362
|
+
importPatterns = [
|
|
363
|
+
// ES imports: import ... from '...' | import ... from "..."
|
|
364
|
+
/import\s+(?:(?:\{[^}]*\}|\*\s+as\s+\w+|\w+)\s*,?\s*)*\s+from\s+['"]([^'"]+)['"]/g,
|
|
365
|
+
// Dynamic imports: import('...')
|
|
366
|
+
/import\(['"]([^'"]+)['"]\)/g,
|
|
367
|
+
// require(): require('...') | require("...")
|
|
368
|
+
/require\(['"]([^'"]+)['"]\)/g,
|
|
369
|
+
// Export from: export ... from '...'
|
|
370
|
+
/export\s+(?:(?:\{[^}]*\}|\*\s+as\s+\w+)\s+from\s+)?['"]([^'"]+)['"]/g,
|
|
371
|
+
];
|
|
372
|
+
for (_i = 0, importPatterns_1 = importPatterns; _i < importPatterns_1.length; _i++) {
|
|
373
|
+
pattern = importPatterns_1[_i];
|
|
374
|
+
match = void 0;
|
|
375
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
376
|
+
importPath = match[1];
|
|
377
|
+
// Skip relative imports
|
|
378
|
+
if (importPath.startsWith(".") || importPath.startsWith("/"))
|
|
379
|
+
continue;
|
|
380
|
+
// Check if this is a known workspace package
|
|
381
|
+
for (_a = 0, _b = this.packageCache; _a < _b.length; _a++) {
|
|
382
|
+
_c = _b[_a], pkgName = _c[0], pkgData = _c[1];
|
|
383
|
+
if (importPath === pkgName || importPath.startsWith(pkgName + "/")) {
|
|
384
|
+
this.addEdge(packageName, pkgName, "import", importPath);
|
|
385
|
+
break;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
catch (_e) {
|
|
392
|
+
// File not readable
|
|
393
|
+
}
|
|
394
|
+
return [2 /*return*/];
|
|
395
|
+
});
|
|
396
|
+
});
|
|
397
|
+
};
|
|
398
|
+
/**
|
|
399
|
+
* Add a node to the graph
|
|
400
|
+
*/
|
|
401
|
+
DependencyGraphBuilder.prototype.addNode = function (name, path, type, version) {
|
|
402
|
+
if (!this.graph.nodes.has(name)) {
|
|
403
|
+
this.graph.nodes.set(name, { name: name, path: path, type: type, version: version });
|
|
404
|
+
this.graph.reverseEdges.set(name, new Set());
|
|
405
|
+
}
|
|
406
|
+
};
|
|
407
|
+
/**
|
|
408
|
+
* Add an edge to the graph
|
|
409
|
+
*/
|
|
410
|
+
DependencyGraphBuilder.prototype.addEdge = function (from, to, type, importPath) {
|
|
411
|
+
// Skip self-references
|
|
412
|
+
if (from === to)
|
|
413
|
+
return;
|
|
414
|
+
// Check if edge already exists
|
|
415
|
+
var existing = this.graph.edges.find(function (e) { return e.from === from && e.to === to; });
|
|
416
|
+
if (existing)
|
|
417
|
+
return;
|
|
418
|
+
this.graph.edges.push({ from: from, to: to, type: type, importPath: importPath });
|
|
419
|
+
// Update reverse edges
|
|
420
|
+
if (!this.graph.reverseEdges.has(to)) {
|
|
421
|
+
this.graph.reverseEdges.set(to, new Set());
|
|
422
|
+
}
|
|
423
|
+
this.graph.reverseEdges.get(to).add(from);
|
|
424
|
+
};
|
|
425
|
+
/**
|
|
426
|
+
* Build reverse edges for impact analysis
|
|
427
|
+
*/
|
|
428
|
+
DependencyGraphBuilder.prototype.buildReverseEdges = function () {
|
|
429
|
+
for (var _i = 0, _a = this.graph.reverseEdges; _i < _a.length; _i++) {
|
|
430
|
+
var _b = _a[_i], to = _b[0], dependents = _b[1];
|
|
431
|
+
// Ensure node exists
|
|
432
|
+
if (!this.graph.nodes.has(to)) {
|
|
433
|
+
this.graph.nodes.set(to, { name: to, path: "", type: "external" });
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
};
|
|
437
|
+
/**
|
|
438
|
+
* Get the built graph
|
|
439
|
+
*/
|
|
440
|
+
DependencyGraphBuilder.prototype.getGraph = function () {
|
|
441
|
+
return this.graph;
|
|
442
|
+
};
|
|
443
|
+
return DependencyGraphBuilder;
|
|
444
|
+
}());
|
|
445
|
+
// ==============
|
|
446
|
+
// MCP Server
|
|
447
|
+
// ==============
|
|
448
|
+
var DEPENDENCY_GRAPH_SCHEMA = {
|
|
449
|
+
name: "dependency_graph",
|
|
450
|
+
description: "Build a complete dependency graph of the monorepo",
|
|
451
|
+
inputSchema: {
|
|
452
|
+
type: "object",
|
|
453
|
+
properties: {
|
|
454
|
+
includeDevDependencies: {
|
|
455
|
+
type: "boolean",
|
|
456
|
+
description: "Include devDependencies in the graph",
|
|
457
|
+
default: false,
|
|
458
|
+
},
|
|
459
|
+
analyzeImports: {
|
|
460
|
+
type: "boolean",
|
|
461
|
+
description: "Analyze TypeScript/JavaScript imports",
|
|
462
|
+
default: true,
|
|
463
|
+
},
|
|
464
|
+
excludePatterns: {
|
|
465
|
+
type: "array",
|
|
466
|
+
items: { type: "string" },
|
|
467
|
+
description: "Regex patterns to exclude from dependency analysis",
|
|
468
|
+
default: [],
|
|
469
|
+
},
|
|
470
|
+
format: {
|
|
471
|
+
type: "string",
|
|
472
|
+
enum: ["json", "mermaid", "dot", "tree"],
|
|
473
|
+
description: "Output format for the graph",
|
|
474
|
+
default: "json",
|
|
475
|
+
},
|
|
476
|
+
},
|
|
477
|
+
},
|
|
478
|
+
};
|
|
479
|
+
var IMPACT_ANALYSIS_SCHEMA = {
|
|
480
|
+
name: "impact_analysis",
|
|
481
|
+
description: "Analyze the impact of changing a specific package",
|
|
482
|
+
inputSchema: {
|
|
483
|
+
type: "object",
|
|
484
|
+
properties: {
|
|
485
|
+
package: {
|
|
486
|
+
type: "string",
|
|
487
|
+
description: "Package name to analyze",
|
|
488
|
+
},
|
|
489
|
+
includeTransitive: {
|
|
490
|
+
type: "boolean",
|
|
491
|
+
description: "Include transitive dependents",
|
|
492
|
+
default: true,
|
|
493
|
+
},
|
|
494
|
+
format: {
|
|
495
|
+
type: "string",
|
|
496
|
+
enum: ["json", "tree"],
|
|
497
|
+
description: "Output format",
|
|
498
|
+
default: "tree",
|
|
499
|
+
},
|
|
500
|
+
},
|
|
501
|
+
required: ["package"],
|
|
502
|
+
},
|
|
503
|
+
};
|
|
504
|
+
var FIND_CIRCULAR_SCHEMA = {
|
|
505
|
+
name: "find_circular",
|
|
506
|
+
description: "Find circular dependencies in the monorepo",
|
|
507
|
+
inputSchema: {
|
|
508
|
+
type: "object",
|
|
509
|
+
properties: {
|
|
510
|
+
maxDepth: {
|
|
511
|
+
type: "number",
|
|
512
|
+
description: "Maximum depth to search for cycles",
|
|
513
|
+
default: 10,
|
|
514
|
+
},
|
|
515
|
+
},
|
|
516
|
+
},
|
|
517
|
+
};
|
|
518
|
+
var UNUSED_CODE_SCHEMA = {
|
|
519
|
+
name: "unused_code",
|
|
520
|
+
description: "Find potentially unused packages (no dependents)",
|
|
521
|
+
inputSchema: {
|
|
522
|
+
type: "object",
|
|
523
|
+
properties: {
|
|
524
|
+
includeExternal: {
|
|
525
|
+
type: "boolean",
|
|
526
|
+
description: "Include external dependencies",
|
|
527
|
+
default: false,
|
|
528
|
+
},
|
|
529
|
+
},
|
|
530
|
+
},
|
|
531
|
+
};
|
|
532
|
+
var PACKAGE_INFO_SCHEMA = {
|
|
533
|
+
name: "package_info",
|
|
534
|
+
description: "Get detailed information about a specific package",
|
|
535
|
+
inputSchema: {
|
|
536
|
+
type: "object",
|
|
537
|
+
properties: {
|
|
538
|
+
package: {
|
|
539
|
+
type: "string",
|
|
540
|
+
description: "Package name",
|
|
541
|
+
},
|
|
542
|
+
},
|
|
543
|
+
required: ["package"],
|
|
544
|
+
},
|
|
545
|
+
};
|
|
546
|
+
// Format the graph for output
|
|
547
|
+
function formatGraph(graph, format) {
|
|
548
|
+
switch (format) {
|
|
549
|
+
case "mermaid":
|
|
550
|
+
return formatAsMermaid(graph);
|
|
551
|
+
case "dot":
|
|
552
|
+
return formatAsDot(graph);
|
|
553
|
+
case "tree":
|
|
554
|
+
return formatAsTree(graph);
|
|
555
|
+
case "json":
|
|
556
|
+
default:
|
|
557
|
+
return JSON.stringify({
|
|
558
|
+
nodes: Array.from(graph.nodes.values()),
|
|
559
|
+
edges: graph.edges,
|
|
560
|
+
}, null, 2);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
function formatAsMermaid(graph) {
|
|
564
|
+
var lines = ["graph TD"];
|
|
565
|
+
// Add nodes
|
|
566
|
+
for (var _i = 0, _a = graph.nodes; _i < _a.length; _i++) {
|
|
567
|
+
var _b = _a[_i], name_1 = _b[0], node = _b[1];
|
|
568
|
+
var label = node.type === "workspace" ? "\uD83D\uDCE6 ".concat(name_1) : "\uD83D\uDCDA ".concat(name_1);
|
|
569
|
+
lines.push(" ".concat(name_1.replace(/[^a-zA-Z0-9]/g, "_"), "[\"").concat(label, "\"]"));
|
|
570
|
+
}
|
|
571
|
+
// Add edges
|
|
572
|
+
for (var _c = 0, _d = graph.edges; _c < _d.length; _c++) {
|
|
573
|
+
var edge = _d[_c];
|
|
574
|
+
var from = edge.from.replace(/[^a-zA-Z0-9]/g, "_");
|
|
575
|
+
var to = edge.to.replace(/[^a-zA-Z0-9]/g, "_");
|
|
576
|
+
var label = edge.type === "workspace" ? "workspace" : edge.type === "import" ? "imports" : "external";
|
|
577
|
+
lines.push(" ".concat(from, " -->|").concat(label, "| ").concat(to));
|
|
578
|
+
}
|
|
579
|
+
// Add styles
|
|
580
|
+
lines.push(' classDef workspace fill:#e1f5fe');
|
|
581
|
+
lines.push(' classDef external fill:#f5f5f5');
|
|
582
|
+
lines.push(' classDef import fill:#fff3e0');
|
|
583
|
+
for (var _e = 0, _f = graph.nodes; _e < _f.length; _e++) {
|
|
584
|
+
var _g = _f[_e], name_2 = _g[0], node = _g[1];
|
|
585
|
+
var id = name_2.replace(/[^a-zA-Z0-9]/g, "_");
|
|
586
|
+
if (node.type === "workspace") {
|
|
587
|
+
lines.push(" class ".concat(id, " workspace"));
|
|
588
|
+
}
|
|
589
|
+
else if (node.type === "external") {
|
|
590
|
+
lines.push(" class ".concat(id, " external"));
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
return lines.join("\n");
|
|
594
|
+
}
|
|
595
|
+
function formatAsDot(graph) {
|
|
596
|
+
var lines = ["digraph dependencies {"];
|
|
597
|
+
lines.push(' rankdir=LR;');
|
|
598
|
+
lines.push(' node [shape=box];');
|
|
599
|
+
// Add nodes
|
|
600
|
+
for (var _i = 0, _a = graph.nodes; _i < _a.length; _i++) {
|
|
601
|
+
var _b = _a[_i], name_3 = _b[0], node = _b[1];
|
|
602
|
+
var color = node.type === "workspace" ? "lightblue" : "lightgray";
|
|
603
|
+
lines.push(" \"".concat(name_3, "\" [fillcolor=").concat(color, ", style=filled];"));
|
|
604
|
+
}
|
|
605
|
+
// Add edges
|
|
606
|
+
for (var _c = 0, _d = graph.edges; _c < _d.length; _c++) {
|
|
607
|
+
var edge = _d[_c];
|
|
608
|
+
var style = edge.type === "workspace" ? "solid" : "dashed";
|
|
609
|
+
lines.push(" \"".concat(edge.from, "\" -> \"").concat(edge.to, "\" [style=").concat(style, ", label=\"").concat(edge.type, "\"];"));
|
|
610
|
+
}
|
|
611
|
+
lines.push("}");
|
|
612
|
+
return lines.join("\n");
|
|
613
|
+
}
|
|
614
|
+
function formatAsTree(graph) {
|
|
615
|
+
var _a;
|
|
616
|
+
var lines = [];
|
|
617
|
+
var seen = new Set();
|
|
618
|
+
// Find root nodes (no incoming edges from other workspace packages)
|
|
619
|
+
var workspaceNodes = Array.from(graph.nodes.values()).filter(function (n) { return n.type === "workspace"; });
|
|
620
|
+
var incomingEdges = new Map();
|
|
621
|
+
for (var _i = 0, workspaceNodes_1 = workspaceNodes; _i < workspaceNodes_1.length; _i++) {
|
|
622
|
+
var node = workspaceNodes_1[_i];
|
|
623
|
+
incomingEdges.set(node.name, 0);
|
|
624
|
+
}
|
|
625
|
+
for (var _b = 0, _c = graph.edges; _b < _c.length; _b++) {
|
|
626
|
+
var edge = _c[_b];
|
|
627
|
+
if (((_a = graph.nodes.get(edge.to)) === null || _a === void 0 ? void 0 : _a.type) === "workspace") {
|
|
628
|
+
incomingEdges.set(edge.to, (incomingEdges.get(edge.to) || 0) + 1);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
// Start from roots
|
|
632
|
+
for (var _d = 0, _e = graph.nodes; _d < _e.length; _d++) {
|
|
633
|
+
var _f = _e[_d], name_4 = _f[0], node = _f[1];
|
|
634
|
+
if (node.type === "workspace" && (incomingEdges.get(name_4) || 0) === 0) {
|
|
635
|
+
lines.push("\uD83D\uDCE6 ".concat(name_4));
|
|
636
|
+
printTree(graph, name_4, "", seen, lines);
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
// Add any disconnected nodes
|
|
640
|
+
for (var _g = 0, _h = graph.nodes; _g < _h.length; _g++) {
|
|
641
|
+
var _j = _h[_g], name_5 = _j[0], node = _j[1];
|
|
642
|
+
if (!seen.has(name_5) && node.type === "workspace") {
|
|
643
|
+
lines.push("\uD83D\uDCE6 ".concat(name_5, " (disconnected)"));
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
return lines.join("\n");
|
|
647
|
+
}
|
|
648
|
+
function printTree(graph, nodeName, prefix, seen, lines) {
|
|
649
|
+
seen.add(nodeName);
|
|
650
|
+
// Find outgoing edges to other workspace packages
|
|
651
|
+
var outgoing = graph.edges.filter(function (e) { var _a; return e.from === nodeName && ((_a = graph.nodes.get(e.to)) === null || _a === void 0 ? void 0 : _a.type) === "workspace"; });
|
|
652
|
+
for (var i = 0; i < outgoing.length; i++) {
|
|
653
|
+
var edge = outgoing[i];
|
|
654
|
+
var isLast = i === outgoing.length - 1;
|
|
655
|
+
var connector = isLast ? "└──" : "├──";
|
|
656
|
+
var childPrefix = prefix + (isLast ? " " : "│ ");
|
|
657
|
+
lines.push("".concat(prefix).concat(connector, " \uD83D\uDCE6 ").concat(edge.to, " [").concat(edge.type, "]"));
|
|
658
|
+
if (!seen.has(edge.to)) {
|
|
659
|
+
printTree(graph, edge.to, childPrefix, seen, lines);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
// Show external dependencies count
|
|
663
|
+
var externals = graph.edges.filter(function (e) { var _a; return e.from === nodeName && ((_a = graph.nodes.get(e.to)) === null || _a === void 0 ? void 0 : _a.type) === "external"; });
|
|
664
|
+
if (externals.length > 0) {
|
|
665
|
+
lines.push("".concat(prefix, "\u2514\u2500\u2500 \uD83D\uDCDA ").concat(externals.length, " external dependencies"));
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
// Find circular dependencies using DFS
|
|
669
|
+
function findCircularDependencies(graph, maxDepth) {
|
|
670
|
+
if (maxDepth === void 0) { maxDepth = 10; }
|
|
671
|
+
var cycles = [];
|
|
672
|
+
var visited = new Set();
|
|
673
|
+
var recursionStack = new Set();
|
|
674
|
+
function dfs(node, path) {
|
|
675
|
+
if (path.length > maxDepth)
|
|
676
|
+
return;
|
|
677
|
+
visited.add(node);
|
|
678
|
+
recursionStack.add(node);
|
|
679
|
+
path.push(node);
|
|
680
|
+
// Check all outgoing edges
|
|
681
|
+
for (var _i = 0, _a = graph.edges; _i < _a.length; _i++) {
|
|
682
|
+
var edge = _a[_i];
|
|
683
|
+
if (edge.from === node) {
|
|
684
|
+
if (recursionStack.has(edge.to)) {
|
|
685
|
+
// Found a cycle
|
|
686
|
+
var cycleStart = path.indexOf(edge.to);
|
|
687
|
+
if (cycleStart >= 0) {
|
|
688
|
+
cycles.push(__spreadArray(__spreadArray([], path.slice(cycleStart), true), [edge.to], false));
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
else if (!visited.has(edge.to)) {
|
|
692
|
+
dfs(edge.to, __spreadArray([], path, true));
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
recursionStack.delete(node);
|
|
697
|
+
}
|
|
698
|
+
// Start DFS from each workspace node
|
|
699
|
+
for (var _i = 0, _a = graph.nodes; _i < _a.length; _i++) {
|
|
700
|
+
var _b = _a[_i], name_6 = _b[0], node = _b[1];
|
|
701
|
+
if (node.type === "workspace" && !visited.has(name_6)) {
|
|
702
|
+
dfs(name_6, []);
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
return cycles;
|
|
706
|
+
}
|
|
707
|
+
// Impact analysis
|
|
708
|
+
function analyzeImpact(graph, packageName, includeTransitive) {
|
|
709
|
+
if (includeTransitive === void 0) { includeTransitive = true; }
|
|
710
|
+
var direct = [];
|
|
711
|
+
var transitive = [];
|
|
712
|
+
var visited = new Set();
|
|
713
|
+
// Get direct dependents
|
|
714
|
+
var directDependents = graph.reverseEdges.get(packageName);
|
|
715
|
+
if (directDependents) {
|
|
716
|
+
for (var _i = 0, directDependents_1 = directDependents; _i < directDependents_1.length; _i++) {
|
|
717
|
+
var dep = directDependents_1[_i];
|
|
718
|
+
direct.push(dep);
|
|
719
|
+
visited.add(dep);
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
// Get transitive dependents
|
|
723
|
+
if (includeTransitive) {
|
|
724
|
+
for (var _a = 0, direct_1 = direct; _a < direct_1.length; _a++) {
|
|
725
|
+
var dep = direct_1[_a];
|
|
726
|
+
collectTransitive(graph, dep, visited, transitive);
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
return {
|
|
730
|
+
direct: direct,
|
|
731
|
+
transitive: transitive,
|
|
732
|
+
all: Array.from(visited),
|
|
733
|
+
};
|
|
734
|
+
}
|
|
735
|
+
function collectTransitive(graph, packageName, visited, result) {
|
|
736
|
+
var dependents = graph.reverseEdges.get(packageName);
|
|
737
|
+
if (!dependents)
|
|
738
|
+
return;
|
|
739
|
+
for (var _i = 0, dependents_1 = dependents; _i < dependents_1.length; _i++) {
|
|
740
|
+
var dep = dependents_1[_i];
|
|
741
|
+
if (!visited.has(dep)) {
|
|
742
|
+
visited.add(dep);
|
|
743
|
+
result.push(dep);
|
|
744
|
+
collectTransitive(graph, dep, visited, result);
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
// Start the MCP server
|
|
749
|
+
var server = new index_js_1.Server({
|
|
750
|
+
name: "@mcp/dependency-graph",
|
|
751
|
+
version: "0.1.0",
|
|
752
|
+
}, {
|
|
753
|
+
capabilities: {
|
|
754
|
+
tools: {},
|
|
755
|
+
},
|
|
756
|
+
});
|
|
757
|
+
var cachedGraph = null;
|
|
758
|
+
var cachedBuilder = null;
|
|
759
|
+
// List tools
|
|
760
|
+
server.setRequestHandler(types_js_1.ListToolsRequestSchema, function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
761
|
+
return __generator(this, function (_a) {
|
|
762
|
+
return [2 /*return*/, ({
|
|
763
|
+
tools: [
|
|
764
|
+
DEPENDENCY_GRAPH_SCHEMA,
|
|
765
|
+
IMPACT_ANALYSIS_SCHEMA,
|
|
766
|
+
FIND_CIRCULAR_SCHEMA,
|
|
767
|
+
UNUSED_CODE_SCHEMA,
|
|
768
|
+
PACKAGE_INFO_SCHEMA,
|
|
769
|
+
],
|
|
770
|
+
})];
|
|
771
|
+
});
|
|
772
|
+
}); });
|
|
773
|
+
// Handle tool calls
|
|
774
|
+
server.setRequestHandler(types_js_1.CallToolRequestSchema, function (request) { return __awaiter(void 0, void 0, void 0, function () {
|
|
775
|
+
var _a, name, args, monorepoRoot, _b, _c, _d, includeDevDependencies, _e, analyzeImports, _f, excludePatterns, _g, format, graph, _h, packageName, _j, includeTransitive, _k, format, impact, lines, _i, _l, dep, _m, _o, dep, _p, maxDepth, cycles, lines, i, _q, includeExternal, unused, _r, _s, _t, name_7, node, dependents, packageName_1, node, dependencies, dependents, lines, _u, dependencies_1, dep, depNode, _v, dependents_2, dep, error_1;
|
|
776
|
+
return __generator(this, function (_w) {
|
|
777
|
+
switch (_w.label) {
|
|
778
|
+
case 0:
|
|
779
|
+
_a = request.params, name = _a.name, args = _a.arguments;
|
|
780
|
+
// Initialize graph builder if needed
|
|
781
|
+
if (!cachedBuilder) {
|
|
782
|
+
monorepoRoot = process.cwd();
|
|
783
|
+
cachedBuilder = new DependencyGraphBuilder(monorepoRoot);
|
|
784
|
+
}
|
|
785
|
+
if (!!cachedGraph) return [3 /*break*/, 2];
|
|
786
|
+
return [4 /*yield*/, cachedBuilder.build()];
|
|
787
|
+
case 1:
|
|
788
|
+
_w.sent();
|
|
789
|
+
cachedGraph = cachedBuilder.getGraph();
|
|
790
|
+
_w.label = 2;
|
|
791
|
+
case 2:
|
|
792
|
+
_w.trys.push([2, 11, , 12]);
|
|
793
|
+
_b = name;
|
|
794
|
+
switch (_b) {
|
|
795
|
+
case "dependency_graph": return [3 /*break*/, 3];
|
|
796
|
+
case "impact_analysis": return [3 /*break*/, 5];
|
|
797
|
+
case "find_circular": return [3 /*break*/, 6];
|
|
798
|
+
case "unused_code": return [3 /*break*/, 7];
|
|
799
|
+
case "package_info": return [3 /*break*/, 8];
|
|
800
|
+
}
|
|
801
|
+
return [3 /*break*/, 9];
|
|
802
|
+
case 3:
|
|
803
|
+
_c = args, _d = _c.includeDevDependencies, includeDevDependencies = _d === void 0 ? false : _d, _e = _c.analyzeImports, analyzeImports = _e === void 0 ? true : _e, _f = _c.excludePatterns, excludePatterns = _f === void 0 ? [] : _f, _g = _c.format, format = _g === void 0 ? "json" : _g;
|
|
804
|
+
return [4 /*yield*/, cachedBuilder.build({ includeDevDependencies: includeDevDependencies, analyzeImports: analyzeImports, excludePatterns: excludePatterns })];
|
|
805
|
+
case 4:
|
|
806
|
+
_w.sent();
|
|
807
|
+
graph = cachedBuilder.getGraph();
|
|
808
|
+
cachedGraph = graph;
|
|
809
|
+
return [2 /*return*/, {
|
|
810
|
+
content: [{ type: "text", text: formatGraph(graph, format) }],
|
|
811
|
+
}];
|
|
812
|
+
case 5:
|
|
813
|
+
{
|
|
814
|
+
_h = args, packageName = _h.package, _j = _h.includeTransitive, includeTransitive = _j === void 0 ? true : _j, _k = _h.format, format = _k === void 0 ? "tree" : _k;
|
|
815
|
+
impact = analyzeImpact(cachedGraph, packageName, includeTransitive);
|
|
816
|
+
if (format === "json") {
|
|
817
|
+
return [2 /*return*/, {
|
|
818
|
+
content: [{ type: "text", text: JSON.stringify(impact, null, 2) }],
|
|
819
|
+
}];
|
|
820
|
+
}
|
|
821
|
+
else {
|
|
822
|
+
lines = ["Impact analysis for: ".concat(packageName)];
|
|
823
|
+
lines.push("\nDirect dependents (".concat(impact.direct.length, "):"));
|
|
824
|
+
for (_i = 0, _l = impact.direct; _i < _l.length; _i++) {
|
|
825
|
+
dep = _l[_i];
|
|
826
|
+
lines.push(" \u2514\u2500\u2500 ".concat(dep));
|
|
827
|
+
}
|
|
828
|
+
if (includeTransitive && impact.transitive.length > 0) {
|
|
829
|
+
lines.push("\nTransitive dependents (".concat(impact.transitive.length, "):"));
|
|
830
|
+
for (_m = 0, _o = impact.transitive; _m < _o.length; _m++) {
|
|
831
|
+
dep = _o[_m];
|
|
832
|
+
lines.push(" \u2514\u2500\u2500 ".concat(dep));
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
lines.push("\nTotal affected: ".concat(impact.all.length, " packages"));
|
|
836
|
+
return [2 /*return*/, { content: [{ type: "text", text: lines.join("\n") }] }];
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
_w.label = 6;
|
|
840
|
+
case 6:
|
|
841
|
+
{
|
|
842
|
+
_p = args.maxDepth, maxDepth = _p === void 0 ? 10 : _p;
|
|
843
|
+
cycles = findCircularDependencies(cachedGraph, maxDepth);
|
|
844
|
+
if (cycles.length === 0) {
|
|
845
|
+
return [2 /*return*/, {
|
|
846
|
+
content: [{ type: "text", text: "No circular dependencies found!" }],
|
|
847
|
+
}];
|
|
848
|
+
}
|
|
849
|
+
lines = ["Found ".concat(cycles.length, " circular dependencies:\n")];
|
|
850
|
+
for (i = 0; i < cycles.length; i++) {
|
|
851
|
+
lines.push("Cycle ".concat(i + 1, ":"));
|
|
852
|
+
lines.push(" ".concat(cycles[i].join(" → ")));
|
|
853
|
+
lines.push("");
|
|
854
|
+
}
|
|
855
|
+
return [2 /*return*/, { content: [{ type: "text", text: lines.join("\n") }] }];
|
|
856
|
+
}
|
|
857
|
+
_w.label = 7;
|
|
858
|
+
case 7:
|
|
859
|
+
{
|
|
860
|
+
_q = args.includeExternal, includeExternal = _q === void 0 ? false : _q;
|
|
861
|
+
unused = [];
|
|
862
|
+
for (_r = 0, _s = cachedGraph.nodes; _r < _s.length; _r++) {
|
|
863
|
+
_t = _s[_r], name_7 = _t[0], node = _t[1];
|
|
864
|
+
if (node.type === "workspace" || includeExternal) {
|
|
865
|
+
dependents = cachedGraph.reverseEdges.get(name_7);
|
|
866
|
+
if (!dependents || dependents.size === 0) {
|
|
867
|
+
unused.push(name_7);
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
if (unused.length === 0) {
|
|
872
|
+
return [2 /*return*/, {
|
|
873
|
+
content: [{ type: "text", text: "No unused packages found!" }],
|
|
874
|
+
}];
|
|
875
|
+
}
|
|
876
|
+
return [2 /*return*/, {
|
|
877
|
+
content: [
|
|
878
|
+
{
|
|
879
|
+
type: "text",
|
|
880
|
+
text: "Found ".concat(unused.length, " potentially unused packages:\n\n").concat(unused.map(function (n) { return " \u2514\u2500\u2500 ".concat(n); }).join("\n")),
|
|
881
|
+
},
|
|
882
|
+
],
|
|
883
|
+
}];
|
|
884
|
+
}
|
|
885
|
+
_w.label = 8;
|
|
886
|
+
case 8:
|
|
887
|
+
{
|
|
888
|
+
packageName_1 = args.package;
|
|
889
|
+
node = cachedGraph.nodes.get(packageName_1);
|
|
890
|
+
if (!node) {
|
|
891
|
+
return [2 /*return*/, {
|
|
892
|
+
content: [{ type: "text", text: "Package \"".concat(packageName_1, "\" not found in dependency graph.") }],
|
|
893
|
+
}];
|
|
894
|
+
}
|
|
895
|
+
dependencies = cachedGraph.edges.filter(function (e) { return e.from === packageName_1; });
|
|
896
|
+
dependents = Array.from(cachedGraph.reverseEdges.get(packageName_1) || []);
|
|
897
|
+
lines = [
|
|
898
|
+
"Package: ".concat(packageName_1),
|
|
899
|
+
"Type: ".concat(node.type),
|
|
900
|
+
"Path: ".concat(node.path || "N/A"),
|
|
901
|
+
node.version ? "Version: ".concat(node.version) : "",
|
|
902
|
+
"",
|
|
903
|
+
"Dependencies (".concat(dependencies.length, "):"),
|
|
904
|
+
];
|
|
905
|
+
for (_u = 0, dependencies_1 = dependencies; _u < dependencies_1.length; _u++) {
|
|
906
|
+
dep = dependencies_1[_u];
|
|
907
|
+
depNode = cachedGraph.nodes.get(dep.to);
|
|
908
|
+
lines.push(" \u2514\u2500\u2500 ".concat(dep.to, " [").concat(dep.type, "]").concat((depNode === null || depNode === void 0 ? void 0 : depNode.version) ? " @ ".concat(depNode.version) : ""));
|
|
909
|
+
}
|
|
910
|
+
lines.push("", "Dependents (".concat(dependents.length, "):"));
|
|
911
|
+
for (_v = 0, dependents_2 = dependents; _v < dependents_2.length; _v++) {
|
|
912
|
+
dep = dependents_2[_v];
|
|
913
|
+
lines.push(" \u2514\u2500\u2500 ".concat(dep));
|
|
914
|
+
}
|
|
915
|
+
return [2 /*return*/, { content: [{ type: "text", text: lines.join("\n") }] }];
|
|
916
|
+
}
|
|
917
|
+
_w.label = 9;
|
|
918
|
+
case 9: throw new Error("Unknown tool: ".concat(name));
|
|
919
|
+
case 10: return [3 /*break*/, 12];
|
|
920
|
+
case 11:
|
|
921
|
+
error_1 = _w.sent();
|
|
922
|
+
return [2 /*return*/, {
|
|
923
|
+
content: [{ type: "text", text: "Error: ".concat(error_1 instanceof Error ? error_1.message : String(error_1)) }],
|
|
924
|
+
isError: true,
|
|
925
|
+
}];
|
|
926
|
+
case 12: return [2 /*return*/];
|
|
927
|
+
}
|
|
928
|
+
});
|
|
929
|
+
}); });
|
|
930
|
+
// Start server
|
|
931
|
+
function main() {
|
|
932
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
933
|
+
var transport;
|
|
934
|
+
var _this = this;
|
|
935
|
+
return __generator(this, function (_a) {
|
|
936
|
+
switch (_a.label) {
|
|
937
|
+
case 0:
|
|
938
|
+
// Set up error handling
|
|
939
|
+
server.onerror = function (error) { return console.error('[MCP] Error:', error); };
|
|
940
|
+
// Signal handlers for graceful shutdown
|
|
941
|
+
process.on('SIGINT', function () { return __awaiter(_this, void 0, void 0, function () {
|
|
942
|
+
return __generator(this, function (_a) {
|
|
943
|
+
switch (_a.label) {
|
|
944
|
+
case 0:
|
|
945
|
+
console.error('[MCP] Shutting down...');
|
|
946
|
+
return [4 /*yield*/, server.close()];
|
|
947
|
+
case 1:
|
|
948
|
+
_a.sent();
|
|
949
|
+
process.exit(0);
|
|
950
|
+
return [2 /*return*/];
|
|
951
|
+
}
|
|
952
|
+
});
|
|
953
|
+
}); });
|
|
954
|
+
process.on('SIGTERM', function () { return __awaiter(_this, void 0, void 0, function () {
|
|
955
|
+
return __generator(this, function (_a) {
|
|
956
|
+
switch (_a.label) {
|
|
957
|
+
case 0:
|
|
958
|
+
console.error('[MCP] Shutting down...');
|
|
959
|
+
return [4 /*yield*/, server.close()];
|
|
960
|
+
case 1:
|
|
961
|
+
_a.sent();
|
|
962
|
+
process.exit(0);
|
|
963
|
+
return [2 /*return*/];
|
|
964
|
+
}
|
|
965
|
+
});
|
|
966
|
+
}); });
|
|
967
|
+
transport = new stdio_js_1.StdioServerTransport();
|
|
968
|
+
return [4 /*yield*/, server.connect(transport)];
|
|
969
|
+
case 1:
|
|
970
|
+
_a.sent();
|
|
971
|
+
// Log to stderr (doesn't interfere with JSON-RPC)
|
|
972
|
+
console.error('[MCP] @mcp/dependency-graph server running on stdio');
|
|
973
|
+
// Keep stdin open for requests
|
|
974
|
+
process.stdin.resume();
|
|
975
|
+
return [2 /*return*/];
|
|
976
|
+
}
|
|
977
|
+
});
|
|
978
|
+
});
|
|
979
|
+
}
|
|
980
|
+
main().catch(function (error) {
|
|
981
|
+
console.error('[MCP] Fatal error:', error);
|
|
982
|
+
process.exit(1);
|
|
983
|
+
});
|