@aletheia-works/vivarium-mcp 0.0.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/LICENSE +202 -0
- package/README.md +118 -0
- package/dist/bundled/recipes.json +217 -0
- package/dist/catalogue.d.ts +7 -0
- package/dist/catalogue.d.ts.map +1 -0
- package/dist/catalogue.js +63 -0
- package/dist/catalogue.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +4 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +114 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/get_recipe.d.ts +28 -0
- package/dist/tools/get_recipe.d.ts.map +1 -0
- package/dist/tools/get_recipe.js +29 -0
- package/dist/tools/get_recipe.js.map +1 -0
- package/dist/tools/list_recipes.d.ts +34 -0
- package/dist/tools/list_recipes.d.ts.map +1 -0
- package/dist/tools/list_recipes.js +43 -0
- package/dist/tools/list_recipes.js.map +1 -0
- package/dist/tools/lookup_verdict.d.ts +39 -0
- package/dist/tools/lookup_verdict.d.ts.map +1 -0
- package/dist/tools/lookup_verdict.js +60 -0
- package/dist/tools/lookup_verdict.js.map +1 -0
- package/dist/tools/match_error.d.ts +62 -0
- package/dist/tools/match_error.d.ts.map +1 -0
- package/dist/tools/match_error.js +282 -0
- package/dist/tools/match_error.js.map +1 -0
- package/dist/tools/prepare_new_recipe.d.ts +92 -0
- package/dist/tools/prepare_new_recipe.d.ts.map +1 -0
- package/dist/tools/prepare_new_recipe.js +193 -0
- package/dist/tools/prepare_new_recipe.js.map +1 -0
- package/dist/tools/verify_branch_fix.d.ts +49 -0
- package/dist/tools/verify_branch_fix.d.ts.map +1 -0
- package/dist/tools/verify_branch_fix.js +207 -0
- package/dist/tools/verify_branch_fix.js.map +1 -0
- package/dist/types.d.ts +32 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +14 -0
- package/dist/types.js.map +1 -0
- package/package.json +56 -0
- package/src/bundled/recipes.json +217 -0
package/dist/server.js
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
// MCP server wiring — registers the v1 tools and connects a stdio
|
|
2
|
+
// transport.
|
|
3
|
+
//
|
|
4
|
+
// Tool surface:
|
|
5
|
+
// list_recipes / get_recipe / lookup_verdict — ADR-0019 §3 (X.1, v0.1).
|
|
6
|
+
// match_error — Phase 6 X.2, mirrors the
|
|
7
|
+
// docs S.2 matcher
|
|
8
|
+
// (ADR-0025 §Neutral).
|
|
9
|
+
// verify_branch_fix — Phase 7 B3, deep-link
|
|
10
|
+
// helper for the AI-slop
|
|
11
|
+
// verification loop
|
|
12
|
+
// (ADR-0030).
|
|
13
|
+
// prepare_new_recipe — Tier 2, returns the full
|
|
14
|
+
// authoring command bundle
|
|
15
|
+
// (scaffold + verify +
|
|
16
|
+
// facets/projects rows)
|
|
17
|
+
// for a new upstream
|
|
18
|
+
// issue.
|
|
19
|
+
//
|
|
20
|
+
// See ADR-0019 §1 for the stdio-transport choice.
|
|
21
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
22
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
23
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
24
|
+
import { GET_RECIPE_TOOL, getRecipe } from './tools/get_recipe.js';
|
|
25
|
+
import { LIST_RECIPES_TOOL, listRecipes, } from './tools/list_recipes.js';
|
|
26
|
+
import { LOOKUP_VERDICT_TOOL, lookupVerdict, } from './tools/lookup_verdict.js';
|
|
27
|
+
import { MATCH_ERROR_TOOL, matchError, } from './tools/match_error.js';
|
|
28
|
+
import { PREPARE_NEW_RECIPE_TOOL, prepareNewRecipe, } from './tools/prepare_new_recipe.js';
|
|
29
|
+
import { VERIFY_BRANCH_FIX_TOOL, verifyBranchFix, } from './tools/verify_branch_fix.js';
|
|
30
|
+
const SERVER_NAME = 'vivarium-mcp';
|
|
31
|
+
// Keep in sync with package.json + jsr.json. Updated by the publish
|
|
32
|
+
// workflow on tag push; unsynced values produce a confusing client
|
|
33
|
+
// experience (the MCP `initialize` response carries this string).
|
|
34
|
+
// Stays at 0.1.0 across the Phase 7 A5 + B3 tool additions because
|
|
35
|
+
// the package has not been published to JSR / npm yet — bumping a
|
|
36
|
+
// pre-publish version literal only confuses clients that ever see
|
|
37
|
+
// a development build.
|
|
38
|
+
const SERVER_VERSION = '0.1.0';
|
|
39
|
+
export function createServer() {
|
|
40
|
+
const server = new Server({ name: SERVER_NAME, version: SERVER_VERSION }, { capabilities: { tools: {} } });
|
|
41
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
42
|
+
tools: [
|
|
43
|
+
LIST_RECIPES_TOOL,
|
|
44
|
+
GET_RECIPE_TOOL,
|
|
45
|
+
LOOKUP_VERDICT_TOOL,
|
|
46
|
+
MATCH_ERROR_TOOL,
|
|
47
|
+
VERIFY_BRANCH_FIX_TOOL,
|
|
48
|
+
PREPARE_NEW_RECIPE_TOOL,
|
|
49
|
+
],
|
|
50
|
+
}));
|
|
51
|
+
server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
52
|
+
const name = req.params.name;
|
|
53
|
+
const args = (req.params.arguments ?? {});
|
|
54
|
+
let payload;
|
|
55
|
+
try {
|
|
56
|
+
switch (name) {
|
|
57
|
+
case 'list_recipes':
|
|
58
|
+
payload = await listRecipes(args);
|
|
59
|
+
break;
|
|
60
|
+
case 'get_recipe':
|
|
61
|
+
payload = await getRecipe(args);
|
|
62
|
+
break;
|
|
63
|
+
case 'lookup_verdict':
|
|
64
|
+
payload = await lookupVerdict(args);
|
|
65
|
+
break;
|
|
66
|
+
case 'match_error':
|
|
67
|
+
payload = await matchError(args);
|
|
68
|
+
break;
|
|
69
|
+
case 'verify_branch_fix':
|
|
70
|
+
payload = await verifyBranchFix(args);
|
|
71
|
+
break;
|
|
72
|
+
case 'prepare_new_recipe':
|
|
73
|
+
payload = await prepareNewRecipe(args);
|
|
74
|
+
break;
|
|
75
|
+
default:
|
|
76
|
+
return {
|
|
77
|
+
isError: true,
|
|
78
|
+
content: [
|
|
79
|
+
{
|
|
80
|
+
type: 'text',
|
|
81
|
+
text: `unknown tool: ${name}`,
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
return {
|
|
89
|
+
isError: true,
|
|
90
|
+
content: [
|
|
91
|
+
{
|
|
92
|
+
type: 'text',
|
|
93
|
+
text: `tool ${name} threw: ${err instanceof Error ? err.message : String(err)}`,
|
|
94
|
+
},
|
|
95
|
+
],
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
content: [
|
|
100
|
+
{
|
|
101
|
+
type: 'text',
|
|
102
|
+
text: JSON.stringify(payload, null, 2),
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
};
|
|
106
|
+
});
|
|
107
|
+
return server;
|
|
108
|
+
}
|
|
109
|
+
export async function runServer() {
|
|
110
|
+
const server = createServer();
|
|
111
|
+
const transport = new StdioServerTransport();
|
|
112
|
+
await server.connect(transport);
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { RecipeEntry } from '../types.js';
|
|
2
|
+
export interface GetRecipeArgs {
|
|
3
|
+
slug: string;
|
|
4
|
+
}
|
|
5
|
+
export type GetRecipeResult = {
|
|
6
|
+
found: true;
|
|
7
|
+
recipe: RecipeEntry;
|
|
8
|
+
} | {
|
|
9
|
+
found: false;
|
|
10
|
+
error: string;
|
|
11
|
+
};
|
|
12
|
+
export declare function getRecipe(args: GetRecipeArgs): Promise<GetRecipeResult>;
|
|
13
|
+
export declare const GET_RECIPE_TOOL: {
|
|
14
|
+
readonly name: "get_recipe";
|
|
15
|
+
readonly description: "Get full metadata for a single recipe by slug, including the live page URL, verdict snapshot URL (Layer 2/3), and GitHub source URL. Use `list_recipes` first to discover available slugs. Returns `found: false` with an error message if the slug is unknown.";
|
|
16
|
+
readonly inputSchema: {
|
|
17
|
+
readonly type: "object";
|
|
18
|
+
readonly properties: {
|
|
19
|
+
readonly slug: {
|
|
20
|
+
readonly type: "string";
|
|
21
|
+
readonly pattern: "^[a-z0-9]+(-[a-z0-9]+)*$";
|
|
22
|
+
readonly description: "Kebab-case recipe slug (e.g. 'pandas-56679', 'bash-local-shadows-exit'). Same convention as Manifest v1's `slug`.";
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
readonly required: readonly ["slug"];
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=get_recipe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get_recipe.d.ts","sourceRoot":"","sources":["../../src/tools/get_recipe.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,eAAe,GACvB;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,GACpC;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpC,wBAAsB,SAAS,CAC7B,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,eAAe,CAAC,CAW1B;AAED,eAAO,MAAM,eAAe;;;;;;;;;;;;;;CAgBlB,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { getCatalogue } from '../catalogue.js';
|
|
2
|
+
export async function getRecipe(args) {
|
|
3
|
+
const slug = args.slug?.trim();
|
|
4
|
+
if (!slug) {
|
|
5
|
+
return { found: false, error: 'missing required argument: slug' };
|
|
6
|
+
}
|
|
7
|
+
const { recipes } = await getCatalogue();
|
|
8
|
+
const recipe = recipes.find((r) => r.slug === slug);
|
|
9
|
+
if (!recipe) {
|
|
10
|
+
return { found: false, error: `recipe not found: ${slug}` };
|
|
11
|
+
}
|
|
12
|
+
return { found: true, recipe };
|
|
13
|
+
}
|
|
14
|
+
export const GET_RECIPE_TOOL = {
|
|
15
|
+
name: 'get_recipe',
|
|
16
|
+
description: 'Get full metadata for a single recipe by slug, including the live page URL, verdict snapshot URL (Layer 2/3), and GitHub source URL. Use `list_recipes` first to discover available slugs. Returns `found: false` with an error message if the slug is unknown.',
|
|
17
|
+
inputSchema: {
|
|
18
|
+
type: 'object',
|
|
19
|
+
properties: {
|
|
20
|
+
slug: {
|
|
21
|
+
type: 'string',
|
|
22
|
+
pattern: '^[a-z0-9]+(-[a-z0-9]+)*$',
|
|
23
|
+
description: "Kebab-case recipe slug (e.g. 'pandas-56679', 'bash-local-shadows-exit'). Same convention as Manifest v1's `slug`.",
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
required: ['slug'],
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=get_recipe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get_recipe.js","sourceRoot":"","sources":["../../src/tools/get_recipe.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAW/C,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,IAAmB;IAEnB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;IAC/B,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,iCAAiC,EAAE,CAAC;IACpE,CAAC;IACD,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,YAAY,EAAE,CAAC;IACzC,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IACpD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,qBAAqB,IAAI,EAAE,EAAE,CAAC;IAC9D,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AACjC,CAAC;AAED,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,IAAI,EAAE,YAAY;IAClB,WAAW,EACT,iQAAiQ;IACnQ,WAAW,EAAE;QACX,IAAI,EAAE,QAAiB;QACvB,UAAU,EAAE;YACV,IAAI,EAAE;gBACJ,IAAI,EAAE,QAAiB;gBACvB,OAAO,EAAE,0BAA0B;gBACnC,WAAW,EACT,mHAAmH;aACtH;SACF;QACD,QAAQ,EAAE,CAAC,MAAM,CAAC;KACnB;CACO,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Layer, RecipeEntry } from '../types.js';
|
|
2
|
+
export interface ListRecipesArgs {
|
|
3
|
+
layer?: Layer;
|
|
4
|
+
project?: string;
|
|
5
|
+
q?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface ListRecipesResult {
|
|
8
|
+
count: number;
|
|
9
|
+
recipes: RecipeEntry[];
|
|
10
|
+
}
|
|
11
|
+
export declare function listRecipes(args: ListRecipesArgs): Promise<ListRecipesResult>;
|
|
12
|
+
export declare const LIST_RECIPES_TOOL: {
|
|
13
|
+
readonly name: "list_recipes";
|
|
14
|
+
readonly description: "List Vivarium reproduction recipes — pages or container images that demonstrate a specific upstream bug. Returns metadata only; live verdicts come from `lookup_verdict`. Filter by `layer` (1=WASM in browser, 2=Docker, 3=record-replay), `project` (upstream project name like \"pandas\" or \"bash\"), or `q` (substring search across slug, project, and title).";
|
|
15
|
+
readonly inputSchema: {
|
|
16
|
+
readonly type: "object";
|
|
17
|
+
readonly properties: {
|
|
18
|
+
readonly layer: {
|
|
19
|
+
readonly type: "integer";
|
|
20
|
+
readonly enum: readonly [1, 2, 3];
|
|
21
|
+
readonly description: "Optional layer filter. 1 = WASM in browser, 2 = Docker, 3 = record-replay.";
|
|
22
|
+
};
|
|
23
|
+
readonly project: {
|
|
24
|
+
readonly type: "string";
|
|
25
|
+
readonly description: "Optional upstream project name (e.g. 'pandas', 'bash'). Case-insensitive exact match.";
|
|
26
|
+
};
|
|
27
|
+
readonly q: {
|
|
28
|
+
readonly type: "string";
|
|
29
|
+
readonly description: "Optional substring search across slug, project, and title. Case-insensitive.";
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=list_recipes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list_recipes.d.ts","sourceRoot":"","sources":["../../src/tools/list_recipes.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEtD,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,CAAC,CAAC,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,WAAW,EAAE,CAAC;CACxB;AAED,wBAAsB,WAAW,CAC/B,IAAI,EAAE,eAAe,GACpB,OAAO,CAAC,iBAAiB,CAAC,CAkB5B;AAED,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;CAyBpB,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { getCatalogue } from '../catalogue.js';
|
|
2
|
+
export async function listRecipes(args) {
|
|
3
|
+
const { recipes } = await getCatalogue();
|
|
4
|
+
const layer = args.layer;
|
|
5
|
+
const project = args.project?.trim().toLowerCase();
|
|
6
|
+
const q = args.q?.trim().toLowerCase();
|
|
7
|
+
const filtered = recipes.filter((r) => {
|
|
8
|
+
if (layer !== undefined && r.layer !== layer)
|
|
9
|
+
return false;
|
|
10
|
+
if (project && r.project.toLowerCase() !== project)
|
|
11
|
+
return false;
|
|
12
|
+
if (q) {
|
|
13
|
+
const hay = (r.slug + ' ' + r.project + ' ' + r.title).toLowerCase();
|
|
14
|
+
if (!hay.includes(q))
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
return true;
|
|
18
|
+
});
|
|
19
|
+
return { count: filtered.length, recipes: filtered };
|
|
20
|
+
}
|
|
21
|
+
export const LIST_RECIPES_TOOL = {
|
|
22
|
+
name: 'list_recipes',
|
|
23
|
+
description: 'List Vivarium reproduction recipes — pages or container images that demonstrate a specific upstream bug. Returns metadata only; live verdicts come from `lookup_verdict`. Filter by `layer` (1=WASM in browser, 2=Docker, 3=record-replay), `project` (upstream project name like "pandas" or "bash"), or `q` (substring search across slug, project, and title).',
|
|
24
|
+
inputSchema: {
|
|
25
|
+
type: 'object',
|
|
26
|
+
properties: {
|
|
27
|
+
layer: {
|
|
28
|
+
type: 'integer',
|
|
29
|
+
enum: [1, 2, 3],
|
|
30
|
+
description: 'Optional layer filter. 1 = WASM in browser, 2 = Docker, 3 = record-replay.',
|
|
31
|
+
},
|
|
32
|
+
project: {
|
|
33
|
+
type: 'string',
|
|
34
|
+
description: "Optional upstream project name (e.g. 'pandas', 'bash'). Case-insensitive exact match.",
|
|
35
|
+
},
|
|
36
|
+
q: {
|
|
37
|
+
type: 'string',
|
|
38
|
+
description: 'Optional substring search across slug, project, and title. Case-insensitive.',
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=list_recipes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list_recipes.js","sourceRoot":"","sources":["../../src/tools/list_recipes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAc/C,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,IAAqB;IAErB,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,YAAY,EAAE,CAAC;IAEzC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;IACzB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACnD,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAEvC,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;QACpC,IAAI,KAAK,KAAK,SAAS,IAAI,CAAC,CAAC,KAAK,KAAK,KAAK;YAAE,OAAO,KAAK,CAAC;QAC3D,IAAI,OAAO,IAAI,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,OAAO;YAAE,OAAO,KAAK,CAAC;QACjE,IAAI,CAAC,EAAE,CAAC;YACN,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,GAAG,GAAG,CAAC,CAAC,OAAO,GAAG,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;YACrE,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;gBAAE,OAAO,KAAK,CAAC;QACrC,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;IAEH,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;AACvD,CAAC;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,IAAI,EAAE,cAAc;IACpB,WAAW,EACT,mWAAmW;IACrW,WAAW,EAAE;QACX,IAAI,EAAE,QAAiB;QACvB,UAAU,EAAE;YACV,KAAK,EAAE;gBACL,IAAI,EAAE,SAAkB;gBACxB,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;gBACf,WAAW,EACT,4EAA4E;aAC/E;YACD,OAAO,EAAE;gBACP,IAAI,EAAE,QAAiB;gBACvB,WAAW,EACT,uFAAuF;aAC1F;YACD,CAAC,EAAE;gBACD,IAAI,EAAE,QAAiB;gBACvB,WAAW,EACT,8EAA8E;aACjF;SACF;KACF;CACO,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { VerdictSnapshot } from '../types.js';
|
|
2
|
+
export interface LookupVerdictArgs {
|
|
3
|
+
slug: string;
|
|
4
|
+
}
|
|
5
|
+
export type LookupVerdictResult = {
|
|
6
|
+
kind: 'live';
|
|
7
|
+
slug: string;
|
|
8
|
+
page_url: string;
|
|
9
|
+
note: string;
|
|
10
|
+
} | {
|
|
11
|
+
kind: 'snapshot';
|
|
12
|
+
slug: string;
|
|
13
|
+
snapshot: VerdictSnapshot;
|
|
14
|
+
} | {
|
|
15
|
+
kind: 'unavailable';
|
|
16
|
+
slug: string;
|
|
17
|
+
reason: string;
|
|
18
|
+
} | {
|
|
19
|
+
kind: 'not_found';
|
|
20
|
+
slug: string;
|
|
21
|
+
error: string;
|
|
22
|
+
};
|
|
23
|
+
export declare function lookupVerdict(args: LookupVerdictArgs): Promise<LookupVerdictResult>;
|
|
24
|
+
export declare const LOOKUP_VERDICT_TOOL: {
|
|
25
|
+
readonly name: "lookup_verdict";
|
|
26
|
+
readonly description: "Look up the latest verdict for a recipe by slug. Layer 1 recipes produce live in-browser verdicts and have no static snapshot — this returns kind='live' with the page URL and a note suggesting the agent open the page directly. Layer 2/3 recipes return kind='snapshot' with the deployed verdict.json contents (verdict, exit code, image digest, captured-at timestamp, stdout, stderr tail). Returns kind='unavailable' or kind='not_found' on failure.";
|
|
27
|
+
readonly inputSchema: {
|
|
28
|
+
readonly type: "object";
|
|
29
|
+
readonly properties: {
|
|
30
|
+
readonly slug: {
|
|
31
|
+
readonly type: "string";
|
|
32
|
+
readonly pattern: "^[a-z0-9]+(-[a-z0-9]+)*$";
|
|
33
|
+
readonly description: "Kebab-case recipe slug.";
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
readonly required: readonly ["slug"];
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=lookup_verdict.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lookup_verdict.d.ts","sourceRoot":"","sources":["../../src/tools/lookup_verdict.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,mBAAmB,GAC3B;IACE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd,GACD;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,eAAe,CAAC;CAC3B,GACD;IACE,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB,GACD;IACE,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEN,wBAAsB,aAAa,CACjC,IAAI,EAAE,iBAAiB,GACtB,OAAO,CAAC,mBAAmB,CAAC,CAgD9B;AAED,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;CAetB,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { fetchVerdictSnapshot, getCatalogue } from '../catalogue.js';
|
|
2
|
+
export async function lookupVerdict(args) {
|
|
3
|
+
const slug = args.slug?.trim();
|
|
4
|
+
if (!slug) {
|
|
5
|
+
return {
|
|
6
|
+
kind: 'not_found',
|
|
7
|
+
slug: '',
|
|
8
|
+
error: 'missing required argument: slug',
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
const { recipes } = await getCatalogue();
|
|
12
|
+
const recipe = recipes.find((r) => r.slug === slug);
|
|
13
|
+
if (!recipe) {
|
|
14
|
+
return {
|
|
15
|
+
kind: 'not_found',
|
|
16
|
+
slug,
|
|
17
|
+
error: `recipe not found: ${slug}`,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
if (recipe.layer === 1) {
|
|
21
|
+
return {
|
|
22
|
+
kind: 'live',
|
|
23
|
+
slug,
|
|
24
|
+
page_url: recipe.page_url,
|
|
25
|
+
note: 'Layer 1 reproductions produce verdicts live in the browser; the agent can open the page or delegate to a browser MCP to obtain an actual verdict.',
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
if (!recipe.verdict_url) {
|
|
29
|
+
return {
|
|
30
|
+
kind: 'unavailable',
|
|
31
|
+
slug,
|
|
32
|
+
reason: 'recipe entry has no verdict_url',
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
const snapshot = await fetchVerdictSnapshot(recipe.verdict_url);
|
|
36
|
+
if (!snapshot) {
|
|
37
|
+
return {
|
|
38
|
+
kind: 'unavailable',
|
|
39
|
+
slug,
|
|
40
|
+
reason: `verdict snapshot fetch failed or returned non-v1 data: ${recipe.verdict_url}`,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
return { kind: 'snapshot', slug, snapshot };
|
|
44
|
+
}
|
|
45
|
+
export const LOOKUP_VERDICT_TOOL = {
|
|
46
|
+
name: 'lookup_verdict',
|
|
47
|
+
description: "Look up the latest verdict for a recipe by slug. Layer 1 recipes produce live in-browser verdicts and have no static snapshot — this returns kind='live' with the page URL and a note suggesting the agent open the page directly. Layer 2/3 recipes return kind='snapshot' with the deployed verdict.json contents (verdict, exit code, image digest, captured-at timestamp, stdout, stderr tail). Returns kind='unavailable' or kind='not_found' on failure.",
|
|
48
|
+
inputSchema: {
|
|
49
|
+
type: 'object',
|
|
50
|
+
properties: {
|
|
51
|
+
slug: {
|
|
52
|
+
type: 'string',
|
|
53
|
+
pattern: '^[a-z0-9]+(-[a-z0-9]+)*$',
|
|
54
|
+
description: 'Kebab-case recipe slug.',
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
required: ['slug'],
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
//# sourceMappingURL=lookup_verdict.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lookup_verdict.js","sourceRoot":"","sources":["../../src/tools/lookup_verdict.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AA8BrE,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,IAAuB;IAEvB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;IAC/B,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO;YACL,IAAI,EAAE,WAAW;YACjB,IAAI,EAAE,EAAE;YACR,KAAK,EAAE,iCAAiC;SACzC,CAAC;IACJ,CAAC;IAED,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,YAAY,EAAE,CAAC;IACzC,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IACpD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO;YACL,IAAI,EAAE,WAAW;YACjB,IAAI;YACJ,KAAK,EAAE,qBAAqB,IAAI,EAAE;SACnC,CAAC;IACJ,CAAC;IAED,IAAI,MAAM,CAAC,KAAK,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO;YACL,IAAI,EAAE,MAAM;YACZ,IAAI;YACJ,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,IAAI,EACF,mJAAmJ;SACtJ,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;QACxB,OAAO;YACL,IAAI,EAAE,aAAa;YACnB,IAAI;YACJ,MAAM,EAAE,iCAAiC;SAC1C,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,oBAAoB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAChE,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO;YACL,IAAI,EAAE,aAAa;YACnB,IAAI;YACJ,MAAM,EAAE,0DAA0D,MAAM,CAAC,WAAW,EAAE;SACvF,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;AAC9C,CAAC;AAED,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,IAAI,EAAE,gBAAgB;IACtB,WAAW,EACT,gcAAgc;IAClc,WAAW,EAAE;QACX,IAAI,EAAE,QAAiB;QACvB,UAAU,EAAE;YACV,IAAI,EAAE;gBACJ,IAAI,EAAE,QAAiB;gBACvB,OAAO,EAAE,0BAA0B;gBACnC,WAAW,EAAE,yBAAyB;aACvC;SACF;QACD,QAAQ,EAAE,CAAC,MAAM,CAAC;KACnB;CACO,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { RecipeEntry } from '../types.js';
|
|
2
|
+
export interface MatchErrorArgs {
|
|
3
|
+
text: string;
|
|
4
|
+
limit?: number;
|
|
5
|
+
}
|
|
6
|
+
interface MatchedToken {
|
|
7
|
+
source: 'symptom' | 'tags' | 'project' | 'slug';
|
|
8
|
+
token: string;
|
|
9
|
+
/**
|
|
10
|
+
* How the token was matched. Omitted (undefined) for direct exact
|
|
11
|
+
* matches (the v1 case). `synonym` indicates the catalogue token
|
|
12
|
+
* was reached via a synonym-group expansion of an input token.
|
|
13
|
+
* `fuzzy` indicates a Levenshtein-distance-1 match (typo-tolerant).
|
|
14
|
+
* v1 clients ignore this field; v2 clients can render the
|
|
15
|
+
* provenance.
|
|
16
|
+
*/
|
|
17
|
+
via?: 'synonym' | 'fuzzy';
|
|
18
|
+
/**
|
|
19
|
+
* Original input token that triggered a non-exact match (set when
|
|
20
|
+
* `via` is `synonym` or `fuzzy`). Lets agents render "you wrote X,
|
|
21
|
+
* we matched Y."
|
|
22
|
+
*/
|
|
23
|
+
input?: string;
|
|
24
|
+
}
|
|
25
|
+
interface ScoredRecipe {
|
|
26
|
+
recipe: RecipeEntry;
|
|
27
|
+
score: number;
|
|
28
|
+
matched: MatchedToken[];
|
|
29
|
+
}
|
|
30
|
+
export interface MatchErrorResult {
|
|
31
|
+
ok: true;
|
|
32
|
+
query_token_count: number;
|
|
33
|
+
total_recipes: number;
|
|
34
|
+
matches: ScoredRecipe[];
|
|
35
|
+
}
|
|
36
|
+
export declare function matchError(args: MatchErrorArgs): Promise<MatchErrorResult | {
|
|
37
|
+
ok: false;
|
|
38
|
+
error: string;
|
|
39
|
+
}>;
|
|
40
|
+
export declare const MATCH_ERROR_TOOL: {
|
|
41
|
+
readonly name: "match_error";
|
|
42
|
+
readonly description: "Find Vivarium recipes that match a pasted error message or stack trace by mechanical token overlap (no LLM). The text is tokenised, lowercase-compared against each recipe's symptom (weight 5 per segment), tags (3), project (2), and slug (2). v2 (Phase 7 A5) adds adjacent-pair tokens (so 'data type' can hit `dtype`), a small synonym table (e.g. dtype⇄datatype, segfault⇄sigsegv), and bounded Levenshtein-1 fuzzy matching for tokens of length ≥ 6. Stopword set covers English, Japanese, German, Spanish, French, Chinese, and Korean noise tokens. Recipes with score > 0 are returned in descending score order; ties broken by (layer asc, slug asc). Each matched token reports its `via` (`synonym` or `fuzzy` when non-exact) and the original `input` that triggered it, so agents can render the provenance. Pair with `get_recipe` to drill into a specific result, or `list_recipes` for unfiltered browsing.";
|
|
43
|
+
readonly inputSchema: {
|
|
44
|
+
readonly type: "object";
|
|
45
|
+
readonly properties: {
|
|
46
|
+
readonly text: {
|
|
47
|
+
readonly type: "string";
|
|
48
|
+
readonly description: "Error message, stack trace, or any free-text fragment to match against the catalogue. Tokenised on non-alphanumeric runs after lowercasing; tokens shorter than 3 chars and a multi-language stopword list are dropped. Input longer than 16 KB is truncated from the front.";
|
|
49
|
+
};
|
|
50
|
+
readonly limit: {
|
|
51
|
+
readonly type: "integer";
|
|
52
|
+
readonly minimum: 1;
|
|
53
|
+
readonly maximum: 50;
|
|
54
|
+
readonly default: 10;
|
|
55
|
+
readonly description: "Maximum number of matches to return. Defaults to 10; capped at 50.";
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
readonly required: readonly ["text"];
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
export {};
|
|
62
|
+
//# sourceMappingURL=match_error.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"match_error.d.ts","sourceRoot":"","sources":["../../src/tools/match_error.ts"],"names":[],"mappings":"AAgCA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,YAAY;IACpB,MAAM,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC;IAChD,KAAK,EAAE,MAAM,CAAC;IACd;;;;;;;OAOG;IACH,GAAG,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;IAC1B;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,YAAY;IACpB,MAAM,EAAE,WAAW,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,YAAY,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,IAAI,CAAC;IACT,iBAAiB,EAAE,MAAM,CAAC;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,YAAY,EAAE,CAAC;CACzB;AAmOD,wBAAsB,UAAU,CAC9B,IAAI,EAAE,cAAc,GACnB,OAAO,CAAC,gBAAgB,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CA8B1D;AAED,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;CAuBnB,CAAC"}
|