mcprigor 1.2.0 → 1.3.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 +5 -1
- package/dist/cli.js +98 -3
- package/dist/cli.js.map +1 -1
- package/dist/flaky.d.ts +34 -0
- package/dist/flaky.d.ts.map +1 -0
- package/dist/flaky.js +80 -0
- package/dist/flaky.js.map +1 -0
- package/dist/project-config.d.ts +16 -0
- package/dist/project-config.d.ts.map +1 -0
- package/dist/project-config.js +91 -0
- package/dist/project-config.js.map +1 -0
- package/dist/qa-language.d.ts.map +1 -1
- package/dist/qa-language.js +25 -2
- package/dist/qa-language.js.map +1 -1
- package/dist/record.d.ts +16 -0
- package/dist/record.d.ts.map +1 -0
- package/dist/record.js +124 -0
- package/dist/record.js.map +1 -0
- package/dist/runner.d.ts +6 -0
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +28 -4
- package/dist/runner.js.map +1 -1
- package/dist/schema.d.ts +80 -0
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +17 -1
- package/dist/schema.js.map +1 -1
- package/dist/session.d.ts +2 -0
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +29 -2
- package/dist/session.js.map +1 -1
- package/dist/types.d.ts +5 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +20 -1
- package/dist/workspace.js.map +1 -1
- package/docs/CLI-REFERENCE.md +59 -0
- package/docs/ENGINEER-SETUP.md +1 -1
- package/docs/LANGUAGE-SPEC.md +10 -0
- package/docs/PLAIN-LANGUAGE-COOKBOOK.md +44 -0
- package/docs/TROUBLESHOOTING.md +4 -0
- package/editors/mcpr-language.json +39 -10
- package/editors/vscode/.vscodeignore +1 -0
- package/editors/vscode/README.md +25 -0
- package/editors/vscode/extension.js +61 -0
- package/editors/vscode/language-configuration.json +11 -0
- package/editors/vscode/package.json +34 -0
- package/editors/vscode/syntaxes/mcpr.tmLanguage.json +45 -0
- package/package.json +1 -1
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// MCP Rigor VS Code extension: on-save validation via the mcprigor CLI.
|
|
2
|
+
// Plain CommonJS, zero dependencies beyond the vscode API.
|
|
3
|
+
const vscode = require("vscode");
|
|
4
|
+
const { exec } = require("node:child_process");
|
|
5
|
+
|
|
6
|
+
let diagnostics;
|
|
7
|
+
|
|
8
|
+
function activate(context) {
|
|
9
|
+
diagnostics = vscode.languages.createDiagnosticCollection("mcprigor");
|
|
10
|
+
context.subscriptions.push(diagnostics);
|
|
11
|
+
context.subscriptions.push(vscode.workspace.onDidSaveTextDocument((document) => {
|
|
12
|
+
if (document.languageId !== "mcpr") return;
|
|
13
|
+
if (!vscode.workspace.getConfiguration("mcprigor").get("validateOnSave", true)) return;
|
|
14
|
+
validate(document);
|
|
15
|
+
}));
|
|
16
|
+
context.subscriptions.push(vscode.workspace.onDidOpenTextDocument((document) => {
|
|
17
|
+
if (document.languageId === "mcpr") validate(document);
|
|
18
|
+
}));
|
|
19
|
+
for (const document of vscode.workspace.textDocuments) if (document.languageId === "mcpr") validate(document);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function validate(document) {
|
|
23
|
+
const command = vscode.workspace.getConfiguration("mcprigor").get("command", "npx mcprigor");
|
|
24
|
+
const folder = vscode.workspace.getWorkspaceFolder(document.uri);
|
|
25
|
+
const cwd = folder ? folder.uri.fsPath : undefined;
|
|
26
|
+
exec(`${command} check "${document.uri.fsPath}"`, { cwd, timeout: 30000 }, (_error, _stdout, stderr) => {
|
|
27
|
+
const items = [];
|
|
28
|
+
// Errors look like: QA-LANG-001 [category] /path/file.mcpr:12 Message text
|
|
29
|
+
const pattern = /^([A-Z]+-[A-Z]+-\d+)\s+\[[^\]]+\]\s+(.+?):(\d+)\s+(.*)$/gm;
|
|
30
|
+
let match;
|
|
31
|
+
while ((match = pattern.exec(stderr)) !== null) {
|
|
32
|
+
const [, code, file, lineText, message] = match;
|
|
33
|
+
if (!document.uri.fsPath.endsWith(file) && !file.endsWith(document.uri.fsPath)) {
|
|
34
|
+
if (!sameFile(file, document.uri.fsPath)) continue;
|
|
35
|
+
}
|
|
36
|
+
const line = Math.max(0, Number(lineText) - 1);
|
|
37
|
+
const range = document.lineAt(Math.min(line, document.lineCount - 1)).range;
|
|
38
|
+
const item = new vscode.Diagnostic(range, `${code} ${message}`, vscode.DiagnosticSeverity.Error);
|
|
39
|
+
item.source = "mcprigor";
|
|
40
|
+
items.push(item);
|
|
41
|
+
}
|
|
42
|
+
// Fallback: a failure with no parseable location goes on line 1
|
|
43
|
+
if (!items.length && stderr.includes("MCP Rigor could not continue")) {
|
|
44
|
+
const firstLine = stderr.split("\n").find((entry) => /^[A-Z]+-[A-Z]+-\d+/.test(entry.trim()));
|
|
45
|
+
if (firstLine) {
|
|
46
|
+
const item = new vscode.Diagnostic(document.lineAt(0).range, firstLine.trim(), vscode.DiagnosticSeverity.Error);
|
|
47
|
+
item.source = "mcprigor";
|
|
48
|
+
items.push(item);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
diagnostics.set(document.uri, items);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function sameFile(a, b) {
|
|
56
|
+
try { return require("node:fs").realpathSync(a) === require("node:fs").realpathSync(b); } catch { return false; }
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function deactivate() { if (diagnostics) diagnostics.dispose(); }
|
|
60
|
+
|
|
61
|
+
module.exports = { activate, deactivate };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"comments": { "lineComment": "#" },
|
|
3
|
+
"brackets": [["{", "}"], ["[", "]"]],
|
|
4
|
+
"autoClosingPairs": [
|
|
5
|
+
{ "open": "\"", "close": "\"", "notIn": ["string"] },
|
|
6
|
+
{ "open": "'", "close": "'", "notIn": ["string"] },
|
|
7
|
+
{ "open": "{", "close": "}" },
|
|
8
|
+
{ "open": "[", "close": "]" }
|
|
9
|
+
],
|
|
10
|
+
"surroundingPairs": [["\"", "\""], ["'", "'"], ["{", "}"], ["[", "]"]]
|
|
11
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mcprigor",
|
|
3
|
+
"displayName": "MCP Rigor",
|
|
4
|
+
"description": "Syntax highlighting and inline validation for MCP Rigor (.mcpr) natural-language MCP test suites.",
|
|
5
|
+
"version": "1.3.0",
|
|
6
|
+
"publisher": "fusionone",
|
|
7
|
+
"license": "Apache-2.0",
|
|
8
|
+
"repository": { "type": "git", "url": "https://github.com/FusionOnePlatform/mcprigor" },
|
|
9
|
+
"engines": { "vscode": "^1.85.0" },
|
|
10
|
+
"categories": ["Programming Languages", "Testing", "Linters"],
|
|
11
|
+
"keywords": ["mcp", "model context protocol", "testing", "qa"],
|
|
12
|
+
"main": "./extension.js",
|
|
13
|
+
"activationEvents": ["onLanguage:mcpr"],
|
|
14
|
+
"contributes": {
|
|
15
|
+
"languages": [{
|
|
16
|
+
"id": "mcpr",
|
|
17
|
+
"aliases": ["MCP Rigor", "mcpr"],
|
|
18
|
+
"extensions": [".mcpr"],
|
|
19
|
+
"configuration": "./language-configuration.json"
|
|
20
|
+
}],
|
|
21
|
+
"grammars": [{
|
|
22
|
+
"language": "mcpr",
|
|
23
|
+
"scopeName": "source.mcpr",
|
|
24
|
+
"path": "./syntaxes/mcpr.tmLanguage.json"
|
|
25
|
+
}],
|
|
26
|
+
"configuration": {
|
|
27
|
+
"title": "MCP Rigor",
|
|
28
|
+
"properties": {
|
|
29
|
+
"mcprigor.validateOnSave": { "type": "boolean", "default": true, "description": "Run 'mcprigor check' when a .mcpr file is saved and surface diagnostics inline." },
|
|
30
|
+
"mcprigor.command": { "type": "string", "default": "npx mcprigor", "description": "Command used to invoke the MCP Rigor CLI." }
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
|
|
3
|
+
"name": "MCP Rigor Language",
|
|
4
|
+
"scopeName": "source.mcpr",
|
|
5
|
+
"patterns": [
|
|
6
|
+
{
|
|
7
|
+
"match": "^\\s*#.*$",
|
|
8
|
+
"name": "comment.line.number-sign.mcpr"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"match": "^MCP Test 1$",
|
|
12
|
+
"name": "keyword.control.version.mcpr"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"match": "^\\s*(Suite|Server|Server options|MCP URL|Compare target|Target options for|Default timeout|Redact|Snapshots|Ignore snapshot paths|Client behavior|Import flows from|Flow|Inputs|Outputs|Test|Scenario|Id|Depends on|Require|Require protocol|Variables|Skip|Setup|Steps|Cleanup|Data source):?",
|
|
16
|
+
"name": "keyword.control.mcpr"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"match": "^\\s*(Call tool|When the server asks for input|When the server requests sampling|Read resource|Get prompt|Send|Expect|Save|Export|Set|Use flow|For each row|Wait up to|Wait for notification|Subscribe to resource|Unsubscribe from resource|Set log level|List all|Get task|List tasks|Cancel task|From CSV|From JSON|From YAML|From Excel|From REST|Column|Derive|Keep rows where|Sample|Cache this source)\\b",
|
|
20
|
+
"name": "keyword.other.mcpr"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"begin": "\"",
|
|
24
|
+
"end": "\"",
|
|
25
|
+
"name": "string.quoted.double.mcpr"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"begin": "'",
|
|
29
|
+
"end": "'",
|
|
30
|
+
"name": "string.quoted.single.mcpr"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"match": "\\$\\{[^}]+\\}",
|
|
34
|
+
"name": "variable.other.mcpr"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"match": "\\b(true|false|null)\\b",
|
|
38
|
+
"name": "constant.language.mcpr"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"match": "\\b-?[0-9]+(?:\\.[0-9]+)?\\b",
|
|
42
|
+
"name": "constant.numeric.mcpr"
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
}
|