@viewlint/mcp 0.0.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/README.md +19 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -0
- package/dist/mcp-cli.d.ts +3 -0
- package/dist/mcp-cli.d.ts.map +1 -0
- package/dist/mcp-cli.js +12 -0
- package/dist/mcp-server.d.ts +3 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +266 -0
- package/dist/types.d.ts +16 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +41 -0
- package/package.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# @viewlint/mcp
|
|
2
|
+
|
|
3
|
+
MCP server for ViewLint. You can use ViewLint with any AI Agent to improve its UI design skills.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx @viewlint/mcp@latest
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Or:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
viewlint --mcp
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## What it does
|
|
18
|
+
|
|
19
|
+
See the [docs](https://viewlint.vercel.app/docs/mcp-server)
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { mcpServer } from "./mcp-server.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-cli.d.ts","sourceRoot":"","sources":["../src/mcp-cli.ts"],"names":[],"mappings":""}
|
package/dist/mcp-cli.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { mcpServer } from "./mcp-server.js";
|
|
4
|
+
function disconnect() {
|
|
5
|
+
mcpServer.close();
|
|
6
|
+
process.exitCode = 0;
|
|
7
|
+
}
|
|
8
|
+
await mcpServer.connect(new StdioServerTransport());
|
|
9
|
+
// Note: do not use stdout because it's used for the MCP transport.
|
|
10
|
+
console.error(`ViewLint MCP server is running. cwd: ${process.cwd()}`);
|
|
11
|
+
process.on("SIGINT", disconnect);
|
|
12
|
+
process.on("SIGTERM", disconnect);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-server.d.ts","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AA0EnE,eAAO,MAAM,SAAS,WAGpB,CAAA"}
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { ViewLint } from "viewlint";
|
|
3
|
+
import { defaultView, findNearestViewlintConfigFile } from "viewlint/config";
|
|
4
|
+
import { getConfigInputSchema, lintUrlsInputSchema } from "./types.js";
|
|
5
|
+
// Helper to count severities
|
|
6
|
+
function countSeverities(messages) {
|
|
7
|
+
let errorCount = 0;
|
|
8
|
+
let warningCount = 0;
|
|
9
|
+
let infoCount = 0;
|
|
10
|
+
for (const message of messages) {
|
|
11
|
+
if (message.severity === "error")
|
|
12
|
+
errorCount += 1;
|
|
13
|
+
if (message.severity === "warn")
|
|
14
|
+
warningCount += 1;
|
|
15
|
+
if (message.severity === "info")
|
|
16
|
+
infoCount += 1;
|
|
17
|
+
}
|
|
18
|
+
return { errorCount, warningCount, infoCount };
|
|
19
|
+
}
|
|
20
|
+
// Filter results for quiet mode (errors only)
|
|
21
|
+
function filterResultsForQuietMode(results) {
|
|
22
|
+
return results.map((result) => {
|
|
23
|
+
const messages = result.messages.filter((m) => m.severity === "error");
|
|
24
|
+
const counts = countSeverities(messages);
|
|
25
|
+
return {
|
|
26
|
+
...result,
|
|
27
|
+
messages,
|
|
28
|
+
suppressedMessages: [],
|
|
29
|
+
errorCount: counts.errorCount,
|
|
30
|
+
warningCount: 0,
|
|
31
|
+
infoCount: 0,
|
|
32
|
+
recommendCount: 0,
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
// Format results for MCP tool response - always JSON
|
|
37
|
+
function formatToolResults(results) {
|
|
38
|
+
const type = "text";
|
|
39
|
+
const content = [];
|
|
40
|
+
// Summary statistics
|
|
41
|
+
const totalErrors = results.reduce((sum, r) => sum + r.errorCount, 0);
|
|
42
|
+
const totalWarnings = results.reduce((sum, r) => sum + r.warningCount, 0);
|
|
43
|
+
const totalInfo = results.reduce((sum, r) => sum + r.infoCount, 0);
|
|
44
|
+
content.push({
|
|
45
|
+
type,
|
|
46
|
+
text: `ViewLint Results Summary: ${totalErrors} error(s), ${totalWarnings} warning(s), ${totalInfo} info message(s) across ${results.length} URL(s).`,
|
|
47
|
+
});
|
|
48
|
+
// JSON format - structured for programmatic use
|
|
49
|
+
content.push({
|
|
50
|
+
type,
|
|
51
|
+
text: JSON.stringify(results, null, 2),
|
|
52
|
+
});
|
|
53
|
+
content.push({
|
|
54
|
+
type,
|
|
55
|
+
text: "\nReview the issues above. If you were asked to fix issues, proceed with fixing them. Otherwise, summarize the findings and ask the user if they want you to address any issues.",
|
|
56
|
+
});
|
|
57
|
+
return content;
|
|
58
|
+
}
|
|
59
|
+
// Initialize the MCP server
|
|
60
|
+
export const mcpServer = new McpServer({
|
|
61
|
+
name: "ViewLint",
|
|
62
|
+
version: "0.0.1",
|
|
63
|
+
});
|
|
64
|
+
// Main linting tool
|
|
65
|
+
mcpServer.registerTool("lint", {
|
|
66
|
+
title: "Lint URLs",
|
|
67
|
+
description: `Lint one or more web page URLs for accessibility and UI issues using ViewLint.
|
|
68
|
+
|
|
69
|
+
ViewLint requires a configuration file to be defined, in the form of \`viewlint.config.js|ts|mjs\`. This file defines rules, views, options, and scopes for linting. ViewLint will not be able to function correctly without a valid configuration file, and views, options, and scopes must be defined in the configuration file.
|
|
70
|
+
|
|
71
|
+
**IMPORTANT**: Before running this tool, use the 'get-config' tool to discover which config file is being used. If no config file exists, the 'get-config' tool will inform you that you can create one for the user.
|
|
72
|
+
|
|
73
|
+
# Basic Usage:
|
|
74
|
+
Just provide one or more URLs to lint. ViewLint will load each page and check for accessibility issues, UI problems, and best practice violations.
|
|
75
|
+
|
|
76
|
+
# Advanced Features (optional):
|
|
77
|
+
- view: Use a named view from config (defines page setup like authentication, navigation)
|
|
78
|
+
- options: Apply named option layers (viewport size, cookies, storage state)
|
|
79
|
+
- scopes: Limit linting to specific named page sections
|
|
80
|
+
- selectors: Limit linting to elements matching CSS selectors
|
|
81
|
+
- quiet: Show only errors, hide warnings`,
|
|
82
|
+
inputSchema: lintUrlsInputSchema,
|
|
83
|
+
}, async (input) => {
|
|
84
|
+
const { urls, configFile, view: viewName, options: optionNames, scopes: scopeNames, selectors, quiet = false, } = input;
|
|
85
|
+
try {
|
|
86
|
+
const viewlint = new ViewLint({
|
|
87
|
+
overrideConfigFile: configFile,
|
|
88
|
+
});
|
|
89
|
+
const resolved = await viewlint.getResolvedOptions();
|
|
90
|
+
// Resolve named options from config
|
|
91
|
+
const optionLayersFromRegistry = (optionNames ?? []).flatMap((name) => {
|
|
92
|
+
const entry = resolved.optionsRegistry.get(name);
|
|
93
|
+
if (!entry) {
|
|
94
|
+
const known = [...resolved.optionsRegistry.keys()].sort();
|
|
95
|
+
const knownMessage = known.length === 0
|
|
96
|
+
? "No named options are defined in config."
|
|
97
|
+
: `Known options: ${known.map((x) => `'${x}'`).join(", ")}.`;
|
|
98
|
+
throw new Error(`Unknown option '${name}'. ${knownMessage}`);
|
|
99
|
+
}
|
|
100
|
+
const layers = Array.isArray(entry) ? entry : [entry];
|
|
101
|
+
return layers.map((layer) => {
|
|
102
|
+
if (layer.meta?.name)
|
|
103
|
+
return layer;
|
|
104
|
+
return { ...layer, meta: { ...(layer.meta ?? {}), name } };
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
// Resolve named scopes from config
|
|
108
|
+
const scopesFromRegistry = (scopeNames ?? []).flatMap((name) => {
|
|
109
|
+
const entry = resolved.scopeRegistry.get(name);
|
|
110
|
+
if (!entry) {
|
|
111
|
+
const known = [...resolved.scopeRegistry.keys()].sort();
|
|
112
|
+
const knownMessage = known.length === 0
|
|
113
|
+
? "No named scopes are defined in config."
|
|
114
|
+
: `Known scopes: ${known.map((x) => `'${x}'`).join(", ")}.`;
|
|
115
|
+
throw new Error(`Unknown scope '${name}'. ${knownMessage}`);
|
|
116
|
+
}
|
|
117
|
+
const scopes = Array.isArray(entry) ? entry : [entry];
|
|
118
|
+
return scopes.map((scope) => {
|
|
119
|
+
if (scope.meta?.name)
|
|
120
|
+
return scope;
|
|
121
|
+
return { ...scope, meta: { ...(scope.meta ?? {}), name } };
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
// Create scopes from CSS selectors
|
|
125
|
+
const selectorScopes = (selectors ?? []).map((selector) => ({
|
|
126
|
+
meta: { name: selector },
|
|
127
|
+
getLocator: ({ page }) => page.locator(selector),
|
|
128
|
+
}));
|
|
129
|
+
const resolvedScopes = [...scopesFromRegistry, ...selectorScopes];
|
|
130
|
+
// Resolve view
|
|
131
|
+
const resolveView = () => {
|
|
132
|
+
if (viewName) {
|
|
133
|
+
const view = resolved.viewRegistry.get(viewName);
|
|
134
|
+
if (!view) {
|
|
135
|
+
const known = [...resolved.viewRegistry.keys()].sort();
|
|
136
|
+
const knownMessage = known.length === 0
|
|
137
|
+
? "No named views are defined in config."
|
|
138
|
+
: `Known views: ${known.map((x) => `'${x}'`).join(", ")}.`;
|
|
139
|
+
throw new Error(`Unknown view '${viewName}'. ${knownMessage}`);
|
|
140
|
+
}
|
|
141
|
+
if (view.meta?.name)
|
|
142
|
+
return view;
|
|
143
|
+
return { ...view, meta: { ...(view.meta ?? {}), name: viewName } };
|
|
144
|
+
}
|
|
145
|
+
return defaultView;
|
|
146
|
+
};
|
|
147
|
+
// Build targets for each URL
|
|
148
|
+
const targets = urls.map((url) => {
|
|
149
|
+
const urlLayer = [{ context: { baseURL: url } }];
|
|
150
|
+
return {
|
|
151
|
+
view: resolveView(),
|
|
152
|
+
options: urlLayer.length === 0 && optionLayersFromRegistry.length === 0
|
|
153
|
+
? undefined
|
|
154
|
+
: [...urlLayer, ...optionLayersFromRegistry],
|
|
155
|
+
scope: resolvedScopes.length === 0 ? undefined : resolvedScopes,
|
|
156
|
+
};
|
|
157
|
+
});
|
|
158
|
+
let results = await viewlint.lintTargets(targets);
|
|
159
|
+
// Apply quiet mode filter
|
|
160
|
+
if (quiet) {
|
|
161
|
+
results = filterResultsForQuietMode(results);
|
|
162
|
+
}
|
|
163
|
+
const totalErrors = results.reduce((sum, r) => sum + r.errorCount, 0);
|
|
164
|
+
const content = formatToolResults(results);
|
|
165
|
+
return {
|
|
166
|
+
content,
|
|
167
|
+
isError: totalErrors > 0,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
return {
|
|
172
|
+
content: [
|
|
173
|
+
{
|
|
174
|
+
type: "text",
|
|
175
|
+
text: `Error running ViewLint: ${error instanceof Error ? error.message : String(error)}`,
|
|
176
|
+
},
|
|
177
|
+
],
|
|
178
|
+
isError: true,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
// Tool to get config file path
|
|
183
|
+
mcpServer.registerTool("get-config", {
|
|
184
|
+
title: "Get ViewLint Config",
|
|
185
|
+
description: `Get the path to the ViewLint configuration file currently being used.
|
|
186
|
+
|
|
187
|
+
This tool discovers and returns the path to the viewlint.config.ts|js|mjs file that ViewLint will use for linting. It searches from the server's working directory upward.
|
|
188
|
+
|
|
189
|
+
If no config file is found, the tool will inform you and you can offer to create one for the user.`,
|
|
190
|
+
inputSchema: getConfigInputSchema,
|
|
191
|
+
}, async (input) => {
|
|
192
|
+
const { configFile } = input;
|
|
193
|
+
try {
|
|
194
|
+
// If a specific config file was requested, check it
|
|
195
|
+
if (configFile) {
|
|
196
|
+
return {
|
|
197
|
+
content: [
|
|
198
|
+
{
|
|
199
|
+
type: "text",
|
|
200
|
+
text: `Specified config file: ${configFile}`,
|
|
201
|
+
},
|
|
202
|
+
],
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
// Otherwise, discover the config file
|
|
206
|
+
const discoveredConfig = findNearestViewlintConfigFile();
|
|
207
|
+
if (discoveredConfig) {
|
|
208
|
+
return {
|
|
209
|
+
content: [
|
|
210
|
+
{
|
|
211
|
+
type: "text",
|
|
212
|
+
text: `ViewLint config file found: ${discoveredConfig}\n\nThis config file defines rules, views, options, and scopes for linting. You can now use the 'lint' tool to lint URLs using this configuration.`,
|
|
213
|
+
},
|
|
214
|
+
],
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
// No config file found
|
|
218
|
+
return {
|
|
219
|
+
content: [
|
|
220
|
+
{
|
|
221
|
+
type: "text",
|
|
222
|
+
text: `No ViewLint config file found in the current working directory or any parent directory.
|
|
223
|
+
|
|
224
|
+
ViewLint requires a configuration file in one of these formats:
|
|
225
|
+
- viewlint.config.ts
|
|
226
|
+
- viewlint.config.js
|
|
227
|
+
- viewlint.config.mjs
|
|
228
|
+
|
|
229
|
+
You can offer to create a basic viewlint.config.ts file for the user. A minimal config looks like:
|
|
230
|
+
|
|
231
|
+
\`\`\`typescript
|
|
232
|
+
import { defineConfig } from "viewlint/config";
|
|
233
|
+
|
|
234
|
+
export default defineConfig({
|
|
235
|
+
rules: {
|
|
236
|
+
// Add rules here
|
|
237
|
+
},
|
|
238
|
+
views: {
|
|
239
|
+
// Define views here (e.g., mobile, desktop, logged-in)
|
|
240
|
+
},
|
|
241
|
+
options: {
|
|
242
|
+
// Define reusable option layers
|
|
243
|
+
},
|
|
244
|
+
scopes: {
|
|
245
|
+
// Define scope selectors here
|
|
246
|
+
},
|
|
247
|
+
});
|
|
248
|
+
\`\`\`
|
|
249
|
+
|
|
250
|
+
Alternatively, you can ask the user to run \`npm init @viewlint/config\` for an interactive guided setup.`,
|
|
251
|
+
},
|
|
252
|
+
],
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
catch (error) {
|
|
256
|
+
return {
|
|
257
|
+
content: [
|
|
258
|
+
{
|
|
259
|
+
type: "text",
|
|
260
|
+
text: `Error discovering config: ${error instanceof Error ? error.message : String(error)}`,
|
|
261
|
+
},
|
|
262
|
+
],
|
|
263
|
+
isError: true,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
});
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const lintUrlsInputSchema: {
|
|
3
|
+
urls: z.ZodArray<z.ZodURL>;
|
|
4
|
+
configFile: z.ZodOptional<z.ZodString>;
|
|
5
|
+
view: z.ZodOptional<z.ZodString>;
|
|
6
|
+
options: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
7
|
+
scopes: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
8
|
+
selectors: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
9
|
+
quiet: z.ZodOptional<z.ZodBoolean>;
|
|
10
|
+
};
|
|
11
|
+
export type LintUrlsInput = z.infer<z.ZodObject<typeof lintUrlsInputSchema>>;
|
|
12
|
+
export declare const getConfigInputSchema: {
|
|
13
|
+
configFile: z.ZodOptional<z.ZodString>;
|
|
14
|
+
};
|
|
15
|
+
export type GetConfigInput = z.infer<z.ZodObject<typeof getConfigInputSchema>>;
|
|
16
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,eAAO,MAAM,mBAAmB;;;;;;;;CA0C/B,CAAA;AAED,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,mBAAmB,CAAC,CAAC,CAAA;AAG5E,eAAO,MAAM,oBAAoB;;CAQhC,CAAA;AAED,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,oBAAoB,CAAC,CAAC,CAAA"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
// Main lint-urls tool schema - simple by default, advanced options available
|
|
3
|
+
export const lintUrlsInputSchema = {
|
|
4
|
+
urls: z
|
|
5
|
+
.array(z.url())
|
|
6
|
+
.min(1)
|
|
7
|
+
.describe("One or more URLs to lint (e.g. https://example.com)"),
|
|
8
|
+
configFile: z
|
|
9
|
+
.string()
|
|
10
|
+
.min(1)
|
|
11
|
+
.optional()
|
|
12
|
+
.describe("Path to a specific viewlint config file. If omitted, uses the default config from the server's working directory. Use the 'get-config' tool to discover the config file being used."),
|
|
13
|
+
view: z
|
|
14
|
+
.string()
|
|
15
|
+
.optional()
|
|
16
|
+
.describe("Use a named view from the config. Views define how the page is loaded and set up before linting."),
|
|
17
|
+
options: z
|
|
18
|
+
.array(z.string())
|
|
19
|
+
.optional()
|
|
20
|
+
.describe("Apply named option layers from config (in order). Options can set viewport, authentication, or other context."),
|
|
21
|
+
scopes: z
|
|
22
|
+
.array(z.string())
|
|
23
|
+
.optional()
|
|
24
|
+
.describe("Apply named scopes from config (in order). Scopes limit linting to specific parts of the page."),
|
|
25
|
+
selectors: z
|
|
26
|
+
.array(z.string())
|
|
27
|
+
.optional()
|
|
28
|
+
.describe("Ad-hoc CSS selectors to use as additional scope roots. Limits linting to elements matching these selectors."),
|
|
29
|
+
quiet: z
|
|
30
|
+
.boolean()
|
|
31
|
+
.optional()
|
|
32
|
+
.describe("If true, only report errors (hide warnings and info messages). Default: false."),
|
|
33
|
+
};
|
|
34
|
+
// Get config tool schema
|
|
35
|
+
export const getConfigInputSchema = {
|
|
36
|
+
configFile: z
|
|
37
|
+
.string()
|
|
38
|
+
.min(1)
|
|
39
|
+
.optional()
|
|
40
|
+
.describe("Optional path to check a specific config file. If omitted, discovers the config from the server's working directory."),
|
|
41
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@viewlint/mcp",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "MCP server for ViewLint",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"viewlint-mcp": "dist/mcp-cli.js"
|
|
8
|
+
},
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./mcp-server": {
|
|
15
|
+
"types": "./dist/mcp-server.d.ts",
|
|
16
|
+
"default": "./dist/mcp-server.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist",
|
|
21
|
+
"README.md"
|
|
22
|
+
],
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@modelcontextprotocol/sdk": "^1.24.1",
|
|
28
|
+
"viewlint": "^0.0.1",
|
|
29
|
+
"zod": "^4.3.5"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@repo/typescript-config": "workspace:*",
|
|
33
|
+
"typescript": "5.9.2",
|
|
34
|
+
"vitest": "3.2.4",
|
|
35
|
+
"viewlint": "workspace:*"
|
|
36
|
+
},
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\" && tsc -p tsconfig.build.json && node -e \"require('node:fs').chmodSync('dist/mcp-cli.js', 0o755)\"",
|
|
39
|
+
"test": "vitest run --passWithNoTests",
|
|
40
|
+
"check-types": "tsc --noEmit",
|
|
41
|
+
"prepack": "npm run build"
|
|
42
|
+
}
|
|
43
|
+
}
|