@vitest-agent/mcp 1.0.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/LICENSE +21 -0
- package/README.md +44 -0
- package/bin/vitest-agent-mcp.js +93 -0
- package/context.js +72 -0
- package/index.d.ts +1577 -0
- package/index.js +19 -0
- package/layers/McpLive.js +30 -0
- package/middleware/idempotency.js +128 -0
- package/package.json +58 -0
- package/prompts/explain-failure.js +27 -0
- package/prompts/index.js +89 -0
- package/prompts/regression-since-pass.js +28 -0
- package/prompts/tdd-resume.js +28 -0
- package/prompts/triage.js +24 -0
- package/prompts/why-flaky.js +30 -0
- package/prompts/wrapup.js +19 -0
- package/resources/index.js +155 -0
- package/resources/indexes.js +77 -0
- package/resources/manifest-schema.js +46 -0
- package/resources/paths.js +20 -0
- package/resources/patterns.js +22 -0
- package/resources/upstream-docs.js +22 -0
- package/router.js +74 -0
- package/server.js +838 -0
- package/tools/_tdd-error-envelope.js +98 -0
- package/tools/acceptance-metrics.js +75 -0
- package/tools/cache-health.js +83 -0
- package/tools/commit-changes.js +64 -0
- package/tools/configure.js +107 -0
- package/tools/coverage.js +76 -0
- package/tools/errors.js +151 -0
- package/tools/failure-signature-get.js +73 -0
- package/tools/file-coverage.js +106 -0
- package/tools/help.js +146 -0
- package/tools/history.js +121 -0
- package/tools/hypothesis.js +127 -0
- package/tools/inventory.js +377 -0
- package/tools/note.js +208 -0
- package/tools/overview.js +92 -0
- package/tools/ping.js +22 -0
- package/tools/register-agent.js +135 -0
- package/tools/run-tests.js +359 -0
- package/tools/settings-list.js +48 -0
- package/tools/status.js +74 -0
- package/tools/tdd-artifact.js +101 -0
- package/tools/tdd-behavior.js +177 -0
- package/tools/tdd-goal.js +147 -0
- package/tools/tdd-phase-transition-request.js +212 -0
- package/tools/tdd-task.js +278 -0
- package/tools/test.js +281 -0
- package/tools/trends.js +112 -0
- package/tools/triage-brief.js +42 -0
- package/tools/turn-search.js +60 -0
- package/tools/wrapup-prompt.js +49 -0
- package/tsdoc-metadata.json +11 -0
- package/utils/effect-to-zod.js +81 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { readFile, readdir } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
//#region src/resources/indexes.ts
|
|
5
|
+
async function listMarkdownPages(root) {
|
|
6
|
+
const out = [];
|
|
7
|
+
async function walk(rel) {
|
|
8
|
+
const entries = await readdir(join(root, rel), { withFileTypes: true });
|
|
9
|
+
for (const entry of entries) {
|
|
10
|
+
if (entry.name.startsWith(".") || entry.name.startsWith("_")) continue;
|
|
11
|
+
const next = rel ? `${rel}/${entry.name}` : entry.name;
|
|
12
|
+
if (entry.isDirectory()) await walk(next);
|
|
13
|
+
else if (entry.isFile() && entry.name.endsWith(".md") && entry.name !== "ATTRIBUTION.md") out.push(next.replace(/\.md$/, ""));
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
await walk("");
|
|
17
|
+
out.sort();
|
|
18
|
+
return out;
|
|
19
|
+
}
|
|
20
|
+
async function renderUpstreamIndex(vendorRoot) {
|
|
21
|
+
const manifestRaw = await readFile(join(vendorRoot, "manifest.json"), "utf8");
|
|
22
|
+
const manifest = JSON.parse(manifestRaw);
|
|
23
|
+
const pages = await listMarkdownPages(vendorRoot);
|
|
24
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
25
|
+
for (const page of pages) {
|
|
26
|
+
const slash = page.indexOf("/");
|
|
27
|
+
const section = slash === -1 ? "root" : page.slice(0, slash);
|
|
28
|
+
const list = grouped.get(section) ?? [];
|
|
29
|
+
list.push(page);
|
|
30
|
+
grouped.set(section, list);
|
|
31
|
+
}
|
|
32
|
+
const lines = [];
|
|
33
|
+
lines.push("# Vitest Documentation (Upstream Snapshot)");
|
|
34
|
+
lines.push("");
|
|
35
|
+
lines.push(`Snapshotted from [vitest-dev/vitest](https://github.com/vitest-dev/vitest) at tag \`${manifest.tag}\` (commit \`${manifest.commitSha.slice(0, 12)}\`).`);
|
|
36
|
+
lines.push("");
|
|
37
|
+
lines.push("Fetch any page by URI: `vitest://docs/<path>` (e.g., `vitest://docs/api/mock`).");
|
|
38
|
+
lines.push("");
|
|
39
|
+
const sections = [...grouped.keys()].sort();
|
|
40
|
+
for (const section of sections) {
|
|
41
|
+
lines.push(`## ${section}`);
|
|
42
|
+
lines.push("");
|
|
43
|
+
for (const page of grouped.get(section) ?? []) {
|
|
44
|
+
const display = page.startsWith(`${section}/`) ? page.slice(section.length + 1) : page;
|
|
45
|
+
lines.push(`- \`vitest://docs/${page}\` — ${display}`);
|
|
46
|
+
}
|
|
47
|
+
lines.push("");
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
content: lines.join("\n"),
|
|
51
|
+
mimeType: "text/markdown"
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
async function renderPatternsIndex(patternsRoot) {
|
|
55
|
+
const metaRaw = await readFile(join(patternsRoot, "_meta.json"), "utf8");
|
|
56
|
+
const meta = JSON.parse(metaRaw);
|
|
57
|
+
const lines = [];
|
|
58
|
+
lines.push("# vitest-agent Curated Patterns");
|
|
59
|
+
lines.push("");
|
|
60
|
+
lines.push("Hand-written patterns specific to the vitest-agent project. Fetch any pattern by URI: `vitest-agent://patterns/<slug>`.");
|
|
61
|
+
lines.push("");
|
|
62
|
+
for (const pattern of meta.patterns) {
|
|
63
|
+
lines.push(`## ${pattern.title}`);
|
|
64
|
+
lines.push("");
|
|
65
|
+
lines.push(pattern.summary);
|
|
66
|
+
lines.push("");
|
|
67
|
+
lines.push(`- URI: \`vitest-agent://patterns/${pattern.slug}\``);
|
|
68
|
+
lines.push("");
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
content: lines.join("\n"),
|
|
72
|
+
mimeType: "text/markdown"
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
//#endregion
|
|
77
|
+
export { renderPatternsIndex, renderUpstreamIndex };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
|
|
3
|
+
//#region src/resources/manifest-schema.ts
|
|
4
|
+
const RELATIVE_PATH = /^[A-Za-z0-9._-]+(?:\/[A-Za-z0-9._-]+)*$/;
|
|
5
|
+
/**
|
|
6
|
+
* MCP 2025-11-25 resource annotations. Both sub-fields are optional so a
|
|
7
|
+
* partially-annotated manifest decodes cleanly during an editorial pass.
|
|
8
|
+
*
|
|
9
|
+
* `audience` is the set of client roles a resource is relevant to; today
|
|
10
|
+
* only `assistant` is meaningful for the vitest-agent MCP server.
|
|
11
|
+
* `priority` is a float in [0, 1] that lets a client rank or filter
|
|
12
|
+
* results before pulling content into context. See the editorial guide
|
|
13
|
+
* in `docs/superpowers/specs/2.0-resource-annotations.md` for the
|
|
14
|
+
* priority bands per content type.
|
|
15
|
+
*/
|
|
16
|
+
const ResourceAnnotations = Schema.Struct({
|
|
17
|
+
audience: Schema.optional(Schema.Array(Schema.Literal("user", "assistant"))),
|
|
18
|
+
priority: Schema.optional(Schema.Number.pipe(Schema.between(0, 1)))
|
|
19
|
+
});
|
|
20
|
+
const ManifestPage = Schema.Struct({
|
|
21
|
+
path: Schema.String.pipe(Schema.pattern(RELATIVE_PATH)),
|
|
22
|
+
title: Schema.NonEmptyString,
|
|
23
|
+
description: Schema.NonEmptyString,
|
|
24
|
+
annotations: Schema.optional(ResourceAnnotations)
|
|
25
|
+
});
|
|
26
|
+
const UpstreamManifest = Schema.Struct({
|
|
27
|
+
tag: Schema.NonEmptyString,
|
|
28
|
+
commitSha: Schema.NonEmptyString,
|
|
29
|
+
capturedAt: Schema.NonEmptyString,
|
|
30
|
+
source: Schema.NonEmptyString,
|
|
31
|
+
pages: Schema.optional(Schema.Array(ManifestPage))
|
|
32
|
+
});
|
|
33
|
+
const decodeUpstreamManifest = Schema.decodeUnknown(UpstreamManifest);
|
|
34
|
+
const encodeUpstreamManifest = Schema.encodeUnknown(UpstreamManifest);
|
|
35
|
+
const SLUG_PATTERN = /^[A-Za-z0-9._]+(?:[/-][A-Za-z0-9._]+)*$/;
|
|
36
|
+
const PatternEntry = Schema.Struct({
|
|
37
|
+
slug: Schema.String.pipe(Schema.pattern(SLUG_PATTERN)),
|
|
38
|
+
title: Schema.NonEmptyString,
|
|
39
|
+
summary: Schema.NonEmptyString,
|
|
40
|
+
annotations: Schema.optional(ResourceAnnotations)
|
|
41
|
+
});
|
|
42
|
+
const PatternsManifest = Schema.Struct({ patterns: Schema.Array(PatternEntry) });
|
|
43
|
+
const decodePatternsManifest = Schema.decodeUnknown(PatternsManifest);
|
|
44
|
+
|
|
45
|
+
//#endregion
|
|
46
|
+
export { decodePatternsManifest, decodeUpstreamManifest };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { isAbsolute, normalize, resolve, sep } from "node:path";
|
|
2
|
+
|
|
3
|
+
//#region src/resources/paths.ts
|
|
4
|
+
/**
|
|
5
|
+
* Resolves a user-provided relative path against a vendored root,
|
|
6
|
+
* appending `.md` if missing and rejecting traversal attempts.
|
|
7
|
+
*/
|
|
8
|
+
function resolveResourcePath(root, relativePath) {
|
|
9
|
+
if (relativePath === "") return root;
|
|
10
|
+
if (relativePath.includes("\0")) throw new Error("path contains null byte");
|
|
11
|
+
if (isAbsolute(relativePath)) throw new Error("absolute path not allowed");
|
|
12
|
+
const stripped = relativePath.replace(/^\/+/, "");
|
|
13
|
+
const resolved = resolve(root, normalize(stripped.endsWith(".md") ? stripped : `${stripped}.md`));
|
|
14
|
+
const rootWithSep = root.endsWith(sep) ? root : `${root}${sep}`;
|
|
15
|
+
if (!resolved.startsWith(rootWithSep) && resolved !== root) throw new Error("path escapes vendor root");
|
|
16
|
+
return resolved;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
//#endregion
|
|
20
|
+
export { resolveResourcePath };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
//#region src/resources/patterns.ts
|
|
5
|
+
const SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
6
|
+
async function readPattern(patternsRoot, slug) {
|
|
7
|
+
if (!SLUG_PATTERN.test(slug)) throw new Error(`invalid slug: ${slug}`);
|
|
8
|
+
const absPath = join(patternsRoot, `${slug}.md`);
|
|
9
|
+
try {
|
|
10
|
+
return {
|
|
11
|
+
content: await readFile(absPath, "utf8"),
|
|
12
|
+
mimeType: "text/markdown"
|
|
13
|
+
};
|
|
14
|
+
} catch (err) {
|
|
15
|
+
const code = err.code;
|
|
16
|
+
if (code === "ENOENT" || code === "EISDIR") throw new Error(`pattern not found: ${slug}. See vitest-agent://patterns/ for the index.`);
|
|
17
|
+
throw err;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
//#endregion
|
|
22
|
+
export { readPattern };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { resolveResourcePath } from "./paths.js";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
|
|
4
|
+
//#region src/resources/upstream-docs.ts
|
|
5
|
+
async function readUpstreamDoc(vendorRoot, relativePath) {
|
|
6
|
+
const absPath = resolveResourcePath(vendorRoot, relativePath);
|
|
7
|
+
let content;
|
|
8
|
+
try {
|
|
9
|
+
content = await readFile(absPath, "utf8");
|
|
10
|
+
} catch (err) {
|
|
11
|
+
const code = err.code;
|
|
12
|
+
if (code === "ENOENT" || code === "EISDIR") throw new Error(`upstream doc not found: ${relativePath}`);
|
|
13
|
+
throw err;
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
content,
|
|
17
|
+
mimeType: "text/markdown"
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
//#endregion
|
|
22
|
+
export { readUpstreamDoc };
|
package/router.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { router } from "./context.js";
|
|
2
|
+
import { acceptanceMetrics } from "./tools/acceptance-metrics.js";
|
|
3
|
+
import { cacheHealth } from "./tools/cache-health.js";
|
|
4
|
+
import { commitChanges } from "./tools/commit-changes.js";
|
|
5
|
+
import { configure } from "./tools/configure.js";
|
|
6
|
+
import { testCoverage } from "./tools/coverage.js";
|
|
7
|
+
import { testErrors } from "./tools/errors.js";
|
|
8
|
+
import { failureSignatureGet } from "./tools/failure-signature-get.js";
|
|
9
|
+
import { fileCoverage } from "./tools/file-coverage.js";
|
|
10
|
+
import { help } from "./tools/help.js";
|
|
11
|
+
import { testHistory } from "./tools/history.js";
|
|
12
|
+
import { hypothesis } from "./tools/hypothesis.js";
|
|
13
|
+
import { inventory } from "./tools/inventory.js";
|
|
14
|
+
import { note } from "./tools/note.js";
|
|
15
|
+
import { testOverview } from "./tools/overview.js";
|
|
16
|
+
import { ping } from "./tools/ping.js";
|
|
17
|
+
import { registerAgent } from "./tools/register-agent.js";
|
|
18
|
+
import { runTests } from "./tools/run-tests.js";
|
|
19
|
+
import { settingsList } from "./tools/settings-list.js";
|
|
20
|
+
import { testStatus } from "./tools/status.js";
|
|
21
|
+
import { tddArtifactList } from "./tools/tdd-artifact.js";
|
|
22
|
+
import { tddBehavior } from "./tools/tdd-behavior.js";
|
|
23
|
+
import { tddGoal } from "./tools/tdd-goal.js";
|
|
24
|
+
import { tddPhaseTransitionRequest } from "./tools/tdd-phase-transition-request.js";
|
|
25
|
+
import { tddTask } from "./tools/tdd-task.js";
|
|
26
|
+
import { test } from "./tools/test.js";
|
|
27
|
+
import { testTrends } from "./tools/trends.js";
|
|
28
|
+
import { triageBrief } from "./tools/triage-brief.js";
|
|
29
|
+
import { turnSearch } from "./tools/turn-search.js";
|
|
30
|
+
import { wrapupPrompt } from "./tools/wrapup-prompt.js";
|
|
31
|
+
|
|
32
|
+
//#region src/router.ts
|
|
33
|
+
/**
|
|
34
|
+
* The tRPC router aggregating all MCP tool procedures.
|
|
35
|
+
*
|
|
36
|
+
* Pass to `createCallerFactory` in tests, or to `createCallerFactory(appRouter)`
|
|
37
|
+
* followed by `startMcpServer` in the bin entry to start the MCP server.
|
|
38
|
+
*
|
|
39
|
+
* @public
|
|
40
|
+
*/
|
|
41
|
+
const appRouter = router({
|
|
42
|
+
help,
|
|
43
|
+
test_status: testStatus,
|
|
44
|
+
test_overview: testOverview,
|
|
45
|
+
test_coverage: testCoverage,
|
|
46
|
+
test_history: testHistory,
|
|
47
|
+
test_trends: testTrends,
|
|
48
|
+
test_errors: testErrors,
|
|
49
|
+
test,
|
|
50
|
+
file_coverage: fileCoverage,
|
|
51
|
+
run_tests: runTests,
|
|
52
|
+
register_agent: registerAgent,
|
|
53
|
+
cache_health: cacheHealth,
|
|
54
|
+
configure,
|
|
55
|
+
inventory,
|
|
56
|
+
settings_list: settingsList,
|
|
57
|
+
note,
|
|
58
|
+
turn_search: turnSearch,
|
|
59
|
+
failure_signature_get: failureSignatureGet,
|
|
60
|
+
tdd_task: tddTask,
|
|
61
|
+
tdd_phase_transition_request: tddPhaseTransitionRequest,
|
|
62
|
+
tdd_goal: tddGoal,
|
|
63
|
+
tdd_behavior: tddBehavior,
|
|
64
|
+
tdd_artifact_list: tddArtifactList,
|
|
65
|
+
hypothesis,
|
|
66
|
+
acceptance_metrics: acceptanceMetrics,
|
|
67
|
+
triage_brief: triageBrief,
|
|
68
|
+
wrapup_prompt: wrapupPrompt,
|
|
69
|
+
commit_changes: commitChanges,
|
|
70
|
+
ping
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
//#endregion
|
|
74
|
+
export { appRouter };
|