mirror of
https://github.com/morluto/rea.git
synced 2026-10-26 17:35:11 +00:00
Use JSON.parse directly in package verification and retain one parsed Cursor recovery snapshot. Route native command source loading through the shared transform-service owner so completed command cleanup leaves no transform child. Preserve JSONC validation and caller inputs. Cover the actual public source-loading lifecycle with an authored command and verified process lineage.
49 lines
1.8 KiB
JavaScript
49 lines
1.8 KiB
JavaScript
import { lstat } from "node:fs/promises";
|
|
import { Ajv2020 } from "ajv/dist/2020.js";
|
|
|
|
// Only catalog verification needs built MCP contracts; path checks work
|
|
// from source without a runtime build.
|
|
const loadMcpVerifierResults = () => import("./mcp-verifier-results.mjs");
|
|
|
|
/** Verify schema validity and that the MCP catalog matches session metadata. */
|
|
export const verifyCompleteToolCatalog = async (client, options) => {
|
|
const { requireMcpLifecycleResult, sortVerifierNames } =
|
|
await loadMcpVerifierResults();
|
|
const listed = await client.listTools(undefined, options);
|
|
const ajv = new Ajv2020({ strict: false, validateFormats: false });
|
|
for (const tool of listed.tools) {
|
|
for (const kind of ["inputSchema", "outputSchema"]) {
|
|
const schema = tool[kind];
|
|
if (schema !== undefined && !ajv.validateSchema(schema))
|
|
throw new Error(
|
|
`packaged MCP has invalid ${tool.name}.${kind}: ${ajv.errorsText(ajv.errors)}`,
|
|
);
|
|
}
|
|
}
|
|
const status = await client.callTool(
|
|
{ name: "binary_session", arguments: {} },
|
|
options,
|
|
);
|
|
const expanded = requireMcpLifecycleResult(status, "binary_session");
|
|
const availability = expanded.tool_availability;
|
|
const expected = sortVerifierNames(availability.map(({ name }) => name));
|
|
const observed = sortVerifierNames(listed.tools.map(({ name }) => name));
|
|
if (JSON.stringify(observed) !== JSON.stringify(expected))
|
|
throw new Error(
|
|
"packaged MCP tool inventory diverged from session metadata",
|
|
);
|
|
return observed;
|
|
};
|
|
|
|
/** Check whether a path exists on disk. */
|
|
export const pathExists = async (path) => {
|
|
try {
|
|
await lstat(path);
|
|
return true;
|
|
} catch (cause) {
|
|
if (cause instanceof Error && "code" in cause && cause.code === "ENOENT")
|
|
return false;
|
|
throw cause;
|
|
}
|
|
};
|