@sylphx/pdf-reader-mcp 1.2.0 → 1.3.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 +508 -246
- package/dist/handlers/readPdf.js +6 -4
- package/dist/index.js +1 -1
- package/dist/pdf/extractor.js +158 -29
- package/dist/pdf/parser.js +6 -4
- package/dist/schemas/readPdf.js +5 -1
- package/dist/utils/pathUtils.js +7 -12
- package/package.json +37 -33
package/dist/handlers/readPdf.js
CHANGED
|
@@ -70,7 +70,7 @@ const processSingleSource = async (source, options) => {
|
|
|
70
70
|
let errorMessage = `Failed to process PDF from ${sourceDescription}.`;
|
|
71
71
|
if (error instanceof McpError) {
|
|
72
72
|
errorMessage = error.message;
|
|
73
|
-
}
|
|
73
|
+
} /* c8 ignore next */
|
|
74
74
|
else if (error instanceof Error) {
|
|
75
75
|
errorMessage += ` Reason: ${error.message}`;
|
|
76
76
|
}
|
|
@@ -93,9 +93,11 @@ export const handleReadPdfFunc = async (args) => {
|
|
|
93
93
|
}
|
|
94
94
|
catch (error) {
|
|
95
95
|
if (error instanceof z.ZodError) {
|
|
96
|
-
throw new McpError(ErrorCode.InvalidParams, `Invalid arguments: ${error.
|
|
96
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid arguments: ${error.issues.map((e) => `${e.path.join('.')} (${e.message})`).join(', ')}`);
|
|
97
97
|
}
|
|
98
|
+
/* c8 ignore next */
|
|
98
99
|
const message = error instanceof Error ? error.message : String(error);
|
|
100
|
+
/* c8 ignore next */
|
|
99
101
|
throw new McpError(ErrorCode.InvalidParams, `Argument validation failed: ${message}`);
|
|
100
102
|
}
|
|
101
103
|
const { sources, include_full_text, include_metadata, include_page_count, include_images } = parsedArgs;
|
|
@@ -147,11 +149,11 @@ export const handleReadPdfFunc = async (args) => {
|
|
|
147
149
|
});
|
|
148
150
|
}
|
|
149
151
|
else if (item.type === 'image' && item.imageData) {
|
|
150
|
-
// Add image content part
|
|
152
|
+
// Add image content part (all images are now encoded as PNG)
|
|
151
153
|
content.push({
|
|
152
154
|
type: 'image',
|
|
153
155
|
data: item.imageData.data,
|
|
154
|
-
mimeType:
|
|
156
|
+
mimeType: 'image/png',
|
|
155
157
|
});
|
|
156
158
|
}
|
|
157
159
|
}
|
package/dist/index.js
CHANGED
|
@@ -11,7 +11,7 @@ import { allToolDefinitions } from './handlers/index.js';
|
|
|
11
11
|
// --- Server Setup ---
|
|
12
12
|
const server = new Server({
|
|
13
13
|
name: 'pdf-reader-mcp',
|
|
14
|
-
version: '1.
|
|
14
|
+
version: '1.3.0',
|
|
15
15
|
description: 'MCP Server for reading PDF files and extracting text, metadata, images, and page information.',
|
|
16
16
|
}, {
|
|
17
17
|
capabilities: { tools: {} },
|
package/dist/pdf/extractor.js
CHANGED
|
@@ -1,5 +1,42 @@
|
|
|
1
1
|
// PDF text and metadata extraction utilities
|
|
2
2
|
import { OPS } from 'pdfjs-dist/legacy/build/pdf.mjs';
|
|
3
|
+
import { PNG } from 'pngjs';
|
|
4
|
+
/**
|
|
5
|
+
* Encode raw pixel data to PNG format
|
|
6
|
+
*/
|
|
7
|
+
const encodePixelsToPNG = (pixelData, width, height, channels) => {
|
|
8
|
+
const png = new PNG({ width, height });
|
|
9
|
+
// Convert pixel data to RGBA format expected by pngjs
|
|
10
|
+
if (channels === 4) {
|
|
11
|
+
// Already RGBA
|
|
12
|
+
png.data = Buffer.from(pixelData);
|
|
13
|
+
}
|
|
14
|
+
else if (channels === 3) {
|
|
15
|
+
// RGB -> RGBA (add alpha channel)
|
|
16
|
+
for (let i = 0; i < width * height; i++) {
|
|
17
|
+
const srcIdx = i * 3;
|
|
18
|
+
const dstIdx = i * 4;
|
|
19
|
+
png.data[dstIdx] = pixelData[srcIdx] ?? 0; // R
|
|
20
|
+
png.data[dstIdx + 1] = pixelData[srcIdx + 1] ?? 0; // G
|
|
21
|
+
png.data[dstIdx + 2] = pixelData[srcIdx + 2] ?? 0; // B
|
|
22
|
+
png.data[dstIdx + 3] = 255; // A (fully opaque)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
else if (channels === 1) {
|
|
26
|
+
// Grayscale -> RGBA
|
|
27
|
+
for (let i = 0; i < width * height; i++) {
|
|
28
|
+
const gray = pixelData[i] ?? 0;
|
|
29
|
+
const dstIdx = i * 4;
|
|
30
|
+
png.data[dstIdx] = gray; // R
|
|
31
|
+
png.data[dstIdx + 1] = gray; // G
|
|
32
|
+
png.data[dstIdx + 2] = gray; // B
|
|
33
|
+
png.data[dstIdx + 3] = 255; // A
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// Encode to PNG and convert to base64
|
|
37
|
+
const pngBuffer = PNG.sync.write(png);
|
|
38
|
+
return pngBuffer.toString('base64');
|
|
39
|
+
};
|
|
3
40
|
/**
|
|
4
41
|
* Extract metadata and page count from a PDF document
|
|
5
42
|
*/
|
|
@@ -68,6 +105,7 @@ export const extractPageTexts = async (pdfDocument, pagesToProcess, sourceDescri
|
|
|
68
105
|
*/
|
|
69
106
|
const extractImagesFromPage = async (page, pageNum) => {
|
|
70
107
|
const images = [];
|
|
108
|
+
/* c8 ignore next */
|
|
71
109
|
try {
|
|
72
110
|
const operatorList = await page.getOperatorList();
|
|
73
111
|
// Find all image painting operations
|
|
@@ -78,7 +116,7 @@ const extractImagesFromPage = async (page, pageNum) => {
|
|
|
78
116
|
imageIndices.push(i);
|
|
79
117
|
}
|
|
80
118
|
}
|
|
81
|
-
// Extract each image
|
|
119
|
+
// Extract each image - try sync first, then async if needed
|
|
82
120
|
const imagePromises = imageIndices.map((imgIndex, arrayIndex) => new Promise((resolve) => {
|
|
83
121
|
const argsArray = operatorList.argsArray[imgIndex];
|
|
84
122
|
if (!argsArray || argsArray.length === 0) {
|
|
@@ -86,30 +124,75 @@ const extractImagesFromPage = async (page, pageNum) => {
|
|
|
86
124
|
return;
|
|
87
125
|
}
|
|
88
126
|
const imageName = argsArray[0];
|
|
89
|
-
//
|
|
90
|
-
|
|
127
|
+
// Helper to process image data
|
|
128
|
+
const processImageData = (imageData) => {
|
|
91
129
|
if (!imageData || typeof imageData !== 'object') {
|
|
92
|
-
|
|
93
|
-
return;
|
|
130
|
+
return null;
|
|
94
131
|
}
|
|
95
132
|
const img = imageData;
|
|
96
133
|
if (!img.data || !img.width || !img.height) {
|
|
97
|
-
|
|
98
|
-
return;
|
|
134
|
+
return null;
|
|
99
135
|
}
|
|
100
|
-
// Determine
|
|
101
|
-
// kind === 1 = grayscale, 2 = RGB, 3 = RGBA
|
|
136
|
+
// Determine number of channels based on kind
|
|
137
|
+
// kind === 1 = grayscale (1 channel), 2 = RGB (3 channels), 3 = RGBA (4 channels)
|
|
138
|
+
const channels = img.kind === 1 ? 1 : img.kind === 3 ? 4 : 3;
|
|
102
139
|
const format = img.kind === 1 ? 'grayscale' : img.kind === 3 ? 'rgba' : 'rgb';
|
|
103
|
-
//
|
|
104
|
-
const
|
|
105
|
-
|
|
140
|
+
// Encode raw pixel data to PNG format
|
|
141
|
+
const pngBase64 = encodePixelsToPNG(img.data, img.width, img.height, channels);
|
|
142
|
+
return {
|
|
106
143
|
page: pageNum,
|
|
107
144
|
index: arrayIndex,
|
|
108
145
|
width: img.width,
|
|
109
146
|
height: img.height,
|
|
110
147
|
format,
|
|
111
|
-
data:
|
|
112
|
-
}
|
|
148
|
+
data: pngBase64,
|
|
149
|
+
};
|
|
150
|
+
};
|
|
151
|
+
// Try to get from commonObjs first if it starts with 'g_'
|
|
152
|
+
if (imageName.startsWith('g_')) {
|
|
153
|
+
try {
|
|
154
|
+
const imageData = page.commonObjs.get(imageName);
|
|
155
|
+
if (imageData) {
|
|
156
|
+
const result = processImageData(imageData);
|
|
157
|
+
resolve(result);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
catch (error) {
|
|
162
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
163
|
+
console.warn(`[PDF Reader MCP] Error getting image from commonObjs ${imageName}: ${message}`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// Try synchronous get first - if image is already loaded
|
|
167
|
+
try {
|
|
168
|
+
const imageData = page.objs.get(imageName);
|
|
169
|
+
if (imageData !== undefined) {
|
|
170
|
+
const result = processImageData(imageData);
|
|
171
|
+
resolve(result);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
catch (error) {
|
|
176
|
+
// Synchronous get failed or not supported, fall through to async
|
|
177
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
178
|
+
console.warn(`[PDF Reader MCP] Sync image get failed for ${imageName}, trying async: ${message}`);
|
|
179
|
+
}
|
|
180
|
+
// Fallback to async callback-based get with timeout
|
|
181
|
+
let resolved = false;
|
|
182
|
+
const timeout = setTimeout(() => {
|
|
183
|
+
if (!resolved) {
|
|
184
|
+
resolved = true;
|
|
185
|
+
console.warn(`[PDF Reader MCP] Image extraction timeout for ${imageName} on page ${String(pageNum)}`);
|
|
186
|
+
resolve(null);
|
|
187
|
+
}
|
|
188
|
+
}, 10000); // 10 second timeout as a safety net
|
|
189
|
+
page.objs.get(imageName, (imageData) => {
|
|
190
|
+
if (!resolved) {
|
|
191
|
+
resolved = true;
|
|
192
|
+
clearTimeout(timeout);
|
|
193
|
+
const result = processImageData(imageData);
|
|
194
|
+
resolve(result);
|
|
195
|
+
}
|
|
113
196
|
});
|
|
114
197
|
}));
|
|
115
198
|
const resolvedImages = await Promise.all(imagePromises);
|
|
@@ -196,7 +279,7 @@ export const extractPageContent = async (pdfDocument, pageNum, includeImages, so
|
|
|
196
279
|
imageIndices.push(i);
|
|
197
280
|
}
|
|
198
281
|
}
|
|
199
|
-
// Extract each image with its Y-coordinate
|
|
282
|
+
// Extract each image with its Y-coordinate - try sync first, then async if needed
|
|
200
283
|
const imagePromises = imageIndices.map((imgIndex, arrayIndex) => new Promise((resolve) => {
|
|
201
284
|
const argsArray = operatorList.argsArray[imgIndex];
|
|
202
285
|
if (!argsArray || argsArray.length === 0) {
|
|
@@ -205,32 +288,29 @@ export const extractPageContent = async (pdfDocument, pageNum, includeImages, so
|
|
|
205
288
|
}
|
|
206
289
|
const imageName = argsArray[0];
|
|
207
290
|
// Get transform matrix from the args (if available)
|
|
208
|
-
// The transform is typically in argsArray[1] for some ops
|
|
209
291
|
let yPosition = 0;
|
|
210
292
|
if (argsArray.length > 1 && Array.isArray(argsArray[1])) {
|
|
211
293
|
const transform = argsArray[1];
|
|
212
|
-
// transform[5] is the Y coordinate
|
|
213
294
|
const yCoord = transform[5];
|
|
214
295
|
if (yCoord !== undefined) {
|
|
215
296
|
yPosition = Math.round(yCoord);
|
|
216
297
|
}
|
|
217
298
|
}
|
|
218
|
-
//
|
|
219
|
-
|
|
299
|
+
// Helper to process image data
|
|
300
|
+
const processImageData = (imageData) => {
|
|
220
301
|
if (!imageData || typeof imageData !== 'object') {
|
|
221
|
-
|
|
222
|
-
return;
|
|
302
|
+
return null;
|
|
223
303
|
}
|
|
224
304
|
const img = imageData;
|
|
225
305
|
if (!img.data || !img.width || !img.height) {
|
|
226
|
-
|
|
227
|
-
return;
|
|
306
|
+
return null;
|
|
228
307
|
}
|
|
229
|
-
// Determine
|
|
308
|
+
// Determine number of channels based on kind
|
|
309
|
+
const channels = img.kind === 1 ? 1 : img.kind === 3 ? 4 : 3;
|
|
230
310
|
const format = img.kind === 1 ? 'grayscale' : img.kind === 3 ? 'rgba' : 'rgb';
|
|
231
|
-
//
|
|
232
|
-
const
|
|
233
|
-
|
|
311
|
+
// Encode raw pixel data to PNG format
|
|
312
|
+
const pngBase64 = encodePixelsToPNG(img.data, img.width, img.height, channels);
|
|
313
|
+
return {
|
|
234
314
|
type: 'image',
|
|
235
315
|
yPosition,
|
|
236
316
|
imageData: {
|
|
@@ -239,9 +319,58 @@ export const extractPageContent = async (pdfDocument, pageNum, includeImages, so
|
|
|
239
319
|
width: img.width,
|
|
240
320
|
height: img.height,
|
|
241
321
|
format,
|
|
242
|
-
data:
|
|
322
|
+
data: pngBase64,
|
|
243
323
|
},
|
|
244
|
-
}
|
|
324
|
+
};
|
|
325
|
+
};
|
|
326
|
+
// Try to get from commonObjs first if it starts with 'g_'
|
|
327
|
+
if (imageName.startsWith('g_')) {
|
|
328
|
+
try {
|
|
329
|
+
const imageData = page.commonObjs.get(imageName);
|
|
330
|
+
if (imageData) {
|
|
331
|
+
const result = processImageData(imageData);
|
|
332
|
+
resolve(result);
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
/* c8 ignore next */
|
|
336
|
+
}
|
|
337
|
+
catch (error) {
|
|
338
|
+
/* c8 ignore next */ const message = error instanceof Error ? error.message : String(error);
|
|
339
|
+
/* c8 ignore next */ console.warn(
|
|
340
|
+
/* c8 ignore next */ `[PDF Reader MCP] Error getting image from commonObjs ${imageName}: ${message}`
|
|
341
|
+
/* c8 ignore next */
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
// Try synchronous get first - if image is already loaded
|
|
346
|
+
try {
|
|
347
|
+
const imageData = page.objs.get(imageName);
|
|
348
|
+
if (imageData !== undefined) {
|
|
349
|
+
const result = processImageData(imageData);
|
|
350
|
+
resolve(result);
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
catch (error) {
|
|
355
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
356
|
+
console.warn(`[PDF Reader MCP] Sync image get failed for ${imageName}, trying async: ${message}`);
|
|
357
|
+
}
|
|
358
|
+
// Fallback to async callback-based get with timeout
|
|
359
|
+
let resolved = false;
|
|
360
|
+
const timeout = setTimeout(() => {
|
|
361
|
+
if (!resolved) {
|
|
362
|
+
resolved = true;
|
|
363
|
+
console.warn(`[PDF Reader MCP] Image extraction timeout for ${imageName} on page ${String(pageNum)}`);
|
|
364
|
+
resolve(null);
|
|
365
|
+
}
|
|
366
|
+
}, 10000); // 10 second timeout as a safety net
|
|
367
|
+
page.objs.get(imageName, (imageData) => {
|
|
368
|
+
if (!resolved) {
|
|
369
|
+
resolved = true;
|
|
370
|
+
clearTimeout(timeout);
|
|
371
|
+
const result = processImageData(imageData);
|
|
372
|
+
resolve(result);
|
|
373
|
+
}
|
|
245
374
|
});
|
|
246
375
|
}));
|
|
247
376
|
const resolvedImages = await Promise.all(imagePromises);
|
package/dist/pdf/parser.js
CHANGED
|
@@ -7,10 +7,9 @@ const MAX_RANGE_SIZE = 10000; // Prevent infinite loops for open ranges
|
|
|
7
7
|
const parseRangePart = (part, pages) => {
|
|
8
8
|
const trimmedPart = part.trim();
|
|
9
9
|
if (trimmedPart.includes('-')) {
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
10
|
+
const splitResult = trimmedPart.split('-');
|
|
11
|
+
const startStr = splitResult[0] || '';
|
|
12
|
+
const endStr = splitResult[1];
|
|
14
13
|
const start = parseInt(startStr, 10);
|
|
15
14
|
const end = endStr === '' || endStr === undefined ? Infinity : parseInt(endStr, 10);
|
|
16
15
|
if (Number.isNaN(start) || Number.isNaN(end) || start <= 0 || start > end) {
|
|
@@ -43,6 +42,9 @@ export const parsePageRanges = (ranges) => {
|
|
|
43
42
|
for (const part of parts) {
|
|
44
43
|
parseRangePart(part, pages);
|
|
45
44
|
}
|
|
45
|
+
// This should never happen as parseRangePart would have thrown an error
|
|
46
|
+
// if no valid pages were found, but we keep this as a safety check
|
|
47
|
+
/* c8 ignore next */
|
|
46
48
|
if (pages.size === 0) {
|
|
47
49
|
throw new Error('Page range string resulted in zero valid pages.');
|
|
48
50
|
}
|
package/dist/schemas/readPdf.js
CHANGED
|
@@ -14,7 +14,11 @@ export const pageSpecifierSchema = z.union([
|
|
|
14
14
|
// Schema for a single PDF source (path or URL)
|
|
15
15
|
export const pdfSourceSchema = z
|
|
16
16
|
.object({
|
|
17
|
-
path: z
|
|
17
|
+
path: z
|
|
18
|
+
.string()
|
|
19
|
+
.min(1)
|
|
20
|
+
.optional()
|
|
21
|
+
.describe('Path to the local PDF file (absolute or relative to cwd).'),
|
|
18
22
|
url: z.string().url().optional().describe('URL of the PDF file.'),
|
|
19
23
|
pages: pageSpecifierSchema
|
|
20
24
|
.optional()
|
package/dist/utils/pathUtils.js
CHANGED
|
@@ -6,10 +6,9 @@ import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
|
|
|
6
6
|
export const PROJECT_ROOT = process.cwd();
|
|
7
7
|
console.info(`[Filesystem MCP - pathUtils] Project Root determined from CWD: ${PROJECT_ROOT}`); // Use info instead of log
|
|
8
8
|
/**
|
|
9
|
-
* Resolves a user-provided
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* @param userPath The relative path provided by the user.
|
|
9
|
+
* Resolves a user-provided path, accepting both absolute and relative paths.
|
|
10
|
+
* Relative paths are resolved against the current working directory (PROJECT_ROOT).
|
|
11
|
+
* @param userPath The path provided by the user (absolute or relative).
|
|
13
12
|
* @returns The resolved absolute path.
|
|
14
13
|
*/
|
|
15
14
|
export const resolvePath = (userPath) => {
|
|
@@ -17,14 +16,10 @@ export const resolvePath = (userPath) => {
|
|
|
17
16
|
throw new McpError(ErrorCode.InvalidParams, 'Path must be a string.');
|
|
18
17
|
}
|
|
19
18
|
const normalizedUserPath = path.normalize(userPath);
|
|
19
|
+
// If absolute path, return it normalized
|
|
20
20
|
if (path.isAbsolute(normalizedUserPath)) {
|
|
21
|
-
|
|
21
|
+
return normalizedUserPath;
|
|
22
22
|
}
|
|
23
|
-
//
|
|
24
|
-
|
|
25
|
-
// Security check: Ensure the resolved path is still within the project root
|
|
26
|
-
if (!resolved.startsWith(PROJECT_ROOT)) {
|
|
27
|
-
throw new McpError(ErrorCode.InvalidRequest, 'Path traversal detected. Access denied.');
|
|
28
|
-
}
|
|
29
|
-
return resolved;
|
|
23
|
+
// If relative path, resolve against the PROJECT_ROOT (cwd)
|
|
24
|
+
return path.resolve(PROJECT_ROOT, normalizedUserPath);
|
|
30
25
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sylphx/pdf-reader-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "An MCP server providing tools to read PDF files.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -39,20 +39,48 @@
|
|
|
39
39
|
"agent",
|
|
40
40
|
"tool"
|
|
41
41
|
],
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "tsc",
|
|
44
|
+
"watch": "tsc --watch",
|
|
45
|
+
"inspector": "npx @modelcontextprotocol/inspector dist/index.js",
|
|
46
|
+
"test": "vitest run",
|
|
47
|
+
"test:watch": "vitest watch",
|
|
48
|
+
"test:cov": "vitest run --coverage --reporter=junit --outputFile=test-report.junit.xml",
|
|
49
|
+
"lint": "biome lint .",
|
|
50
|
+
"lint:fix": "biome lint --write .",
|
|
51
|
+
"format": "biome format --write .",
|
|
52
|
+
"check-format": "biome format .",
|
|
53
|
+
"check": "biome check .",
|
|
54
|
+
"check:fix": "biome check --write .",
|
|
55
|
+
"validate": "npm run check && npm run test",
|
|
56
|
+
"docs:dev": "vitepress dev docs",
|
|
57
|
+
"docs:build": "vitepress build docs",
|
|
58
|
+
"docs:preview": "vitepress preview docs",
|
|
59
|
+
"start": "node dist/index.js",
|
|
60
|
+
"typecheck": "tsc --noEmit",
|
|
61
|
+
"benchmark": "vitest bench",
|
|
62
|
+
"clean": "rm -rf dist coverage",
|
|
63
|
+
"docs:api": "typedoc --entryPoints src/index.ts --tsconfig tsconfig.json --plugin typedoc-plugin-markdown --out docs/api --readme none",
|
|
64
|
+
"prepublishOnly": "pnpm run clean && pnpm run build",
|
|
65
|
+
"release": "standard-version",
|
|
66
|
+
"prepare": "husky"
|
|
67
|
+
},
|
|
42
68
|
"dependencies": {
|
|
43
|
-
"@modelcontextprotocol/sdk": "1.
|
|
69
|
+
"@modelcontextprotocol/sdk": "^1.21.0",
|
|
44
70
|
"glob": "^11.0.1",
|
|
45
71
|
"pdfjs-dist": "^5.4.296",
|
|
46
|
-
"
|
|
47
|
-
"zod
|
|
72
|
+
"pngjs": "^7.0.0",
|
|
73
|
+
"zod": "^3.25.76",
|
|
74
|
+
"zod-to-json-schema": "^3.24.6"
|
|
48
75
|
},
|
|
49
76
|
"devDependencies": {
|
|
50
77
|
"@biomejs/biome": "^2.3.2",
|
|
51
|
-
"@commitlint/cli": "^
|
|
52
|
-
"@commitlint/config-conventional": "^
|
|
78
|
+
"@commitlint/cli": "^20.1.0",
|
|
79
|
+
"@commitlint/config-conventional": "^20.0.0",
|
|
53
80
|
"@types/glob": "^8.1.0",
|
|
54
81
|
"@types/node": "^24.0.7",
|
|
55
|
-
"@
|
|
82
|
+
"@types/pngjs": "^6.0.5",
|
|
83
|
+
"@vitest/coverage-v8": "^4.0.7",
|
|
56
84
|
"husky": "^9.1.7",
|
|
57
85
|
"lint-staged": "^16.2.6",
|
|
58
86
|
"standard-version": "^9.5.0",
|
|
@@ -60,7 +88,7 @@
|
|
|
60
88
|
"typedoc-plugin-markdown": "^4.9.0",
|
|
61
89
|
"typescript": "^5.8.3",
|
|
62
90
|
"vitepress": "^1.6.3",
|
|
63
|
-
"vitest": "^
|
|
91
|
+
"vitest": "^4.0.7",
|
|
64
92
|
"vue": "^3.5.13"
|
|
65
93
|
},
|
|
66
94
|
"commitlint": {
|
|
@@ -72,29 +100,5 @@
|
|
|
72
100
|
"*.{ts,tsx,js,cjs,json}": [
|
|
73
101
|
"biome check --write --no-errors-on-unmatched --files-ignore-unknown=true"
|
|
74
102
|
]
|
|
75
|
-
},
|
|
76
|
-
"scripts": {
|
|
77
|
-
"build": "tsc",
|
|
78
|
-
"watch": "tsc --watch",
|
|
79
|
-
"inspector": "npx @modelcontextprotocol/inspector dist/index.js",
|
|
80
|
-
"test": "vitest run",
|
|
81
|
-
"test:watch": "vitest watch",
|
|
82
|
-
"test:cov": "vitest run --coverage --reporter=junit --outputFile=test-report.junit.xml",
|
|
83
|
-
"lint": "biome lint .",
|
|
84
|
-
"lint:fix": "biome lint --write .",
|
|
85
|
-
"format": "biome format --write .",
|
|
86
|
-
"check-format": "biome format .",
|
|
87
|
-
"check": "biome check .",
|
|
88
|
-
"check:fix": "biome check --write .",
|
|
89
|
-
"validate": "npm run check && npm run test",
|
|
90
|
-
"docs:dev": "vitepress dev docs",
|
|
91
|
-
"docs:build": "vitepress build docs",
|
|
92
|
-
"docs:preview": "vitepress preview docs",
|
|
93
|
-
"start": "node dist/index.js",
|
|
94
|
-
"typecheck": "tsc --noEmit",
|
|
95
|
-
"benchmark": "vitest bench",
|
|
96
|
-
"clean": "rm -rf dist coverage",
|
|
97
|
-
"docs:api": "typedoc --entryPoints src/index.ts --tsconfig tsconfig.json --plugin typedoc-plugin-markdown --out docs/api --readme none",
|
|
98
|
-
"release": "standard-version"
|
|
99
103
|
}
|
|
100
|
-
}
|
|
104
|
+
}
|