@deplens/mcp 0.1.7 → 0.1.8
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/bin/deplens-mcp.js +0 -0
- package/package.json +6 -3
- package/src/core/changelog-parser.mjs +313 -0
- package/src/core/diff-analyzer.mjs +590 -0
- package/src/core/diff.mjs +145 -0
- package/src/core/inspect.mjs +950 -482
- package/src/core/parse-dts.mjs +198 -172
- package/src/core/parse-source.mjs +524 -0
- package/src/core/version-resolver.mjs +317 -0
- package/src/server.mjs +581 -37
package/bin/deplens-mcp.js
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deplens/mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./src/server.mjs",
|
|
6
6
|
"bin": {
|
|
@@ -17,8 +17,11 @@
|
|
|
17
17
|
"node": ">=18"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@deplens/core": "0.1.
|
|
21
|
-
"@modelcontextprotocol/sdk": "^1.25.1"
|
|
20
|
+
"@deplens/core": "0.1.6",
|
|
21
|
+
"@modelcontextprotocol/sdk": "^1.25.1",
|
|
22
|
+
"fast-glob": "^3.3.2",
|
|
23
|
+
"typescript": "^5.0.0",
|
|
24
|
+
"import-meta-resolve": "^4.0.0"
|
|
22
25
|
},
|
|
23
26
|
"publishConfig": {
|
|
24
27
|
"access": "public"
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* changelog-parser.mjs - Parse CHANGELOG.md files to extract version notes
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import fs from "fs";
|
|
6
|
+
import path from "path";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Common changelog file names
|
|
10
|
+
*/
|
|
11
|
+
const CHANGELOG_NAMES = [
|
|
12
|
+
"CHANGELOG.md",
|
|
13
|
+
"CHANGELOG",
|
|
14
|
+
"changelog.md",
|
|
15
|
+
"Changelog.md",
|
|
16
|
+
"HISTORY.md",
|
|
17
|
+
"HISTORY",
|
|
18
|
+
"history.md",
|
|
19
|
+
"CHANGES.md",
|
|
20
|
+
"CHANGES",
|
|
21
|
+
"changes.md",
|
|
22
|
+
"NEWS.md",
|
|
23
|
+
"RELEASES.md",
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Find changelog file in package directory
|
|
28
|
+
*/
|
|
29
|
+
export function findChangelog(packageDir) {
|
|
30
|
+
for (const name of CHANGELOG_NAMES) {
|
|
31
|
+
const fullPath = path.join(packageDir, name);
|
|
32
|
+
if (fs.existsSync(fullPath)) {
|
|
33
|
+
return fullPath;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Parse version header patterns
|
|
41
|
+
*/
|
|
42
|
+
const VERSION_PATTERNS = [
|
|
43
|
+
// ## [1.2.3] - 2024-01-01
|
|
44
|
+
/^##\s*\[?v?(\d+\.\d+\.\d+(?:-[\w.]+)?)\]?(?:\s*[-–—]\s*(.+))?$/i,
|
|
45
|
+
// ## 1.2.3
|
|
46
|
+
/^##\s*v?(\d+\.\d+\.\d+(?:-[\w.]+)?)(?:\s+(.+))?$/i,
|
|
47
|
+
// # Version 1.2.3
|
|
48
|
+
/^#\s*(?:Version\s+)?v?(\d+\.\d+\.\d+(?:-[\w.]+)?)(?:\s+(.+))?$/i,
|
|
49
|
+
// ### 1.2.3
|
|
50
|
+
/^###\s*v?(\d+\.\d+\.\d+(?:-[\w.]+)?)(?:\s+(.+))?$/i,
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Categorize changelog entry
|
|
55
|
+
*/
|
|
56
|
+
function categorizeEntry(line) {
|
|
57
|
+
const lowerLine = line.toLowerCase();
|
|
58
|
+
|
|
59
|
+
if (/breaking|removed|deprecated/i.test(lowerLine)) {
|
|
60
|
+
return "breaking";
|
|
61
|
+
}
|
|
62
|
+
if (/fix|bug|patch|resolved|corrected/i.test(lowerLine)) {
|
|
63
|
+
return "fixed";
|
|
64
|
+
}
|
|
65
|
+
if (/add|new|feature|implement/i.test(lowerLine)) {
|
|
66
|
+
return "added";
|
|
67
|
+
}
|
|
68
|
+
if (/change|update|improve|enhance|refactor/i.test(lowerLine)) {
|
|
69
|
+
return "changed";
|
|
70
|
+
}
|
|
71
|
+
if (/security|vulnerability|cve/i.test(lowerLine)) {
|
|
72
|
+
return "security";
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return "other";
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Parse a single changelog entry line
|
|
80
|
+
*/
|
|
81
|
+
function parseEntryLine(line) {
|
|
82
|
+
// Remove bullet points and clean up
|
|
83
|
+
const cleaned = line
|
|
84
|
+
.replace(/^[\s*\-•·]+/, "")
|
|
85
|
+
.replace(/\[#\d+\].*$/, "") // Remove issue links
|
|
86
|
+
.replace(/\(#\d+\)/, "")
|
|
87
|
+
.replace(/by @[\w-]+/i, "")
|
|
88
|
+
.trim();
|
|
89
|
+
|
|
90
|
+
if (!cleaned || cleaned.length < 3) return null;
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
text: cleaned,
|
|
94
|
+
category: categorizeEntry(cleaned),
|
|
95
|
+
raw: line,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Parse changelog content
|
|
101
|
+
*/
|
|
102
|
+
export function parseChangelog(content) {
|
|
103
|
+
const lines = content.split("\n");
|
|
104
|
+
const versions = {};
|
|
105
|
+
let currentVersion = null;
|
|
106
|
+
let currentSection = null;
|
|
107
|
+
|
|
108
|
+
for (const line of lines) {
|
|
109
|
+
// Check for version header
|
|
110
|
+
let versionMatch = null;
|
|
111
|
+
for (const pattern of VERSION_PATTERNS) {
|
|
112
|
+
const match = line.match(pattern);
|
|
113
|
+
if (match) {
|
|
114
|
+
versionMatch = match;
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (versionMatch) {
|
|
120
|
+
currentVersion = versionMatch[1];
|
|
121
|
+
const date = versionMatch[2] || null;
|
|
122
|
+
|
|
123
|
+
versions[currentVersion] = {
|
|
124
|
+
version: currentVersion,
|
|
125
|
+
date,
|
|
126
|
+
sections: {
|
|
127
|
+
breaking: [],
|
|
128
|
+
added: [],
|
|
129
|
+
changed: [],
|
|
130
|
+
fixed: [],
|
|
131
|
+
security: [],
|
|
132
|
+
other: [],
|
|
133
|
+
},
|
|
134
|
+
raw: [],
|
|
135
|
+
};
|
|
136
|
+
currentSection = null;
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (!currentVersion) continue;
|
|
141
|
+
|
|
142
|
+
// Check for section headers (### Added, ### Fixed, etc.)
|
|
143
|
+
const sectionMatch = line.match(
|
|
144
|
+
/^###\s*(Added|Changed|Deprecated|Removed|Fixed|Security|Breaking)/i,
|
|
145
|
+
);
|
|
146
|
+
if (sectionMatch) {
|
|
147
|
+
const section = sectionMatch[1].toLowerCase();
|
|
148
|
+
if (section === "removed" || section === "deprecated") {
|
|
149
|
+
currentSection = "breaking";
|
|
150
|
+
} else {
|
|
151
|
+
currentSection = section;
|
|
152
|
+
}
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Parse entry lines
|
|
157
|
+
if (line.match(/^[\s*\-•·]+/)) {
|
|
158
|
+
const entry = parseEntryLine(line);
|
|
159
|
+
if (entry) {
|
|
160
|
+
const section = currentSection || entry.category;
|
|
161
|
+
if (versions[currentVersion].sections[section]) {
|
|
162
|
+
versions[currentVersion].sections[section].push(entry);
|
|
163
|
+
} else {
|
|
164
|
+
versions[currentVersion].sections.other.push(entry);
|
|
165
|
+
}
|
|
166
|
+
versions[currentVersion].raw.push(line);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return versions;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Parse changelog file
|
|
176
|
+
*/
|
|
177
|
+
export function parseChangelogFile(filePath) {
|
|
178
|
+
if (!fs.existsSync(filePath)) {
|
|
179
|
+
return { error: "Changelog not found", versions: {} };
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
183
|
+
return {
|
|
184
|
+
file: filePath,
|
|
185
|
+
versions: parseChangelog(content),
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Get changelog entries between two versions
|
|
191
|
+
*/
|
|
192
|
+
export function getChangesBetweenVersions(changelog, fromVersion, toVersion) {
|
|
193
|
+
const versions = changelog.versions || {};
|
|
194
|
+
const versionList = Object.keys(versions);
|
|
195
|
+
|
|
196
|
+
// Sort versions (semver-like)
|
|
197
|
+
versionList.sort((a, b) => {
|
|
198
|
+
const aParts = a.split(".").map(Number);
|
|
199
|
+
const bParts = b.split(".").map(Number);
|
|
200
|
+
for (let i = 0; i < 3; i++) {
|
|
201
|
+
if ((aParts[i] || 0) !== (bParts[i] || 0)) {
|
|
202
|
+
return (aParts[i] || 0) - (bParts[i] || 0);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return 0;
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
// Find versions in range
|
|
209
|
+
const fromIndex = versionList.indexOf(fromVersion);
|
|
210
|
+
const toIndex = versionList.indexOf(toVersion);
|
|
211
|
+
|
|
212
|
+
if (fromIndex === -1 || toIndex === -1) {
|
|
213
|
+
// Try to find closest versions
|
|
214
|
+
return {
|
|
215
|
+
exact: false,
|
|
216
|
+
versions: [],
|
|
217
|
+
note: `Could not find exact versions. Available: ${versionList.slice(-5).join(", ")}`,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const inRange = versionList.slice(fromIndex + 1, toIndex + 1);
|
|
222
|
+
|
|
223
|
+
const combined = {
|
|
224
|
+
breaking: [],
|
|
225
|
+
added: [],
|
|
226
|
+
changed: [],
|
|
227
|
+
fixed: [],
|
|
228
|
+
security: [],
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
for (const v of inRange) {
|
|
232
|
+
const vData = versions[v];
|
|
233
|
+
if (!vData) continue;
|
|
234
|
+
|
|
235
|
+
for (const [section, entries] of Object.entries(vData.sections)) {
|
|
236
|
+
if (combined[section]) {
|
|
237
|
+
combined[section].push(
|
|
238
|
+
...entries.map((e) => ({
|
|
239
|
+
...e,
|
|
240
|
+
version: v,
|
|
241
|
+
})),
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return {
|
|
248
|
+
exact: true,
|
|
249
|
+
from: fromVersion,
|
|
250
|
+
to: toVersion,
|
|
251
|
+
versionsIncluded: inRange,
|
|
252
|
+
changes: combined,
|
|
253
|
+
summary: {
|
|
254
|
+
breaking: combined.breaking.length,
|
|
255
|
+
added: combined.added.length,
|
|
256
|
+
changed: combined.changed.length,
|
|
257
|
+
fixed: combined.fixed.length,
|
|
258
|
+
security: combined.security.length,
|
|
259
|
+
},
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Format changelog diff as text
|
|
265
|
+
*/
|
|
266
|
+
export function formatChangelogDiff(changelogDiff, options = {}) {
|
|
267
|
+
const { maxPerSection = 5 } = options;
|
|
268
|
+
const lines = [];
|
|
269
|
+
|
|
270
|
+
if (!changelogDiff.exact) {
|
|
271
|
+
lines.push(`⚠️ ${changelogDiff.note}`);
|
|
272
|
+
return lines.join("\n");
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
lines.push(`📜 Changelog: ${changelogDiff.from} → ${changelogDiff.to}`);
|
|
276
|
+
lines.push(
|
|
277
|
+
` Versions included: ${changelogDiff.versionsIncluded.join(", ")}`,
|
|
278
|
+
);
|
|
279
|
+
lines.push("");
|
|
280
|
+
|
|
281
|
+
const sections = [
|
|
282
|
+
{ key: "breaking", icon: "🔴", title: "Breaking Changes" },
|
|
283
|
+
{ key: "added", icon: "🟢", title: "Added" },
|
|
284
|
+
{ key: "changed", icon: "🟡", title: "Changed" },
|
|
285
|
+
{ key: "fixed", icon: "🔧", title: "Fixed" },
|
|
286
|
+
{ key: "security", icon: "🔒", title: "Security" },
|
|
287
|
+
];
|
|
288
|
+
|
|
289
|
+
for (const { key, icon, title } of sections) {
|
|
290
|
+
const entries = changelogDiff.changes[key] || [];
|
|
291
|
+
if (entries.length === 0) continue;
|
|
292
|
+
|
|
293
|
+
lines.push(`${icon} ${title} (${entries.length}):`);
|
|
294
|
+
const shown = entries.slice(0, maxPerSection);
|
|
295
|
+
for (const entry of shown) {
|
|
296
|
+
lines.push(` • ${entry.text} (${entry.version})`);
|
|
297
|
+
}
|
|
298
|
+
if (entries.length > maxPerSection) {
|
|
299
|
+
lines.push(` ... and ${entries.length - maxPerSection} more`);
|
|
300
|
+
}
|
|
301
|
+
lines.push("");
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
return lines.join("\n");
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
export default {
|
|
308
|
+
findChangelog,
|
|
309
|
+
parseChangelog,
|
|
310
|
+
parseChangelogFile,
|
|
311
|
+
getChangesBetweenVersions,
|
|
312
|
+
formatChangelogDiff,
|
|
313
|
+
};
|