mirror of
https://github.com/microsoft/vscode-extension-samples.git
synced 2026-04-27 16:55:44 +08:00
add extension sample for mcp server publishing (#1156)
This commit is contained in:
6
mcp-extension-sample/.gitignore
vendored
Normal file
6
mcp-extension-sample/.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
out
|
||||
node_modules
|
||||
.vscode-test/
|
||||
*.vsix
|
||||
|
||||
*.d.ts
|
||||
21
mcp-extension-sample/.vscode/launch.json
vendored
Normal file
21
mcp-extension-sample/.vscode/launch.json
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
// A launch configuration that compiles the extension and then opens it inside a new window
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [{
|
||||
"name": "Run Extension",
|
||||
"type": "extensionHost",
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "${execPath}",
|
||||
"args": [
|
||||
"--extensionDevelopmentPath=${workspaceFolder}"
|
||||
],
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/out/**/*.js"
|
||||
],
|
||||
"preLaunchTask": "npm: watch"
|
||||
}
|
||||
]
|
||||
}
|
||||
20
mcp-extension-sample/.vscode/tasks.json
vendored
Normal file
20
mcp-extension-sample/.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "watch",
|
||||
"problemMatcher": "$tsc-watch",
|
||||
"isBackground": true,
|
||||
"presentation": {
|
||||
"reveal": "never"
|
||||
},
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
13
mcp-extension-sample/README.md
Normal file
13
mcp-extension-sample/README.md
Normal file
@ -0,0 +1,13 @@
|
||||
# MCP Extension sample
|
||||
|
||||
This sample demonstrates usage of the MCP connection API. This API is currently still proposed.
|
||||
|
||||
## Running the Sample
|
||||
|
||||
- Run `npm install` in terminal to install dependencies
|
||||
- A `postinstall` script would download latest version of `vscode.proposed.<proposalName>.d.ts`
|
||||
- Run the `Run Extension` target in the Debug View. This will:
|
||||
- Start a task `npm: watch` to compile the code
|
||||
- Run the extension in a new VS Code window
|
||||
- In the new window, run the command `Add Gist Source` command with a gist containing MCP servers ([example](https://gist.github.com/connor4312/3939ae7f6e55b2e391b5d585df27465c))
|
||||
- You can now run these MCP servers in chat.
|
||||
245
mcp-extension-sample/package-lock.json
generated
Normal file
245
mcp-extension-sample/package-lock.json
generated
Normal file
@ -0,0 +1,245 @@
|
||||
{
|
||||
"name": "mcp-extension-sample",
|
||||
"version": "0.0.1",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "mcp-extension-sample",
|
||||
"version": "0.0.1",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/node": "^20",
|
||||
"@vscode/dts": "^0.4.1",
|
||||
"typescript": "^5.8.2"
|
||||
},
|
||||
"engines": {
|
||||
"vscode": "^1.99.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.16.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.10.tgz",
|
||||
"integrity": "sha512-vQUKgWTjEIRFCvK6CyriPH3MZYiYlNy0fKiEYHWbcoWLEgs4opurGGKlebrTLqdSMIbXImH6XExNiIyNUv3WpA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~6.19.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@vscode/dts": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@vscode/dts/-/dts-0.4.1.tgz",
|
||||
"integrity": "sha512-o8cI5Vqt6S6Y5mCI7yCkSQdiLQaLG5DMUpciJV3zReZwE+dA5KERxSVX8H3cPEhyKw21XwKGmIrg6YmN6M5uZA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"https-proxy-agent": "^7.0.0",
|
||||
"minimist": "^1.2.8",
|
||||
"prompts": "^2.4.2"
|
||||
},
|
||||
"bin": {
|
||||
"dts": "index.js"
|
||||
}
|
||||
},
|
||||
"node_modules/agent-base": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz",
|
||||
"integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ms": "2.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/https-proxy-agent": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.0.tgz",
|
||||
"integrity": "sha512-0euwPCRyAPSgGdzD1IVN9nJYHtBhJwb6XPfbpQcYbPCwrBidX6GzxmchnaF4sfF/jPb74Ojx5g4yTg3sixlyPw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"agent-base": "^7.0.2",
|
||||
"debug": "4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/kleur": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
|
||||
"integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/minimist": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
|
||||
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
|
||||
"dev": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/prompts": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
|
||||
"integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"kleur": "^3.0.3",
|
||||
"sisteransi": "^1.0.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/sisteransi": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
|
||||
"integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.8.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz",
|
||||
"integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "6.19.8",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
|
||||
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
|
||||
"dev": true
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": {
|
||||
"version": "20.16.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.10.tgz",
|
||||
"integrity": "sha512-vQUKgWTjEIRFCvK6CyriPH3MZYiYlNy0fKiEYHWbcoWLEgs4opurGGKlebrTLqdSMIbXImH6XExNiIyNUv3WpA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"undici-types": "~6.19.2"
|
||||
}
|
||||
},
|
||||
"@vscode/dts": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@vscode/dts/-/dts-0.4.1.tgz",
|
||||
"integrity": "sha512-o8cI5Vqt6S6Y5mCI7yCkSQdiLQaLG5DMUpciJV3zReZwE+dA5KERxSVX8H3cPEhyKw21XwKGmIrg6YmN6M5uZA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"https-proxy-agent": "^7.0.0",
|
||||
"minimist": "^1.2.8",
|
||||
"prompts": "^2.4.2"
|
||||
}
|
||||
},
|
||||
"agent-base": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz",
|
||||
"integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"debug": "^4.3.4"
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"https-proxy-agent": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.0.tgz",
|
||||
"integrity": "sha512-0euwPCRyAPSgGdzD1IVN9nJYHtBhJwb6XPfbpQcYbPCwrBidX6GzxmchnaF4sfF/jPb74Ojx5g4yTg3sixlyPw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"agent-base": "^7.0.2",
|
||||
"debug": "4"
|
||||
}
|
||||
},
|
||||
"kleur": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
|
||||
"integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==",
|
||||
"dev": true
|
||||
},
|
||||
"minimist": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
|
||||
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
|
||||
"dev": true
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"dev": true
|
||||
},
|
||||
"prompts": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
|
||||
"integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"kleur": "^3.0.3",
|
||||
"sisteransi": "^1.0.5"
|
||||
}
|
||||
},
|
||||
"sisteransi": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
|
||||
"integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
|
||||
"dev": true
|
||||
},
|
||||
"typescript": {
|
||||
"version": "5.8.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz",
|
||||
"integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==",
|
||||
"dev": true
|
||||
},
|
||||
"undici-types": {
|
||||
"version": "6.19.8",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
|
||||
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
}
|
||||
51
mcp-extension-sample/package.json
Normal file
51
mcp-extension-sample/package.json
Normal file
@ -0,0 +1,51 @@
|
||||
{
|
||||
"enabledApiProposals": [
|
||||
"mcpConfigurationProvider"
|
||||
],
|
||||
"name": "mcp-extension-sample",
|
||||
"displayName": "mcp-extension-sample",
|
||||
"description": "Sample showing how to use Proposed API",
|
||||
"version": "0.0.1",
|
||||
"publisher": "vscode-samples",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"repository": "https://github.com/Microsoft/vscode-extension-samples",
|
||||
"engines": {
|
||||
"vscode": "^1.99.0"
|
||||
},
|
||||
"categories": [
|
||||
"Other"
|
||||
],
|
||||
"main": "./out/extension.js",
|
||||
"contributes": {
|
||||
"commands": [
|
||||
{
|
||||
"command": "mcp-extension-sample.addGist",
|
||||
"title": "MCP Extension Sample: Add Gist Source"
|
||||
},
|
||||
{
|
||||
"command": "mcp-extension-sample.removeGist",
|
||||
"title": "MCP Extension Sample: Remove Gist Source"
|
||||
}
|
||||
],
|
||||
"modelContextServerCollections": [
|
||||
{
|
||||
"id": "exampleGist",
|
||||
"label": "Github Gists"
|
||||
}
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"vscode:prepublish": "npm run compile",
|
||||
"compile": "tsc -p ./",
|
||||
"watch": "tsc -watch -p ./",
|
||||
"download-api": "dts dev",
|
||||
"postdownload-api": "dts main",
|
||||
"postinstall": "npm run download-api"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20",
|
||||
"@vscode/dts": "^0.4.1",
|
||||
"typescript": "^5.8.2"
|
||||
}
|
||||
}
|
||||
93
mcp-extension-sample/src/extension.ts
Normal file
93
mcp-extension-sample/src/extension.ts
Normal file
@ -0,0 +1,93 @@
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
export function activate(context: vscode.ExtensionContext) {
|
||||
let gists: string[] = context.globalState.get('gists', []);
|
||||
const didChangeEmitter = new vscode.EventEmitter<void>();
|
||||
|
||||
/**
|
||||
* You can use proposed API here. `vscode.` should start auto complete
|
||||
* Proposed API as defined in vscode.proposed.<proposalName>.d.ts.
|
||||
*/
|
||||
|
||||
|
||||
context.subscriptions.push(vscode.commands.registerCommand('mcp-extension-sample.addGist', async () => {
|
||||
const gist = await vscode.window.showInputBox({ prompt: 'Enter Gist URL' });
|
||||
if (gist) {
|
||||
gists.push(gist);
|
||||
context.globalState.update('gists', gists);
|
||||
vscode.window.showInformationMessage(`Gist added: ${gist}`);
|
||||
didChangeEmitter.fire();
|
||||
}
|
||||
}));
|
||||
|
||||
context.subscriptions.push(vscode.commands.registerCommand('mcp-extension-sample.removeGist', async () => {
|
||||
const gist = await vscode.window.showQuickPick(gists, { placeHolder: 'Select Gist to remove' });
|
||||
if (gist) {
|
||||
gists = gists.filter(g => g !== gist);
|
||||
context.globalState.update('gists', gists);
|
||||
vscode.window.showInformationMessage(`Gist removed: ${gist}`);
|
||||
didChangeEmitter.fire();
|
||||
}
|
||||
}));
|
||||
|
||||
context.subscriptions.push(vscode.lm.registerMcpConfigurationProvider('exampleGist', {
|
||||
onDidChange: didChangeEmitter.event,
|
||||
provideMcpServerDefinitions: async () => {
|
||||
let output: vscode.McpServerDefinition[] = [];
|
||||
await Promise.all(gists.map(g => fetchGistContents(g).then(content => {
|
||||
const s = JSON.parse(content);
|
||||
if (!Array.isArray(s)) {
|
||||
throw new Error(`Gist content is not an MCP server array: ${g}`);
|
||||
}
|
||||
|
||||
output.push(...s);
|
||||
})));
|
||||
|
||||
return output;
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
async function fetchGistContents(gistUrl: string): Promise<string> {
|
||||
// Parse the gist URL to get the ID
|
||||
const gistId = extractGistId(gistUrl);
|
||||
if (!gistId) {
|
||||
throw new Error(`Invalid Gist URL: ${gistUrl}`);
|
||||
}
|
||||
|
||||
// Fetch the raw gist content
|
||||
try {
|
||||
const response = await fetch(`https://api.github.com/gists/${gistId}`);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch gist: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
|
||||
const gistData: any = await response.json();
|
||||
|
||||
// Get the first file content from the gist
|
||||
const files = gistData.files;
|
||||
const firstFile = Object.keys(files)[0];
|
||||
|
||||
if (files[firstFile].truncated) {
|
||||
// If content is truncated, fetch the raw URL
|
||||
const rawResponse = await fetch(files[firstFile].raw_url);
|
||||
if (!rawResponse.ok) {
|
||||
throw new Error(`Failed to fetch raw content: ${rawResponse.status}`);
|
||||
}
|
||||
return await rawResponse.text();
|
||||
} else {
|
||||
return files[firstFile].content;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching gist:', error);
|
||||
throw error;
|
||||
}
|
||||
|
||||
// Helper function to extract gist ID from URL
|
||||
function extractGistId(url: string): string | null {
|
||||
// Handle URLs like https://gist.github.com/user/gistId or just the ID
|
||||
const match = url.match(/gist\.github\.com\/(?:[^/]+\/)?([a-zA-Z0-9]+)/) || url.match(/^([a-zA-Z0-9]+)$/);
|
||||
return match ? match[1] : null;
|
||||
}
|
||||
}
|
||||
12
mcp-extension-sample/tsconfig.json
Normal file
12
mcp-extension-sample/tsconfig.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "es2020",
|
||||
"lib": ["es2020"],
|
||||
"outDir": "out",
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"rootDir": "src"
|
||||
},
|
||||
"exclude": ["node_modules", ".vscode-test"]
|
||||
}
|
||||
Reference in New Issue
Block a user