mcp-lint 0.1.0 → 0.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 +222 -60
- package/dist/cli/commands/check.js +98 -52
- package/dist/cli/commands/check.js.map +1 -1
- package/dist/cli/commands/compat.d.ts +2 -0
- package/dist/cli/commands/compat.js +138 -0
- package/dist/cli/commands/compat.js.map +1 -0
- package/dist/cli/commands/diff.d.ts +2 -0
- package/dist/cli/commands/diff.js +134 -0
- package/dist/cli/commands/diff.js.map +1 -0
- package/dist/cli/commands/explain.d.ts +2 -0
- package/dist/cli/commands/explain.js +50 -0
- package/dist/cli/commands/explain.js.map +1 -0
- package/dist/cli/commands/fix.js +3 -1
- package/dist/cli/commands/fix.js.map +1 -1
- package/dist/config/config.d.ts +1 -1
- package/dist/config/config.js +6 -3
- package/dist/config/config.js.map +1 -1
- package/dist/config/plugin-loader.d.ts +6 -0
- package/dist/config/plugin-loader.js +19 -0
- package/dist/config/plugin-loader.js.map +1 -0
- package/dist/config/presets.d.ts +2 -0
- package/dist/config/presets.js +58 -0
- package/dist/config/presets.js.map +1 -0
- package/dist/core/compat-matrix.d.ts +13 -0
- package/dist/core/compat-matrix.js +31 -0
- package/dist/core/compat-matrix.js.map +1 -0
- package/dist/core/quality-score.d.ts +15 -0
- package/dist/core/quality-score.js +30 -0
- package/dist/core/quality-score.js.map +1 -0
- package/dist/core/rule.d.ts +11 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/rules/client-specific/cline.d.ts +2 -0
- package/dist/rules/client-specific/cline.js +49 -0
- package/dist/rules/client-specific/cline.js.map +1 -0
- package/dist/rules/client-specific/continue.d.ts +2 -0
- package/dist/rules/client-specific/continue.js +30 -0
- package/dist/rules/client-specific/continue.js.map +1 -0
- package/dist/rules/client-specific/openai.d.ts +3 -0
- package/dist/rules/client-specific/openai.js +59 -0
- package/dist/rules/client-specific/openai.js.map +1 -0
- package/dist/rules/client-specific/windsurf.d.ts +2 -0
- package/dist/rules/client-specific/windsurf.js +39 -0
- package/dist/rules/client-specific/windsurf.js.map +1 -0
- package/dist/rules/index.js +9 -0
- package/dist/rules/index.js.map +1 -1
- package/package.json +44 -44
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { loadFile } from '../../loaders/file-loader.js';
|
|
2
|
+
import { loadStdio } from '../../loaders/stdio-loader.js';
|
|
3
|
+
import { loadSSE } from '../../loaders/sse-loader.js';
|
|
4
|
+
import { LintEngine } from '../../core/engine.js';
|
|
5
|
+
import { buildCompatMatrix } from '../../core/compat-matrix.js';
|
|
6
|
+
import { allRules } from '../../rules/index.js';
|
|
7
|
+
import { loadConfig, DEFAULT_CONFIG } from '../../config/config.js';
|
|
8
|
+
import { loadPluginRules } from '../../config/plugin-loader.js';
|
|
9
|
+
import chalk from 'chalk';
|
|
10
|
+
function formatCompatTerminal(matrix, noColor) {
|
|
11
|
+
if (noColor)
|
|
12
|
+
chalk.level = 0;
|
|
13
|
+
const { tools, clients, cells } = matrix;
|
|
14
|
+
if (tools.length === 0)
|
|
15
|
+
return chalk.yellow('No tools found.\n');
|
|
16
|
+
const TOOL_WIDTH = Math.max(...tools.map((t) => t.length), 12) + 2;
|
|
17
|
+
const COL_WIDTH = 10;
|
|
18
|
+
const header = ' '.repeat(TOOL_WIDTH) +
|
|
19
|
+
clients.map((c) => c.padEnd(COL_WIDTH)).join('');
|
|
20
|
+
const rows = tools.map((tool) => {
|
|
21
|
+
const cols = clients.map((client) => {
|
|
22
|
+
const cell = cells[tool][client];
|
|
23
|
+
return cell.compatible
|
|
24
|
+
? chalk.green('✓'.padEnd(COL_WIDTH))
|
|
25
|
+
: chalk.red('✗'.padEnd(COL_WIDTH));
|
|
26
|
+
});
|
|
27
|
+
return tool.padEnd(TOOL_WIDTH) + cols.join('');
|
|
28
|
+
});
|
|
29
|
+
const incompatible = tools.filter((t) => clients.some((c) => !cells[t][c].compatible));
|
|
30
|
+
const summary = incompatible.length === 0
|
|
31
|
+
? chalk.green('\nAll tools compatible across all clients.\n')
|
|
32
|
+
: chalk.yellow(`\n${incompatible.length} tool${incompatible.length !== 1 ? 's' : ''} have compatibility issues. Run \`mcp-lint check\` for details.\n`);
|
|
33
|
+
return ['\n', header, ...rows, summary].join('\n');
|
|
34
|
+
}
|
|
35
|
+
function formatCompatJson(matrix) {
|
|
36
|
+
const result = {
|
|
37
|
+
tools: matrix.tools,
|
|
38
|
+
clients: matrix.clients,
|
|
39
|
+
matrix: {},
|
|
40
|
+
};
|
|
41
|
+
for (const tool of matrix.tools) {
|
|
42
|
+
result.matrix[tool] = {};
|
|
43
|
+
for (const client of matrix.clients) {
|
|
44
|
+
const cell = matrix.cells[tool][client];
|
|
45
|
+
(result.matrix[tool])[client] = {
|
|
46
|
+
compatible: cell.compatible,
|
|
47
|
+
errorCount: cell.errorCount,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return JSON.stringify(result, null, 2) + '\n';
|
|
52
|
+
}
|
|
53
|
+
function formatCompatMarkdown(matrix) {
|
|
54
|
+
const { tools, clients, cells } = matrix;
|
|
55
|
+
if (tools.length === 0)
|
|
56
|
+
return '_No tools found._\n';
|
|
57
|
+
const header = `| Tool | ${clients.join(' | ')} |`;
|
|
58
|
+
const separator = `|------|${clients.map(() => '------|').join('')}`;
|
|
59
|
+
const rows = tools.map((tool) => {
|
|
60
|
+
const cols = clients.map((c) => (cells[tool][c].compatible ? '✅' : '❌'));
|
|
61
|
+
return `| ${tool} | ${cols.join(' | ')} |`;
|
|
62
|
+
});
|
|
63
|
+
const incompatible = tools.filter((t) => clients.some((c) => !cells[t][c].compatible));
|
|
64
|
+
const summary = incompatible.length === 0
|
|
65
|
+
? '\n_All tools compatible across all clients._\n'
|
|
66
|
+
: `\n_${incompatible.length} tool(s) have compatibility issues. Run \`mcp-lint check\` for details._\n`;
|
|
67
|
+
return [header, separator, ...rows, summary].join('\n') + '\n';
|
|
68
|
+
}
|
|
69
|
+
export function registerCompatCommand(program) {
|
|
70
|
+
program
|
|
71
|
+
.command('compat [input]')
|
|
72
|
+
.description('Show compatibility matrix across all MCP clients')
|
|
73
|
+
.option('--format <format>', 'Output format: terminal|json|markdown', 'terminal')
|
|
74
|
+
.option('--no-color', 'Disable terminal colors')
|
|
75
|
+
.option('--config <path>', 'Path to .mcplintrc.json config file')
|
|
76
|
+
.option('--client <client>', 'Show only one client column')
|
|
77
|
+
.option('--server <type>', 'Server transport: stdio|sse')
|
|
78
|
+
.option('--url <url>', 'SSE server URL (use with --server sse)')
|
|
79
|
+
.allowExcessArguments(true)
|
|
80
|
+
.action(async (input, options) => {
|
|
81
|
+
try {
|
|
82
|
+
const fileConfig = await loadConfig(options.config);
|
|
83
|
+
const config = {
|
|
84
|
+
clients: DEFAULT_CONFIG.clients,
|
|
85
|
+
...fileConfig,
|
|
86
|
+
};
|
|
87
|
+
let tools;
|
|
88
|
+
if (options.server === 'stdio') {
|
|
89
|
+
const rawArgv = process.argv;
|
|
90
|
+
const sepIdx = rawArgv.indexOf('--');
|
|
91
|
+
if (sepIdx === -1 || sepIdx >= rawArgv.length - 1) {
|
|
92
|
+
throw new Error('--server stdio requires a command after --');
|
|
93
|
+
}
|
|
94
|
+
const [cmd, ...cmdArgs] = rawArgv.slice(sepIdx + 1);
|
|
95
|
+
tools = await loadStdio(cmd, cmdArgs);
|
|
96
|
+
}
|
|
97
|
+
else if (options.server === 'sse') {
|
|
98
|
+
if (!options.url)
|
|
99
|
+
throw new Error('--server sse requires --url <url>');
|
|
100
|
+
tools = await loadSSE(options.url);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
if (!input)
|
|
104
|
+
throw new Error('Specify an input file or use --server stdio|sse');
|
|
105
|
+
tools = await loadFile(input);
|
|
106
|
+
}
|
|
107
|
+
const pluginRules = await loadPluginRules(config);
|
|
108
|
+
const engine = new LintEngine([...allRules, ...pluginRules], config);
|
|
109
|
+
const diagnostics = engine.lint(tools);
|
|
110
|
+
let matrix = buildCompatMatrix(tools, diagnostics);
|
|
111
|
+
if (options.client) {
|
|
112
|
+
const clientId = options.client;
|
|
113
|
+
if (!matrix.clients.includes(clientId)) {
|
|
114
|
+
throw new Error(`Unknown client "${options.client}". Available: ${matrix.clients.join(', ')}`);
|
|
115
|
+
}
|
|
116
|
+
matrix = { ...matrix, clients: [clientId] };
|
|
117
|
+
}
|
|
118
|
+
let output;
|
|
119
|
+
if (options.format === 'json') {
|
|
120
|
+
output = formatCompatJson(matrix);
|
|
121
|
+
}
|
|
122
|
+
else if (options.format === 'markdown') {
|
|
123
|
+
output = formatCompatMarkdown(matrix);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
output = formatCompatTerminal(matrix, !options.color);
|
|
127
|
+
}
|
|
128
|
+
process.stdout.write(output);
|
|
129
|
+
const hasIncompatible = matrix.tools.some((t) => matrix.clients.some((c) => !matrix.cells[t][c].compatible));
|
|
130
|
+
process.exit(hasIncompatible ? 1 : 0);
|
|
131
|
+
}
|
|
132
|
+
catch (err) {
|
|
133
|
+
process.stderr.write(`Error: ${err.message}\n`);
|
|
134
|
+
process.exit(2);
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=compat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compat.js","sourceRoot":"","sources":["../../../src/cli/commands/compat.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { loadFile } from '../../loaders/file-loader.js';
|
|
2
|
+
import { LintEngine } from '../../core/engine.js';
|
|
3
|
+
import { allRules } from '../../rules/index.js';
|
|
4
|
+
import { loadConfig, DEFAULT_CONFIG } from '../../config/config.js';
|
|
5
|
+
import { loadPluginRules } from '../../config/plugin-loader.js';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
function diffDiagnostics(before, after) {
|
|
8
|
+
const key = (d) => `${d.toolName}::${d.ruleId}::${d.path}`;
|
|
9
|
+
const beforeMap = new Map(before.map((d) => [key(d), d]));
|
|
10
|
+
const afterMap = new Map(after.map((d) => [key(d), d]));
|
|
11
|
+
const fixed = before.filter((d) => !afterMap.has(key(d)));
|
|
12
|
+
const introduced = after.filter((d) => !beforeMap.has(key(d)));
|
|
13
|
+
const unchanged = after.filter((d) => beforeMap.has(key(d)));
|
|
14
|
+
return { fixed, introduced, unchanged };
|
|
15
|
+
}
|
|
16
|
+
function formatDiffTerminal(diff, noColor) {
|
|
17
|
+
if (noColor)
|
|
18
|
+
chalk.level = 0;
|
|
19
|
+
const lines = [''];
|
|
20
|
+
if (diff.introduced.length === 0 && diff.fixed.length === 0) {
|
|
21
|
+
lines.push(chalk.dim('No changes in lint results.\n'));
|
|
22
|
+
return lines.join('\n');
|
|
23
|
+
}
|
|
24
|
+
if (diff.introduced.length > 0) {
|
|
25
|
+
lines.push(chalk.bold.red(`✖ ${diff.introduced.length} new issue${diff.introduced.length !== 1 ? 's' : ''} introduced:`));
|
|
26
|
+
for (const d of diff.introduced) {
|
|
27
|
+
const icon = d.severity === 'error' ? chalk.red('✖') : chalk.yellow('⚠');
|
|
28
|
+
lines.push(` ${icon} [${d.toolName}] ${chalk.red(d.message)}`);
|
|
29
|
+
lines.push(` ${chalk.gray(d.path)} ${chalk.dim(`[${d.ruleId}]`)}`);
|
|
30
|
+
}
|
|
31
|
+
lines.push('');
|
|
32
|
+
}
|
|
33
|
+
if (diff.fixed.length > 0) {
|
|
34
|
+
lines.push(chalk.bold.green(`✔ ${diff.fixed.length} issue${diff.fixed.length !== 1 ? 's' : ''} fixed:`));
|
|
35
|
+
for (const d of diff.fixed) {
|
|
36
|
+
lines.push(` ${chalk.green('✔')} [${d.toolName}] ${chalk.green(d.message)}`);
|
|
37
|
+
lines.push(` ${chalk.gray(d.path)} ${chalk.dim(`[${d.ruleId}]`)}`);
|
|
38
|
+
}
|
|
39
|
+
lines.push('');
|
|
40
|
+
}
|
|
41
|
+
if (diff.unchanged.length > 0) {
|
|
42
|
+
lines.push(chalk.dim(`${diff.unchanged.length} existing issue${diff.unchanged.length !== 1 ? 's' : ''} unchanged.`));
|
|
43
|
+
lines.push('');
|
|
44
|
+
}
|
|
45
|
+
return lines.join('\n');
|
|
46
|
+
}
|
|
47
|
+
function formatDiffJson(diff) {
|
|
48
|
+
return JSON.stringify({
|
|
49
|
+
introduced: diff.introduced,
|
|
50
|
+
fixed: diff.fixed,
|
|
51
|
+
unchanged: diff.unchanged,
|
|
52
|
+
summary: {
|
|
53
|
+
introduced: diff.introduced.length,
|
|
54
|
+
fixed: diff.fixed.length,
|
|
55
|
+
unchanged: diff.unchanged.length,
|
|
56
|
+
},
|
|
57
|
+
}, null, 2) + '\n';
|
|
58
|
+
}
|
|
59
|
+
function formatDiffMarkdown(diff) {
|
|
60
|
+
const lines = [];
|
|
61
|
+
if (diff.introduced.length === 0 && diff.fixed.length === 0) {
|
|
62
|
+
lines.push('_No changes in lint results._');
|
|
63
|
+
return lines.join('\n') + '\n';
|
|
64
|
+
}
|
|
65
|
+
if (diff.introduced.length > 0) {
|
|
66
|
+
lines.push(`### ❌ ${diff.introduced.length} new issue${diff.introduced.length !== 1 ? 's' : ''} introduced`);
|
|
67
|
+
lines.push('');
|
|
68
|
+
for (const d of diff.introduced) {
|
|
69
|
+
lines.push(`- **[${d.toolName}]** \`${d.ruleId}\` — ${d.message}`);
|
|
70
|
+
}
|
|
71
|
+
lines.push('');
|
|
72
|
+
}
|
|
73
|
+
if (diff.fixed.length > 0) {
|
|
74
|
+
lines.push(`### ✅ ${diff.fixed.length} issue${diff.fixed.length !== 1 ? 's' : ''} fixed`);
|
|
75
|
+
lines.push('');
|
|
76
|
+
for (const d of diff.fixed) {
|
|
77
|
+
lines.push(`- **[${d.toolName}]** \`${d.ruleId}\` — ${d.message}`);
|
|
78
|
+
}
|
|
79
|
+
lines.push('');
|
|
80
|
+
}
|
|
81
|
+
if (diff.unchanged.length > 0) {
|
|
82
|
+
lines.push(`_${diff.unchanged.length} existing issue${diff.unchanged.length !== 1 ? 's' : ''} unchanged._`);
|
|
83
|
+
}
|
|
84
|
+
return lines.join('\n') + '\n';
|
|
85
|
+
}
|
|
86
|
+
export function registerDiffCommand(program) {
|
|
87
|
+
program
|
|
88
|
+
.command('diff <before> <after>')
|
|
89
|
+
.description('Compare lint results between two schema versions')
|
|
90
|
+
.option('--format <format>', 'Output format: terminal|json|markdown', 'terminal')
|
|
91
|
+
.option('--no-color', 'Disable terminal colors')
|
|
92
|
+
.option('--config <path>', 'Path to .mcplintrc.json config file')
|
|
93
|
+
.option('--clients <clients>', 'Comma-separated client filter')
|
|
94
|
+
.action(async (before, after, options) => {
|
|
95
|
+
try {
|
|
96
|
+
const fileConfig = await loadConfig(options.config);
|
|
97
|
+
const cliClients = options.clients
|
|
98
|
+
? options.clients.split(',').map((s) => s.trim())
|
|
99
|
+
: undefined;
|
|
100
|
+
const config = {
|
|
101
|
+
clients: DEFAULT_CONFIG.clients,
|
|
102
|
+
...fileConfig,
|
|
103
|
+
...(cliClients ? { clients: cliClients } : {}),
|
|
104
|
+
};
|
|
105
|
+
const [toolsBefore, toolsAfter] = await Promise.all([
|
|
106
|
+
loadFile(before),
|
|
107
|
+
loadFile(after),
|
|
108
|
+
]);
|
|
109
|
+
const pluginRules = await loadPluginRules(config);
|
|
110
|
+
const engine = new LintEngine([...allRules, ...pluginRules], config);
|
|
111
|
+
const diagBefore = engine.lint(toolsBefore);
|
|
112
|
+
const diagAfter = engine.lint(toolsAfter);
|
|
113
|
+
const diff = diffDiagnostics(diagBefore, diagAfter);
|
|
114
|
+
let output;
|
|
115
|
+
if (options.format === 'json') {
|
|
116
|
+
output = formatDiffJson(diff);
|
|
117
|
+
}
|
|
118
|
+
else if (options.format === 'markdown') {
|
|
119
|
+
output = formatDiffMarkdown(diff);
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
output = formatDiffTerminal(diff, !options.color);
|
|
123
|
+
}
|
|
124
|
+
process.stdout.write(output);
|
|
125
|
+
const hasNewErrors = diff.introduced.some((d) => d.severity === 'error');
|
|
126
|
+
process.exit(hasNewErrors ? 1 : 0);
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
process.stderr.write(`Error: ${err.message}\n`);
|
|
130
|
+
process.exit(2);
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=diff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.js","sourceRoot":"","sources":["../../../src/cli/commands/diff.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { allRules } from '../../rules/index.js';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
export function registerExplainCommand(program) {
|
|
4
|
+
program
|
|
5
|
+
.command('explain <rule-id>')
|
|
6
|
+
.description('Show documentation and examples for a rule')
|
|
7
|
+
.option('--no-color', 'Disable terminal colors')
|
|
8
|
+
.action((ruleId, options) => {
|
|
9
|
+
if (!options.color)
|
|
10
|
+
chalk.level = 0;
|
|
11
|
+
const rule = allRules.find((r) => r.id === ruleId);
|
|
12
|
+
if (!rule) {
|
|
13
|
+
const available = allRules.map((r) => ` ${r.id}`).join('\n');
|
|
14
|
+
process.stderr.write(`Unknown rule "${ruleId}".\n\nAvailable rules:\n${available}\n`);
|
|
15
|
+
process.exit(2);
|
|
16
|
+
}
|
|
17
|
+
const lines = [];
|
|
18
|
+
lines.push('');
|
|
19
|
+
lines.push(chalk.bold(`Rule: ${chalk.cyan(rule.id)}`));
|
|
20
|
+
lines.push(`Severity: ${rule.severity === 'error' ? chalk.red(rule.severity) : chalk.yellow(rule.severity)}`);
|
|
21
|
+
lines.push(`Clients: ${rule.clients.join(', ')}`);
|
|
22
|
+
lines.push(`Fixable: ${rule.docs?.fixNote ? chalk.green('yes') : chalk.dim('no')}`);
|
|
23
|
+
lines.push('');
|
|
24
|
+
lines.push(chalk.bold('Description'));
|
|
25
|
+
lines.push(rule.description);
|
|
26
|
+
if (rule.docs) {
|
|
27
|
+
lines.push('');
|
|
28
|
+
lines.push(chalk.bold('Why'));
|
|
29
|
+
lines.push(rule.docs.why);
|
|
30
|
+
lines.push('');
|
|
31
|
+
lines.push(chalk.bold('Bad example'));
|
|
32
|
+
lines.push(JSON.stringify(rule.docs.badExample, null, 2));
|
|
33
|
+
lines.push('');
|
|
34
|
+
lines.push(chalk.bold('Good example'));
|
|
35
|
+
lines.push(JSON.stringify(rule.docs.goodExample, null, 2));
|
|
36
|
+
if (rule.docs.fixNote) {
|
|
37
|
+
lines.push('');
|
|
38
|
+
lines.push(chalk.bold('Auto-fix'));
|
|
39
|
+
lines.push(rule.docs.fixNote);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
lines.push('');
|
|
44
|
+
lines.push(chalk.dim('No additional documentation available for this rule.'));
|
|
45
|
+
}
|
|
46
|
+
lines.push('');
|
|
47
|
+
process.stdout.write(lines.join('\n'));
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=explain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"explain.js","sourceRoot":"","sources":["../../../src/cli/commands/explain.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/commands/fix.js
CHANGED
|
@@ -4,6 +4,7 @@ import { LintEngine } from '../../core/engine.js';
|
|
|
4
4
|
import { allRules } from '../../rules/index.js';
|
|
5
5
|
import { applyFixes } from '../../core/fixer.js';
|
|
6
6
|
import { loadConfig } from '../../config/config.js';
|
|
7
|
+
import { loadPluginRules } from '../../config/plugin-loader.js';
|
|
7
8
|
export function registerFixCommand(program) {
|
|
8
9
|
program
|
|
9
10
|
.command('fix <input>')
|
|
@@ -16,8 +17,9 @@ export function registerFixCommand(program) {
|
|
|
16
17
|
.action(async (input, options) => {
|
|
17
18
|
try {
|
|
18
19
|
const fileConfig = await loadConfig(options.config);
|
|
20
|
+
const pluginRules = await loadPluginRules(fileConfig);
|
|
19
21
|
const tools = await loadFile(input);
|
|
20
|
-
const engine = new LintEngine(allRules, fileConfig);
|
|
22
|
+
const engine = new LintEngine([...allRules, ...pluginRules], fileConfig);
|
|
21
23
|
const diagnostics = engine.lint(tools);
|
|
22
24
|
const onlyRules = options.rules
|
|
23
25
|
? options.rules.split(',').map((r) => r.trim())
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fix.js","sourceRoot":"","sources":["../../../src/cli/commands/fix.ts"],"names":[],"mappings":"AACA,OAAO,EAAY,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"fix.js","sourceRoot":"","sources":["../../../src/cli/commands/fix.ts"],"names":[],"mappings":"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"}
|
package/dist/config/config.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { Config } from '../core/rule.js';
|
|
2
2
|
export declare function loadConfig(configPath?: string): Promise<Config>;
|
|
3
|
-
export declare const DEFAULT_CONFIG: Required<Omit<Config, 'rules'>>;
|
|
3
|
+
export declare const DEFAULT_CONFIG: Required<Omit<Config, 'rules' | 'extends' | 'plugins'>>;
|
package/dist/config/config.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
2
|
import { resolve, dirname } from 'node:path';
|
|
3
3
|
import { homedir } from 'node:os';
|
|
4
|
+
import { applyExtends } from './presets.js';
|
|
4
5
|
async function readConfigFile(filePath) {
|
|
5
6
|
const content = await readFile(filePath, 'utf-8');
|
|
6
7
|
return JSON.parse(content);
|
|
@@ -8,7 +9,8 @@ async function readConfigFile(filePath) {
|
|
|
8
9
|
export async function loadConfig(configPath) {
|
|
9
10
|
if (configPath) {
|
|
10
11
|
try {
|
|
11
|
-
|
|
12
|
+
const raw = await readConfigFile(configPath);
|
|
13
|
+
return await applyExtends(raw);
|
|
12
14
|
}
|
|
13
15
|
catch (err) {
|
|
14
16
|
throw new Error(`Cannot load config from "${configPath}": ${err.message}`);
|
|
@@ -18,7 +20,8 @@ export async function loadConfig(configPath) {
|
|
|
18
20
|
const home = homedir();
|
|
19
21
|
while (true) {
|
|
20
22
|
try {
|
|
21
|
-
|
|
23
|
+
const raw = await readConfigFile(resolve(dir, '.mcplintrc.json'));
|
|
24
|
+
return await applyExtends(raw);
|
|
22
25
|
}
|
|
23
26
|
catch {
|
|
24
27
|
// not found here, try parent
|
|
@@ -31,7 +34,7 @@ export async function loadConfig(configPath) {
|
|
|
31
34
|
return {};
|
|
32
35
|
}
|
|
33
36
|
export const DEFAULT_CONFIG = {
|
|
34
|
-
clients: ['claude', 'cursor', 'gemini', 'vscode'],
|
|
37
|
+
clients: ['claude', 'cursor', 'gemini', 'vscode', 'windsurf', 'cline', 'openai', 'continue'],
|
|
35
38
|
ignore: [],
|
|
36
39
|
maxDepth: 5,
|
|
37
40
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,KAAK,UAAU,cAAc,CAAC,QAAgB;IAC5C,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAClD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAW,CAAC;AACvC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,UAAmB;IAClD,IAAI,UAAU,EAAE,CAAC;QACf,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,UAAU,CAAC,CAAC;YAC7C,OAAO,MAAM,YAAY,CAAC,GAAG,CAAC,CAAC;QACjC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,4BAA4B,UAAU,MAAO,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;QACxF,CAAC;IACH,CAAC;IAED,IAAI,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IACxB,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IAEvB,OAAO,IAAI,EAAE,CAAC;QACZ,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,OAAO,CAAC,GAAG,EAAE,iBAAiB,CAAC,CAAC,CAAC;YAClE,OAAO,MAAM,YAAY,CAAC,GAAG,CAAC,CAAC;QACjC,CAAC;QAAC,MAAM,CAAC;YACP,6BAA6B;QAC/B,CAAC;QAED,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,MAAM,KAAK,GAAG,IAAI,GAAG,KAAK,IAAI;YAAE,MAAM;QAC1C,GAAG,GAAG,MAAM,CAAC;IACf,CAAC;IAED,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAA4D;IACrF,OAAO,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,CAAC;IAC5F,MAAM,EAAE,EAAE;IACV,QAAQ,EAAE,CAAC;CACZ,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export async function loadPluginRules(config) {
|
|
2
|
+
if (!config.plugins?.length)
|
|
3
|
+
return [];
|
|
4
|
+
const extraRules = [];
|
|
5
|
+
for (const pkgName of config.plugins) {
|
|
6
|
+
let mod;
|
|
7
|
+
try {
|
|
8
|
+
mod = (await import(pkgName));
|
|
9
|
+
}
|
|
10
|
+
catch (err) {
|
|
11
|
+
throw new Error(`Cannot load plugin "${pkgName}": ${err.message}`);
|
|
12
|
+
}
|
|
13
|
+
const plugin = mod.default ?? mod;
|
|
14
|
+
if (plugin.rules)
|
|
15
|
+
extraRules.push(...plugin.rules);
|
|
16
|
+
}
|
|
17
|
+
return extraRules;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=plugin-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-loader.js","sourceRoot":"","sources":["../../src/config/plugin-loader.ts"],"names":[],"mappings":"AAOA,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,MAAc;IAClD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM;QAAE,OAAO,EAAE,CAAC;IAEvC,MAAM,UAAU,GAAW,EAAE,CAAC;IAC9B,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACrC,IAAI,GAAiB,CAAC;QACtB,IAAI,CAAC;YACH,GAAG,GAAG,CAAC,MAAM,MAAM,CAAC,OAAO,CAAC,CAAiB,CAAC;QAChD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,uBAAuB,OAAO,MAAO,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;QAChF,CAAC;QAED,MAAM,MAAM,GAAkB,GAAkC,CAAC,OAAO,IAAI,GAAG,CAAC;QAChF,IAAI,MAAM,CAAC,KAAK;YAAE,UAAU,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IACrD,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
const recommended = {
|
|
2
|
+
clients: ['claude', 'cursor', 'gemini', 'vscode', 'windsurf', 'cline', 'openai', 'continue'],
|
|
3
|
+
ignore: [],
|
|
4
|
+
maxDepth: 5,
|
|
5
|
+
};
|
|
6
|
+
const strict = {
|
|
7
|
+
clients: ['claude', 'cursor', 'gemini', 'vscode', 'windsurf', 'cline', 'openai', 'continue'],
|
|
8
|
+
ignore: [],
|
|
9
|
+
maxDepth: 3,
|
|
10
|
+
rules: {
|
|
11
|
+
'no-required-false': 'error',
|
|
12
|
+
'no-content-encoding': 'error',
|
|
13
|
+
'description-exists': 'error',
|
|
14
|
+
'no-empty-enum': 'error',
|
|
15
|
+
'max-depth': 'error',
|
|
16
|
+
'no-recursive-refs': 'error',
|
|
17
|
+
'valid-json-schema-subset': 'error',
|
|
18
|
+
'no-unsupported-formats': 'error',
|
|
19
|
+
'claude/no-type-array': 'error',
|
|
20
|
+
'cursor/no-default-without-type': 'error',
|
|
21
|
+
'gemini/no-optional-without-default': 'error',
|
|
22
|
+
'gemini/no-nested-objects': 'error',
|
|
23
|
+
'vscode/max-params': 'error',
|
|
24
|
+
'windsurf/no-union-types': 'error',
|
|
25
|
+
'cline/description-max-length': 'error',
|
|
26
|
+
'openai/no-additional-properties': 'error',
|
|
27
|
+
'openai/strict-types': 'error',
|
|
28
|
+
'continue/no-default-values': 'error',
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
const PRESETS = { recommended, strict };
|
|
32
|
+
export async function applyExtends(userConfig) {
|
|
33
|
+
const presetName = userConfig.extends;
|
|
34
|
+
if (!presetName)
|
|
35
|
+
return userConfig;
|
|
36
|
+
let preset;
|
|
37
|
+
if (PRESETS[presetName]) {
|
|
38
|
+
preset = PRESETS[presetName];
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
try {
|
|
42
|
+
const mod = await import(presetName);
|
|
43
|
+
preset = (mod.default ?? mod);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
throw new Error(`Unknown preset "${presetName}". Builtin presets: ${Object.keys(PRESETS).join(', ')}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const { extends: _removed, ...restUser } = userConfig;
|
|
50
|
+
return {
|
|
51
|
+
...preset,
|
|
52
|
+
...restUser,
|
|
53
|
+
rules: { ...preset.rules, ...restUser.rules },
|
|
54
|
+
clients: restUser.clients ?? preset.clients,
|
|
55
|
+
ignore: [...(preset.ignore ?? []), ...(restUser.ignore ?? [])],
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=presets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presets.js","sourceRoot":"","sources":["../../src/config/presets.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,GAAW;IAC1B,OAAO,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,CAAC;IAC5F,MAAM,EAAE,EAAE;IACV,QAAQ,EAAE,CAAC;CACZ,CAAC;AAEF,MAAM,MAAM,GAAW;IACrB,OAAO,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,CAAC;IAC5F,MAAM,EAAE,EAAE;IACV,QAAQ,EAAE,CAAC;IACX,KAAK,EAAE;QACL,mBAAmB,EAAE,OAAO;QAC5B,qBAAqB,EAAE,OAAO;QAC9B,oBAAoB,EAAE,OAAO;QAC7B,eAAe,EAAE,OAAO;QACxB,WAAW,EAAE,OAAO;QACpB,mBAAmB,EAAE,OAAO;QAC5B,0BAA0B,EAAE,OAAO;QACnC,wBAAwB,EAAE,OAAO;QACjC,sBAAsB,EAAE,OAAO;QAC/B,gCAAgC,EAAE,OAAO;QACzC,oCAAoC,EAAE,OAAO;QAC7C,0BAA0B,EAAE,OAAO;QACnC,mBAAmB,EAAE,OAAO;QAC5B,yBAAyB,EAAE,OAAO;QAClC,8BAA8B,EAAE,OAAO;QACvC,iCAAiC,EAAE,OAAO;QAC1C,qBAAqB,EAAE,OAAO;QAC9B,4BAA4B,EAAE,OAAO;KACtC;CACF,CAAC;AAEF,MAAM,OAAO,GAA2B,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC;AAEhE,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,UAAkB;IACnD,MAAM,UAAU,GAAG,UAAU,CAAC,OAAO,CAAC;IACtC,IAAI,CAAC,UAAU;QAAE,OAAO,UAAU,CAAC;IAEnC,IAAI,MAAc,CAAC;IACnB,IAAI,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;QACxB,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC/B,CAAC;SAAM,CAAC;QACN,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;YACrC,MAAM,GAAG,CAAE,GAA4B,CAAC,OAAO,IAAI,GAAG,CAAW,CAAC;QACpE,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,KAAK,CAAC,mBAAmB,UAAU,uBAAuB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACzG,CAAC;IACH,CAAC;IAED,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,QAAQ,EAAE,GAAG,UAAU,CAAC;IACtD,OAAO;QACL,GAAG,MAAM;QACT,GAAG,QAAQ;QACX,KAAK,EAAE,EAAE,GAAG,MAAM,CAAC,KAAK,EAAE,GAAG,QAAQ,CAAC,KAAK,EAAE;QAC7C,OAAO,EAAE,QAAQ,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO;QAC3C,MAAM,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,QAAQ,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;KAC/D,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ClientId, MCPTool } from './rule.js';
|
|
2
|
+
import type { Diagnostic } from './diagnostic.js';
|
|
3
|
+
export interface CompatCell {
|
|
4
|
+
compatible: boolean;
|
|
5
|
+
errorCount: number;
|
|
6
|
+
issues: Diagnostic[];
|
|
7
|
+
}
|
|
8
|
+
export interface CompatMatrix {
|
|
9
|
+
tools: string[];
|
|
10
|
+
clients: ClientId[];
|
|
11
|
+
cells: Record<string, Record<ClientId, CompatCell>>;
|
|
12
|
+
}
|
|
13
|
+
export declare function buildCompatMatrix(tools: MCPTool[], diagnostics: Diagnostic[]): CompatMatrix;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const ALL_CLIENTS = [
|
|
2
|
+
'claude', 'cursor', 'gemini', 'vscode',
|
|
3
|
+
'windsurf', 'cline', 'openai', 'continue',
|
|
4
|
+
];
|
|
5
|
+
export function buildCompatMatrix(tools, diagnostics) {
|
|
6
|
+
const cells = {};
|
|
7
|
+
for (const tool of tools) {
|
|
8
|
+
cells[tool.name] = {};
|
|
9
|
+
for (const client of ALL_CLIENTS) {
|
|
10
|
+
cells[tool.name][client] = { compatible: true, errorCount: 0, issues: [] };
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
for (const diag of diagnostics) {
|
|
14
|
+
for (const client of diag.clients) {
|
|
15
|
+
const cell = cells[diag.toolName]?.[client];
|
|
16
|
+
if (!cell)
|
|
17
|
+
continue;
|
|
18
|
+
cell.issues.push(diag);
|
|
19
|
+
if (diag.severity === 'error') {
|
|
20
|
+
cell.errorCount++;
|
|
21
|
+
cell.compatible = false;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
tools: tools.map((t) => t.name),
|
|
27
|
+
clients: ALL_CLIENTS,
|
|
28
|
+
cells,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=compat-matrix.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compat-matrix.js","sourceRoot":"","sources":["../../src/core/compat-matrix.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,GAAe;IAC9B,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ;IACtC,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU;CAC1C,CAAC;AAEF,MAAM,UAAU,iBAAiB,CAAC,KAAgB,EAAE,WAAyB;IAC3E,MAAM,KAAK,GAAiD,EAAE,CAAC;IAE/D,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAkC,CAAC;QACtD,KAAK,MAAM,MAAM,IAAI,WAAW,EAAE,CAAC;YACjC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;QAC7E,CAAC;IACH,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAClC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;YAC5C,IAAI,CAAC,IAAI;gBAAE,SAAS;YACpB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACvB,IAAI,IAAI,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;gBAC9B,IAAI,CAAC,UAAU,EAAE,CAAC;gBAClB,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;YAC1B,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO;QACL,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QAC/B,OAAO,EAAE,WAAW;QACpB,KAAK;KACN,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Diagnostic } from './diagnostic.js';
|
|
2
|
+
import type { MCPTool } from './rule.js';
|
|
3
|
+
export interface ToolScore {
|
|
4
|
+
toolName: string;
|
|
5
|
+
score: number;
|
|
6
|
+
grade: 'A' | 'B' | 'C' | 'D' | 'F';
|
|
7
|
+
errors: number;
|
|
8
|
+
warnings: number;
|
|
9
|
+
}
|
|
10
|
+
export interface QualityReport {
|
|
11
|
+
overall: number;
|
|
12
|
+
grade: 'A' | 'B' | 'C' | 'D' | 'F';
|
|
13
|
+
tools: ToolScore[];
|
|
14
|
+
}
|
|
15
|
+
export declare function computeQualityReport(tools: MCPTool[], diagnostics: Diagnostic[]): QualityReport;
|