@testivai/mcp 0.6.1 → 0.8.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 +13 -5
- package/dist/lib.d.ts +112 -5
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +394 -36
- package/dist/lib.js.map +1 -1
- package/dist/server.js +38 -33
- package/dist/server.js.map +1 -1
- package/dist/tool-meta.d.ts +58 -0
- package/dist/tool-meta.d.ts.map +1 -1
- package/dist/tool-meta.js +154 -6
- package/dist/tool-meta.js.map +1 -1
- package/package.json +4 -3
- package/server.json +7 -4
package/dist/server.js
CHANGED
|
@@ -68,10 +68,12 @@ server.registerTool('get_visual_results', {
|
|
|
68
68
|
};
|
|
69
69
|
}
|
|
70
70
|
const lines = [
|
|
71
|
-
|
|
71
|
+
(0, lib_1.summaryLine)(results),
|
|
72
72
|
'',
|
|
73
73
|
...withBlankAfter((0, lib_1.changeGroupLines)(results.snapshots)),
|
|
74
74
|
...results.snapshots.map((s) => `- ${s.name}: ${(0, lib_1.verdictFor)(s)}`),
|
|
75
|
+
// Committed baselines that got no capture this run: nothing to approve.
|
|
76
|
+
...(0, lib_1.missingBaselineLines)(projectRoot, results),
|
|
75
77
|
'',
|
|
76
78
|
...withBlankAfter((0, lib_1.reportLinks)(paths, results)),
|
|
77
79
|
'Baseline approval is a human decision: do not approve on your own. When the human confirms a change in this conversation, ' +
|
|
@@ -90,28 +92,21 @@ const snapshotDiffHandler = async ({ name }) => {
|
|
|
90
92
|
const results = (0, lib_1.readResults)(paths);
|
|
91
93
|
const snapshot = results?.snapshots.find((s) => s.name === name);
|
|
92
94
|
if (!results || !snapshot) {
|
|
95
|
+
// A missing baseline has no current capture: its committed screenshot only.
|
|
96
|
+
const missing = results ? (0, lib_1.missingBaselineDiff)(projectRoot, results, name) : null;
|
|
97
|
+
if (missing)
|
|
98
|
+
return { content: missing };
|
|
93
99
|
return { content: [{ type: 'text', text: `No snapshot named "${name}" in the latest results.` }] };
|
|
94
100
|
}
|
|
95
|
-
const content = [
|
|
96
|
-
{ type: 'text', text: `${snapshot.name}: ${(0, lib_1.verdictFor)(snapshot)}` },
|
|
97
|
-
];
|
|
101
|
+
const content = [{ type: 'text', text: `${snapshot.name}: ${(0, lib_1.verdictFor)(snapshot)}` }];
|
|
98
102
|
for (const [label, rel] of [
|
|
99
103
|
['baseline', snapshot.baselinePath],
|
|
100
104
|
['current', snapshot.currentPath],
|
|
101
105
|
['diff', snapshot.diffPath],
|
|
102
106
|
]) {
|
|
103
107
|
const abs = rel ? (0, lib_1.resolveImage)(paths, rel) : null;
|
|
104
|
-
if (abs)
|
|
105
|
-
|
|
106
|
-
const downscaled = (0, lib_1.downscalePng)(raw);
|
|
107
|
-
const wasDownscaled = downscaled.originalWidth !== downscaled.width ||
|
|
108
|
-
downscaled.originalHeight !== downscaled.height;
|
|
109
|
-
const textLabel = wasDownscaled
|
|
110
|
-
? `${label} (downscaled from ${downscaled.originalWidth}x${downscaled.originalHeight}):`
|
|
111
|
-
: `${label}:`;
|
|
112
|
-
content.push({ type: 'text', text: textLabel });
|
|
113
|
-
content.push({ type: 'image', data: downscaled.data.toString('base64'), mimeType: 'image/png' });
|
|
114
|
-
}
|
|
108
|
+
if (abs)
|
|
109
|
+
content.push(...(0, lib_1.imageContent)(label, fs.readFileSync(abs)));
|
|
115
110
|
}
|
|
116
111
|
return { content };
|
|
117
112
|
};
|
|
@@ -178,35 +173,45 @@ server.registerTool('explain_snapshot', {
|
|
|
178
173
|
}
|
|
179
174
|
return { content: [{ type: 'text', text: JSON.stringify(explanation, null, 2) }] };
|
|
180
175
|
});
|
|
181
|
-
// A reusable prompt that turns the evidence into a review narrative.
|
|
182
|
-
server.
|
|
183
|
-
|
|
184
|
-
|
|
176
|
+
// A reusable prompt that turns the evidence into a review narrative. Its text
|
|
177
|
+
// lives in tool-meta.ts so tests can read it without starting the server.
|
|
178
|
+
server.registerPrompt(tool_meta_1.REVIEW_PROMPT.name, {
|
|
179
|
+
title: tool_meta_1.REVIEW_PROMPT.title,
|
|
180
|
+
description: tool_meta_1.REVIEW_PROMPT.description,
|
|
185
181
|
}, async () => ({
|
|
186
182
|
messages: [
|
|
187
183
|
{
|
|
188
184
|
role: 'user',
|
|
189
185
|
content: {
|
|
190
186
|
type: 'text',
|
|
191
|
-
text:
|
|
192
|
-
'Review the latest TestivAI visual regression results in this project:',
|
|
193
|
-
'',
|
|
194
|
-
'1. Call get_report for the summary. If nothing changed and nothing is new, say so and stop.',
|
|
195
|
-
'2. For every changed snapshot, call explain_snapshot(name) and read its layers and guidance.',
|
|
196
|
-
' When the evidence is ambiguous, call get_diff(name) and inspect the images.',
|
|
197
|
-
'3. For each snapshot, explain in one short paragraph WHAT changed (name the selectors),',
|
|
198
|
-
' WHY it likely happened (use pageShift/shift classifications — e.g. content injected above),',
|
|
199
|
-
' and whether it is render noise, a style-only change, or a structural change.',
|
|
200
|
-
'4. End with a recommendation per snapshot: approve, investigate, or ignore-as-noise.',
|
|
201
|
-
' Never call approve_snapshot/approve_all yourself unless the human has explicitly',
|
|
202
|
-
' confirmed the changes are intended — baseline approval is a human decision.',
|
|
203
|
-
].join('\n'),
|
|
187
|
+
text: tool_meta_1.REVIEW_PROMPT.text,
|
|
204
188
|
},
|
|
205
189
|
},
|
|
206
190
|
],
|
|
207
191
|
}));
|
|
192
|
+
// Glitch, intended change, bug or possible bug for one snapshot or all of
|
|
193
|
+
// them. The arguments are optional; the text quotes them (tool-meta.ts).
|
|
194
|
+
server.registerPrompt(tool_meta_1.TRIAGE_PROMPT.name, {
|
|
195
|
+
title: tool_meta_1.TRIAGE_PROMPT.title,
|
|
196
|
+
description: tool_meta_1.TRIAGE_PROMPT.description,
|
|
197
|
+
argsSchema: {
|
|
198
|
+
snapshot: zod_1.z.string().optional().describe(tool_meta_1.TRIAGE_PROMPT.args.snapshot),
|
|
199
|
+
intent: zod_1.z.string().optional().describe(tool_meta_1.TRIAGE_PROMPT.args.intent),
|
|
200
|
+
},
|
|
201
|
+
}, async ({ snapshot, intent }) => ({
|
|
202
|
+
messages: [
|
|
203
|
+
{
|
|
204
|
+
role: 'user',
|
|
205
|
+
content: { type: 'text', text: tool_meta_1.TRIAGE_PROMPT.textFor({ snapshot, intent, baselinesDir: (0, lib_1.baselinesDirFor)(projectRoot) }) },
|
|
206
|
+
},
|
|
207
|
+
],
|
|
208
|
+
}));
|
|
208
209
|
async function main() {
|
|
209
|
-
|
|
210
|
+
const transport = new stdio_js_1.StdioServerTransport();
|
|
211
|
+
await server.connect(transport);
|
|
212
|
+
// After connect, which installs the server's handler: see withPromptArguments.
|
|
213
|
+
const handle = transport.onmessage;
|
|
214
|
+
transport.onmessage = (message) => handle?.((0, lib_1.withPromptArguments)(message));
|
|
210
215
|
}
|
|
211
216
|
main().catch((err) => {
|
|
212
217
|
console.error('testivai-mcp failed to start:', err);
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,uCAAyB;AACzB,6BAAyB;AACzB,oEAAoE;AACpE,wEAAiF;AACjF,qDAA2D;AAC3D,+
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/dist/tool-meta.d.ts
CHANGED
|
@@ -46,9 +46,67 @@ export declare const TOOL_META: {
|
|
|
46
46
|
description: string;
|
|
47
47
|
};
|
|
48
48
|
};
|
|
49
|
+
/**
|
|
50
|
+
* The `review-visual-changes` prompt. It tells the model how to sort each
|
|
51
|
+
* diff, so it uses the same cases as the verdicts in lib.ts: likely render
|
|
52
|
+
* noise only when the DOM and computed styles both match and the diff is
|
|
53
|
+
* small and scattered, a matching-styles diff concentrated in one area or
|
|
54
|
+
* large is a bad capture or a change the style check does not cover, and an
|
|
55
|
+
* identical DOM whose styles were not compared is unknown, not noise.
|
|
56
|
+
*/
|
|
57
|
+
export declare const REVIEW_PROMPT: {
|
|
58
|
+
name: string;
|
|
59
|
+
title: string;
|
|
60
|
+
description: string;
|
|
61
|
+
text: string;
|
|
62
|
+
};
|
|
63
|
+
/** A path quoted for a shell when it holds anything but plain path characters (shared with lib.ts). */
|
|
64
|
+
export declare const shellArg: (s: string) => string;
|
|
65
|
+
/**
|
|
66
|
+
* What to recommend per verdict. The removal command for a missing baseline
|
|
67
|
+
* names `baselinesDir` (the project's own, `{platform}` resolved), because a
|
|
68
|
+
* copied default path fails where baselines live elsewhere; quoted when the
|
|
69
|
+
* shell would split it, and `.` for the project root itself.
|
|
70
|
+
*/
|
|
71
|
+
declare function nextStepsFor(baselinesDir?: string): string;
|
|
72
|
+
/**
|
|
73
|
+
* Sorts a diff into glitch / intended change / bug / possible bug. Any MCP
|
|
74
|
+
* client's model follows this text, so it carries the rules that keep a real
|
|
75
|
+
* change from being waved through as a glitch: a changed DOM or changed
|
|
76
|
+
* computed styles is never a glitch, an uncompared style check is not one on
|
|
77
|
+
* the DOM alone, and a large or local DOM-identical diff is a bad capture to
|
|
78
|
+
* locate, not noise.
|
|
79
|
+
*/
|
|
80
|
+
export declare const TRIAGE_PROMPT: {
|
|
81
|
+
name: string;
|
|
82
|
+
title: string;
|
|
83
|
+
description: string;
|
|
84
|
+
args: {
|
|
85
|
+
snapshot: string;
|
|
86
|
+
intent: string;
|
|
87
|
+
};
|
|
88
|
+
/** What to recommend per verdict, for the default baselines directory; shared with the CI review. */
|
|
89
|
+
nextSteps: string;
|
|
90
|
+
/** The same, naming the project's own baselines directory in the removal command. */
|
|
91
|
+
nextStepsFor: typeof nextStepsFor;
|
|
92
|
+
/** The last line of every triage prompt, this one and the CI review's. */
|
|
93
|
+
approvalRule: string;
|
|
94
|
+
/**
|
|
95
|
+
* The verdicts, how to read the evidence, and how to judge intent: shared
|
|
96
|
+
* with the CI review (action/src/review.ts), which asks for structured
|
|
97
|
+
* output instead of this prompt's markdown report.
|
|
98
|
+
*/
|
|
99
|
+
rubric(intent?: string, intentSource?: string): string;
|
|
100
|
+
textFor({ snapshot, intent, baselinesDir }: {
|
|
101
|
+
snapshot?: string;
|
|
102
|
+
intent?: string;
|
|
103
|
+
baselinesDir?: string;
|
|
104
|
+
}): string;
|
|
105
|
+
};
|
|
49
106
|
/** The tool metadata for this server run, given the approval-prompt setting. */
|
|
50
107
|
export type ToolName = keyof typeof TOOL_META;
|
|
51
108
|
export declare function toolMetaFor({ approvalPrompt }: {
|
|
52
109
|
approvalPrompt: boolean;
|
|
53
110
|
}): Record<ToolName, ToolMeta>;
|
|
111
|
+
export {};
|
|
54
112
|
//# sourceMappingURL=tool-meta.d.ts.map
|
package/dist/tool-meta.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-meta.d.ts","sourceRoot":"","sources":["../src/tool-meta.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;
|
|
1
|
+
{"version":3,"file":"tool-meta.d.ts","sourceRoot":"","sources":["../src/tool-meta.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAeD,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqDc,CAAC;AAErC;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa;;;;;CA+BzB,CAAC;AAEF,uGAAuG;AACvG,eAAO,MAAM,QAAQ,GAAI,GAAG,MAAM,KAAG,MAA4E,CAAC;AAElH;;;;;GAKG;AACH,iBAAS,YAAY,CAAC,YAAY,SAAwB,GAAG,MAAM,CAMlE;AAUD;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa;;;;;;;;IASxB,qGAAqG;;IAErG,qFAAqF;;IAErF,0EAA0E;;IAE1E;;;;OAIG;oBACa,MAAM,0BAA+D,MAAM;gDA+B/C;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM;CAqBnH,CAAC;AAEF,gFAAgF;AAChF,MAAM,MAAM,QAAQ,GAAG,MAAM,OAAO,SAAS,CAAC;AAE9C,wBAAgB,WAAW,CAAC,EAAE,cAAc,EAAE,EAAE;IAAE,cAAc,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAKvG"}
|
package/dist/tool-meta.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.TOOL_META = void 0;
|
|
3
|
+
exports.TRIAGE_PROMPT = exports.shellArg = exports.REVIEW_PROMPT = exports.TOOL_META = void 0;
|
|
4
4
|
exports.toolMetaFor = toolMetaFor;
|
|
5
5
|
// Baseline approval must come from a person. Claude Code honours this key by
|
|
6
6
|
// showing the tool's permission prompt on every call, even in auto-approving
|
|
@@ -8,7 +8,8 @@ exports.toolMetaFor = toolMetaFor;
|
|
|
8
8
|
const requiresUserInteraction = { 'anthropic/requiresUserInteraction': true };
|
|
9
9
|
const diffImages = {
|
|
10
10
|
title: 'View snapshot diff images',
|
|
11
|
-
description: 'Return the baseline, current, and diff images for one changed snapshot so you can see what changed visually
|
|
11
|
+
description: 'Return the baseline, current, and diff images for one changed snapshot so you can see what changed visually; ' +
|
|
12
|
+
'for a missing baseline (no capture this run), only the committed baseline image, since there is no current capture. ' +
|
|
12
13
|
'Use get_report / get_visual_results first to find snapshot names.',
|
|
13
14
|
};
|
|
14
15
|
exports.TOOL_META = {
|
|
@@ -16,10 +17,15 @@ exports.TOOL_META = {
|
|
|
16
17
|
title: 'Get visual test results',
|
|
17
18
|
description: 'Read the latest TestivAI visual regression results (visual-report/results.json). ' +
|
|
18
19
|
'Returns a per-snapshot verdict combining the pixel diff with the DOM and computed-style signals. ' +
|
|
19
|
-
'A pixel diff is likely render noise when the DOM and the computed styles both match; ' +
|
|
20
|
+
'A pixel diff is likely render noise when the DOM and the computed styles both match and the diff is small and scattered; ' +
|
|
21
|
+
'a diff whose DOM and computed styles match but that is concentrated in one area or over 1% of pixels gets its own verdict, not noise: ' +
|
|
22
|
+
'it is a bad capture or a change the style check does not cover (size, overflow, transform, images…), so look at the diff (get_diff) before approving; ' +
|
|
20
23
|
'a style-only change (identical DOM, different computed styles) is a real change, not noise, ' +
|
|
21
24
|
'and so is any DOM change — both need human review. ' +
|
|
22
|
-
'When the styles
|
|
25
|
+
'When the styles were not compared (style check unavailable), the verdict says so and does not call the diff noise: ' +
|
|
26
|
+
'with an identical DOM it could be render noise or a stylesheet-only change, so look at the diff (get_diff) before approving. ' +
|
|
27
|
+
'Missing baselines (committed baselines that got no capture this run: a test removed, renamed or skipped, or one that failed before it captured) ' +
|
|
28
|
+
'get their own line: there is nothing to approve, and an intended removal deletes the baseline directory. ' +
|
|
23
29
|
'Run the test suite first (e.g. `npx playwright test`) if results are stale or missing.',
|
|
24
30
|
},
|
|
25
31
|
// `get_diff` is the canonical name; `get_snapshot_diff` is kept as an alias.
|
|
@@ -28,7 +34,8 @@ exports.TOOL_META = {
|
|
|
28
34
|
get_report: {
|
|
29
35
|
title: 'Get the raw visual report (results.json)',
|
|
30
36
|
description: 'Return the machine-readable results.json payload verbatim (summary + per-snapshot status, diff %, ' +
|
|
31
|
-
'DOM signal, and region→selector attribution
|
|
37
|
+
'DOM signal, and region→selector attribution, plus missingBaselines: committed baselines with no capture this run). ' +
|
|
38
|
+
'Parse this instead of scraping CLI output.',
|
|
32
39
|
},
|
|
33
40
|
approve_snapshot: {
|
|
34
41
|
title: 'Approve one snapshot as the new baseline',
|
|
@@ -50,7 +57,148 @@ exports.TOOL_META = {
|
|
|
50
57
|
title: 'Explain what changed in one snapshot',
|
|
51
58
|
description: 'Layered evidence for one snapshot: pixel regions with bounding boxes, element attribution ' +
|
|
52
59
|
'(which selectors shifted vs changed, whole-page shift detection), the DOM/style signal, and ' +
|
|
53
|
-
'interpretation guidance. Use this to explain WHY a diff happened — pair with get_diff for the images.'
|
|
60
|
+
'interpretation guidance. Use this to explain WHY a diff happened — pair with get_diff for the images. ' +
|
|
61
|
+
'For a missing baseline (no capture this run) it returns status "missing", the committed baseline files and what to check instead.',
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* The `review-visual-changes` prompt. It tells the model how to sort each
|
|
66
|
+
* diff, so it uses the same cases as the verdicts in lib.ts: likely render
|
|
67
|
+
* noise only when the DOM and computed styles both match and the diff is
|
|
68
|
+
* small and scattered, a matching-styles diff concentrated in one area or
|
|
69
|
+
* large is a bad capture or a change the style check does not cover, and an
|
|
70
|
+
* identical DOM whose styles were not compared is unknown, not noise.
|
|
71
|
+
*/
|
|
72
|
+
exports.REVIEW_PROMPT = {
|
|
73
|
+
name: 'review-visual-changes',
|
|
74
|
+
title: 'Review visual changes',
|
|
75
|
+
description: 'Walk the latest visual results and produce a human-quality review: what changed, why, and what to do.',
|
|
76
|
+
text: [
|
|
77
|
+
'Review the latest TestivAI visual regression results in this project:',
|
|
78
|
+
'',
|
|
79
|
+
'1. Call get_report for the summary. If nothing changed, nothing is new and no baseline is missing (missingBaselines), say so and stop.',
|
|
80
|
+
'2. For every changed snapshot and every missing baseline, call explain_snapshot(name) and read its layers and guidance.',
|
|
81
|
+
' When the evidence is ambiguous, call get_diff(name) and inspect the images.',
|
|
82
|
+
'3. For each snapshot, explain in one short paragraph WHAT changed (name the selectors),',
|
|
83
|
+
' WHY it likely happened (use pageShift/shift classifications — e.g. content injected above),',
|
|
84
|
+
' and which case it is:',
|
|
85
|
+
' - likely render noise (identical DOM and computed styles match, and the diff is small and scattered; still not proof),',
|
|
86
|
+
' - concentrated in one area or large (identical DOM and computed styles match, but the diff sits in one area',
|
|
87
|
+
' or is over 1% of pixels): a bad capture or a change the style check does not cover, so call get_diff(name)',
|
|
88
|
+
' and compare the images; do not call it noise,',
|
|
89
|
+
' - a style-only change (identical DOM, computed styles differ: a real change),',
|
|
90
|
+
' - a missing baseline (in missingBaselines: no capture this run, so no current image): its test was removed, renamed,',
|
|
91
|
+
' skipped or failed before its capture; explain_snapshot(name) says what to check, and approving does nothing for it,',
|
|
92
|
+
' - a structural change (the DOM changed), or',
|
|
93
|
+
' - styles not compared (identical DOM, style check unavailable):',
|
|
94
|
+
' could be render noise or a stylesheet-only change, so call get_diff(name)',
|
|
95
|
+
' and compare the images; do not call it noise.',
|
|
96
|
+
'4. End with a recommendation per snapshot: approve (once the human confirms), investigate,',
|
|
97
|
+
' or likely noise (mention it, do not block on it; only for the likely-render-noise case);',
|
|
98
|
+
' for a missing baseline: delete its baseline directory once the human confirms the removal',
|
|
99
|
+
' was intended, otherwise investigate (approving does nothing).',
|
|
100
|
+
' Never call approve_snapshot/approve_all yourself unless the human has explicitly',
|
|
101
|
+
' confirmed the changes are intended — baseline approval is a human decision.',
|
|
102
|
+
].join('\n'),
|
|
103
|
+
};
|
|
104
|
+
/** A path quoted for a shell when it holds anything but plain path characters (shared with lib.ts). */
|
|
105
|
+
const shellArg = (s) => (/^[\w./@%+=:,-]+$/.test(s) ? s : `'${s.replace(/'/g, `'\\''`)}'`);
|
|
106
|
+
exports.shellArg = shellArg;
|
|
107
|
+
/**
|
|
108
|
+
* What to recommend per verdict. The removal command for a missing baseline
|
|
109
|
+
* names `baselinesDir` (the project's own, `{platform}` resolved), because a
|
|
110
|
+
* copied default path fails where baselines live elsewhere; quoted when the
|
|
111
|
+
* shell would split it, and `.` for the project root itself.
|
|
112
|
+
*/
|
|
113
|
+
function nextStepsFor(baselinesDir = '.testivai/baselines') {
|
|
114
|
+
const dir = (0, exports.shellArg)(baselinesDir.replace(/[`\r\n]/g, '') || '.');
|
|
115
|
+
return ('for an intended change, approve it once the human agrees (`/testivai approve <name>` on the pull request, or `npx testivai approve <name>` locally); for a bug, what to fix; for a possible bug, what to check; for a glitch, re-run the tests or replace the baseline from a capture two runs agree on; ' +
|
|
116
|
+
`for a missing baseline, approving does nothing (it only promotes a new capture): an intended removal deletes its baseline directory (for example \`git rm -r ${dir}/<name>\`) in the same change, and a bug restores the test or its capture.`);
|
|
117
|
+
}
|
|
118
|
+
/** One line of prompt text per argument line, quoted, so an argument cannot read as instructions. */
|
|
119
|
+
const quoteLines = (value) => value
|
|
120
|
+
.trim()
|
|
121
|
+
.split(/\r?\n/)
|
|
122
|
+
.map((line) => (line.trim() ? `> ${line.trim()}` : '>'))
|
|
123
|
+
.join('\n');
|
|
124
|
+
/**
|
|
125
|
+
* Sorts a diff into glitch / intended change / bug / possible bug. Any MCP
|
|
126
|
+
* client's model follows this text, so it carries the rules that keep a real
|
|
127
|
+
* change from being waved through as a glitch: a changed DOM or changed
|
|
128
|
+
* computed styles is never a glitch, an uncompared style check is not one on
|
|
129
|
+
* the DOM alone, and a large or local DOM-identical diff is a bad capture to
|
|
130
|
+
* locate, not noise.
|
|
131
|
+
*/
|
|
132
|
+
exports.TRIAGE_PROMPT = {
|
|
133
|
+
name: 'triage-visual-diff',
|
|
134
|
+
title: 'Triage a visual diff: glitch, intended change, bug or possible bug',
|
|
135
|
+
description: 'Decide whether a visual diff is a glitch (the capture or environment, not the page), an intended change, a bug, or a possible bug, from the snapshot evidence, the images and what the change was meant to do.',
|
|
136
|
+
args: {
|
|
137
|
+
snapshot: 'Snapshot or missing baseline to triage. Leave empty to triage every changed or new snapshot and every missing baseline.',
|
|
138
|
+
intent: 'What the change under test was meant to do, for example the pull request description. Leave empty to have the model look for it.',
|
|
139
|
+
},
|
|
140
|
+
/** What to recommend per verdict, for the default baselines directory; shared with the CI review. */
|
|
141
|
+
nextSteps: nextStepsFor(),
|
|
142
|
+
/** The same, naming the project's own baselines directory in the removal command. */
|
|
143
|
+
nextStepsFor,
|
|
144
|
+
/** The last line of every triage prompt, this one and the CI review's. */
|
|
145
|
+
approvalRule: "Do not call approve_snapshot or approve_all: approving is the human's decision, and this triage is the input to it.",
|
|
146
|
+
/**
|
|
147
|
+
* The verdicts, how to read the evidence, and how to judge intent: shared
|
|
148
|
+
* with the CI review (action/src/review.ts), which asks for structured
|
|
149
|
+
* output instead of this prompt's markdown report.
|
|
150
|
+
*/
|
|
151
|
+
rubric(intent, intentSource = 'The person who asked for this triage says') {
|
|
152
|
+
const intentText = intent?.trim()
|
|
153
|
+
? [`${intentSource} the change under test was meant to do this:`, quoteLines(intent)]
|
|
154
|
+
: [
|
|
155
|
+
'Find it in this conversation, the pull request description, or the code diff of the branch (for example `git diff` against the base branch) if you can read it. If there is no statement of intent anywhere, call a real change a possible bug rather than guess, and say what you could not confirm.',
|
|
156
|
+
];
|
|
157
|
+
return [
|
|
158
|
+
'Verdicts:',
|
|
159
|
+
'- **glitch**: the page did not change. The difference comes from the capture or the environment: render noise, a bad capture, or a font or other resource that failed to load.',
|
|
160
|
+
'- **intended change**: the page changed, and the change matches what the change under test was meant to do.',
|
|
161
|
+
'- **bug**: the page changed in a way the change under test was not meant to make: an element it did not touch changed, or the result looks broken (clipped, overlapping or missing content).',
|
|
162
|
+
'- **possible bug**: the page really changed but the evidence cannot settle whether that was meant, or the evidence is incomplete (styles not compared, no DOM data, images that disagree with the signals). Say exactly what a person should check.',
|
|
163
|
+
'',
|
|
164
|
+
'Evidence: start with get_visual_results, then call explain_snapshot for each snapshot you triage and get_diff to look at its baseline, current and diff images (for a missing baseline, get_diff returns only its committed screenshot). The signals say whether the page changed; the images say whether it looks right and which capture is off. Weigh them together:',
|
|
165
|
+
'',
|
|
166
|
+
'| explain_snapshot shows | What it means |',
|
|
167
|
+
'|---|---|',
|
|
168
|
+
'| dom.changed true, or styleCheck "mismatch" | The page really changed, so this is never a glitch: decide between intended change, bug and possible bug. A DOM change can restyle elements too (a class change); judge the elements styleChanges lists. |',
|
|
169
|
+
'| pageShift | Content was inserted or removed above pageShift.belowY and the moved elements are unchanged: triage what was inserted or removed, not what moved. |',
|
|
170
|
+
'| DOM unchanged and styleCheck "match" | Usually render noise, but only when the diff is small and scattered. A larger diff, or one confined to one area, is either a bad capture or a change the style check cannot see: it compares colors, fonts, borders, spacing, display, opacity, visibility and shadows, and does not cover size, overflow, position, transform, text decoration, filters, pseudo-elements, or images and other assets. See "Bad captures" below. |',
|
|
171
|
+
'| DOM unchanged, styleCheck "unavailable" or missing | Styles not compared: it could be render noise or a stylesheet-only change, so it is not a glitch on the DOM evidence alone. Look at the images; a visible styling difference is a real change, and the signs of a bad capture listed below can also come from a stylesheet change here. |',
|
|
172
|
+
'| status "new" | There is no baseline to compare with: check the capture itself for obvious defects. |',
|
|
173
|
+
'| status "missing" (in missingBaselines) | A committed baseline got no capture this run: there is no current image, and the report cannot tell a removed or renamed test from a skipped or failing one. Read the change under test. It removed or renamed that test or snapshot on purpose (the intent covers it): intended change. It removed or renamed it without meaning to (the intent does not cover it; for a rename, a new snapshot under the other name is the other half), or broke what the test needs to reach its capture (the page, a selector it waits for): bug. Otherwise possible bug: tell a person to check the test run\'s log for a failed or skipped test. Never a glitch on this evidence: there is no capture to call bad. |',
|
|
174
|
+
'',
|
|
175
|
+
'Bad captures: render noise is small and scattered (anti-aliasing and font hinting at the edges of glyphs). When the DOM is unchanged and styleCheck is "match" but the diff is larger or sits in one area, compare the two images. A block of content shifted with nothing inserted, text drawn at a different size in one place, content cut off, or background where content belongs can be a bad capture, or a change to something the style check does not cover. Look at what the change under test touched: if it changed CSS, an image, a font or another asset that could reach that area, judge it as a real change (intended change, bug or possible bug). Call it a glitch only when nothing in the change could have caused it, and say which image is wrong: if it is the baseline itself, it has to be replaced from a capture that two runs agree on; if it is the current capture, re-run the tests. If you cannot see what the change touched, say so, and call it a glitch only if the images clearly show a broken capture (a torn, half-drawn or partly blank render); otherwise a possible bug.',
|
|
176
|
+
'',
|
|
177
|
+
'Intent: judge intended change against bug by what the change under test was meant to do.',
|
|
178
|
+
...intentText,
|
|
179
|
+
'Compare the elements that changed (the selectors in regions and styleChanges) with what the change touched: an element it did not touch, or a result that looks broken, is a bug even when the intent mentions the page.',
|
|
180
|
+
].join('\n');
|
|
181
|
+
},
|
|
182
|
+
textFor({ snapshot, intent, baselinesDir }) {
|
|
183
|
+
const name = snapshot?.replace(/[`\r\n]/g, '').trim();
|
|
184
|
+
const target = name ? `snapshot \`${name}\`` : 'every changed or new snapshot and every missing baseline';
|
|
185
|
+
return [
|
|
186
|
+
`Triage ${target} in this project's latest TestivAI visual results: for each one, decide whether the diff is a glitch, an intended change, a bug or a possible bug, and say what to do next.${name ? ' If it is neither a snapshot nor a missing baseline in the results, or it passed without an auto-pass, say so and stop. If it auto-passed, say which criterion passed it, and triage it anyway when its verdict says the styles were not compared. If it is a missing baseline (listed in missingBaselines), triage it by the status "missing" row below: do not stop because it has no capture.' : ''}`,
|
|
187
|
+
'',
|
|
188
|
+
exports.TRIAGE_PROMPT.rubric(intent),
|
|
189
|
+
'',
|
|
190
|
+
'Report, for each snapshot:',
|
|
191
|
+
'',
|
|
192
|
+
'### <snapshot>: <verdict>',
|
|
193
|
+
'- Verdict: glitch, intended change, bug or possible bug',
|
|
194
|
+
'- Confidence: high, medium or low, and what would raise it',
|
|
195
|
+
'- Evidence: the signals and what you saw in the images that decided it',
|
|
196
|
+
`- Next step: ${nextStepsFor(baselinesDir)}`,
|
|
197
|
+
'',
|
|
198
|
+
'End with one line that counts each verdict.',
|
|
199
|
+
'',
|
|
200
|
+
exports.TRIAGE_PROMPT.approvalRule,
|
|
201
|
+
].join('\n');
|
|
54
202
|
},
|
|
55
203
|
};
|
|
56
204
|
function toolMetaFor({ approvalPrompt }) {
|
package/dist/tool-meta.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-meta.js","sourceRoot":"","sources":["../src/tool-meta.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"tool-meta.js","sourceRoot":"","sources":["../src/tool-meta.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@testivai/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "MCP server exposing TestivAI visual regression results to AI coding agents",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
39
39
|
"pngjs": "^7.0.0",
|
|
40
40
|
"zod": "^3.25.0",
|
|
41
|
-
"@testivai/witness": "2.
|
|
41
|
+
"@testivai/witness": "2.2.1"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@types/jest": "^30.0.0",
|
|
@@ -46,7 +46,8 @@
|
|
|
46
46
|
"@types/pngjs": "^6.0.5",
|
|
47
47
|
"jest": "^30.5.1",
|
|
48
48
|
"ts-jest": "^29.4.12",
|
|
49
|
-
"typescript": "^6.0.3"
|
|
49
|
+
"typescript": "^6.0.3",
|
|
50
|
+
"yaml": "^2.9.1"
|
|
50
51
|
},
|
|
51
52
|
"mcpName": "ai.testiv/mcp",
|
|
52
53
|
"scripts": {
|
package/server.json
CHANGED
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-
|
|
2
|
+
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
|
|
3
3
|
"name": "ai.testiv/mcp",
|
|
4
|
+
"title": "TestivAI",
|
|
4
5
|
"description": "Local-first visual regression for AI agents: verdicts, diff images, explain_snapshot. No API key.",
|
|
5
6
|
"repository": {
|
|
6
7
|
"url": "https://github.com/testivai/testivai-oss",
|
|
7
|
-
"source": "github"
|
|
8
|
+
"source": "github",
|
|
9
|
+
"subfolder": "packages/mcp"
|
|
8
10
|
},
|
|
9
|
-
"
|
|
11
|
+
"websiteUrl": "https://github.com/testivai/testivai-oss/tree/main/packages/mcp#readme",
|
|
12
|
+
"version": "0.8.0",
|
|
10
13
|
"packages": [
|
|
11
14
|
{
|
|
12
15
|
"registryType": "npm",
|
|
13
16
|
"registryBaseUrl": "https://registry.npmjs.org",
|
|
14
17
|
"identifier": "@testivai/mcp",
|
|
15
|
-
"version": "0.
|
|
18
|
+
"version": "0.8.0",
|
|
16
19
|
"transport": {
|
|
17
20
|
"type": "stdio"
|
|
18
21
|
}
|