fix(verifiers): consolidate shared helper ownership

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.
This commit is contained in:
morluto committed 2026-10-24 22:28:39 +08:00
1 parent 791524c2fa
commit 48ff37f6ea
14 files changed
+149 -80

No files matched your search

+5 -5
View File
@@ -1,12 +1,12 @@
import { importVerifierSource } from "./verifier-source-loader.mjs";
let implementation; let implementation;
/** Load the development command owner and its canonical process source graph. */ /** Load the development command owner and its canonical process source graph. */
export async function createVerifierCommands(options = {}) { export async function createVerifierCommands(options = {}) {
implementation ??= import("tsx/esm/api").then(({ tsImport }) => implementation ??= importVerifierSource(
tsImport( new URL("./verifier-command-owner.mts", import.meta.url).href,
new URL("./verifier-command-owner.mts", import.meta.url).href, import.meta.url,
import.meta.url,
),
); );
const module = await implementation; const module = await implementation;
return module.createVerifierCommands(options); return module.createVerifierCommands(options);
+1 -4
View File
@@ -1,13 +1,10 @@
import { lstat } from "node:fs/promises"; import { lstat } from "node:fs/promises";
import { Ajv2020 } from "ajv/dist/2020.js"; import { Ajv2020 } from "ajv/dist/2020.js";
// Only catalog verification needs built MCP contracts; the other helpers work // Only catalog verification needs built MCP contracts; path checks work
// from source without a runtime build. // from source without a runtime build.
const loadMcpVerifierResults = () => import("./mcp-verifier-results.mjs"); const loadMcpVerifierResults = () => import("./mcp-verifier-results.mjs");
/** Parse JSON from a command output string. */
export const json = (text) => JSON.parse(text);
/** Verify schema validity and that the MCP catalog matches session metadata. */ /** Verify schema validity and that the MCP catalog matches session metadata. */
export const verifyCompleteToolCatalog = async (client, options) => { export const verifyCompleteToolCatalog = async (client, options) => {
const { requireMcpLifecycleResult, sortVerifierNames } = const { requireMcpLifecycleResult, sortVerifierNames } =
+5 -7
View File
@@ -3,8 +3,6 @@ import { isDeepStrictEqual } from "node:util";
import { join } from "node:path"; import { join } from "node:path";
import { TextReader, Uint8ArrayWriter, ZipWriter } from "@zip.js/zip.js"; import { TextReader, Uint8ArrayWriter, ZipWriter } from "@zip.js/zip.js";
import { json } from "./lib/verify-package-core.mjs";
/** Run artifact and JavaScript application analysis against packaged fixtures. */ /** Run artifact and JavaScript application analysis against packaged fixtures. */
export async function verifyPackageArtifactAndElectron({ export async function verifyPackageArtifactAndElectron({
commands, commands,
@@ -37,14 +35,14 @@ const verifyPackagedArtifact = async ({
const artifactWriter = new ZipWriter(new Uint8ArrayWriter()); const artifactWriter = new ZipWriter(new Uint8ArrayWriter());
await artifactWriter.add("app/main.js", new TextReader("main();")); await artifactWriter.add("app/main.js", new TextReader("main();"));
await writeFile(artifactArchive, await artifactWriter.close()); await writeFile(artifactArchive, await artifactWriter.close());
const artifactInspection = json( const artifactInspection = JSON.parse(
await commands.run( await commands.run(
cli, cli,
["inspect-artifact", artifactArchive, "--json"], ["inspect-artifact", artifactArchive, "--json"],
environment, environment,
), ),
); );
const repeatedArtifactInspection = json( const repeatedArtifactInspection = JSON.parse(
await commands.run( await commands.run(
cli, cli,
["inspect-artifact", artifactArchive, "--json"], ["inspect-artifact", artifactArchive, "--json"],
@@ -95,7 +93,7 @@ const verifyPackagedElectronApplication = async ({
join(applicationRoot, "preload.js"), join(applicationRoot, "preload.js"),
'const { contextBridge, ipcRenderer } = require("electron");\ncontextBridge.exposeInMainWorld("rea", { ping: () => ipcRenderer.invoke("rea:ping") });\n', 'const { contextBridge, ipcRenderer } = require("electron");\ncontextBridge.exposeInMainWorld("rea", { ping: () => ipcRenderer.invoke("rea:ping") });\n',
); );
const applicationAnalysis = json( const applicationAnalysis = JSON.parse(
await commands.run( await commands.run(
cli, cli,
["analyze-javascript-application", applicationRoot, "--json"], ["analyze-javascript-application", applicationRoot, "--json"],
@@ -110,7 +108,7 @@ const verifyPackagedElectronApplication = async ({
?.paired_renderer_transmissions !== 1 ?.paired_renderer_transmissions !== 1
) )
throw new Error("packaged JavaScript application analysis CLI failed"); throw new Error("packaged JavaScript application analysis CLI failed");
const routedApplicationAnalysis = json( const routedApplicationAnalysis = JSON.parse(
await commands.run( await commands.run(
cli, cli,
["analyze", applicationRoot, "--json"], ["analyze", applicationRoot, "--json"],
@@ -138,7 +136,7 @@ const verifyPackagedArtifactExtraction = async ({
); );
if (occurrence?.logical_path === undefined) if (occurrence?.logical_path === undefined)
throw new Error("packaged artifact inventory omitted the selected member"); throw new Error("packaged artifact inventory omitted the selected member");
const extraction = json( const extraction = JSON.parse(
await commands.run( await commands.run(
cli, cli,
["extract-artifact", artifactArchive, "--json"], ["extract-artifact", artifactArchive, "--json"],
+5 -4
View File
@@ -1,4 +1,3 @@
import { json } from "./lib/verify-package-core.mjs";
import { import {
expandCapabilitiesOutput, expandCapabilitiesOutput,
expandProviderOutput, expandProviderOutput,
@@ -11,12 +10,14 @@ export async function verifyPackageCapabilitiesAndSearch({
environment, environment,
}) { }) {
const capabilities = expandCapabilitiesOutput( const capabilities = expandCapabilitiesOutput(
json(await commands.run(cli, ["capabilities", "--json"], environment)), JSON.parse(
await commands.run(cli, ["capabilities", "--json"], environment),
),
); );
if (!Array.isArray(capabilities.capabilities)) if (!Array.isArray(capabilities.capabilities))
throw new Error("packaged capabilities CLI failed"); throw new Error("packaged capabilities CLI failed");
const providers = expandProviderOutput( const providers = expandProviderOutput(
json(await commands.run(cli, ["providers", "--json"], environment)), JSON.parse(await commands.run(cli, ["providers", "--json"], environment)),
); );
const candidates = providers.analysis_provider_candidates; const candidates = providers.analysis_provider_candidates;
if ( if (
@@ -32,7 +33,7 @@ export async function verifyPackageCapabilitiesAndSearch({
) )
throw new Error("packaged providers CLI failed"); throw new Error("packaged providers CLI failed");
if (process.platform !== "linux") { if (process.platform !== "linux") {
const searchResult = json( const searchResult = JSON.parse(
await commands.run( await commands.run(
cli, cli,
[ [
+1 -3
View File
@@ -1,5 +1,3 @@
import { json } from "./lib/verify-package-core.mjs";
const REQUIRED_HELP_COMMANDS = [ const REQUIRED_HELP_COMMANDS = [
"setup", "setup",
"update", "update",
@@ -87,7 +85,7 @@ export async function verifyPackageDiscovery({ commands, cli, environment }) {
["doctor", "--json"], ["doctor", "--json"],
environment, environment,
); );
const doctor = json(doctorExecution.stdout); const doctor = JSON.parse(doctorExecution.stdout);
const { supportedSetupHost, hopperReadinessRequired, hopperSetupSupported } = const { supportedSetupHost, hopperReadinessRequired, hopperSetupSupported } =
packageSetupSupport(doctor.checks, { packageSetupSupport(doctor.checks, {
platform: process.platform, platform: process.platform,
+4 -5
View File
@@ -2,7 +2,6 @@ import { readFile, writeFile } from "node:fs/promises";
import { join } from "node:path"; import { join } from "node:path";
import { createEvidence } from "../dist/domain/evidence.js"; import { createEvidence } from "../dist/domain/evidence.js";
import { json } from "./lib/verify-package-core.mjs";
/** Round-trip historical reference import and evidence bundles. */ /** Round-trip historical reference import and evidence bundles. */
export async function verifyPackageEvidence({ export async function verifyPackageEvidence({
@@ -12,7 +11,7 @@ export async function verifyPackageEvidence({
referenceRoot, referenceRoot,
environment, environment,
}) { }) {
const referenceImport = json( const referenceImport = JSON.parse(
await commands.run( await commands.run(
cli, cli,
["import-reference-source", referenceRoot, "--json"], ["import-reference-source", referenceRoot, "--json"],
@@ -39,21 +38,21 @@ export async function verifyPackageEvidence({
const sourceBundlePath = join(evidenceRoot, "source.json"); const sourceBundlePath = join(evidenceRoot, "source.json");
const canonicalBundlePath = join(evidenceRoot, "canonical.json"); const canonicalBundlePath = join(evidenceRoot, "canonical.json");
await writeFile(sourceBundlePath, serializeEvidenceBundle(sourceBundle)); await writeFile(sourceBundlePath, serializeEvidenceBundle(sourceBundle));
const importedBundle = json( const importedBundle = JSON.parse(
await commands.run( await commands.run(
cli, cli,
["evidence-import", sourceBundlePath, "--json"], ["evidence-import", sourceBundlePath, "--json"],
environment, environment,
), ),
); );
const exportedBundle = json( const exportedBundle = JSON.parse(
await commands.run( await commands.run(
cli, cli,
["evidence-export", sourceBundlePath, canonicalBundlePath, "--json"], ["evidence-export", sourceBundlePath, canonicalBundlePath, "--json"],
environment, environment,
), ),
); );
const comparedBundle = json( const comparedBundle = JSON.parse(
await commands.run( await commands.run(
cli, cli,
["compare", sourceBundlePath, canonicalBundlePath, "--json"], ["compare", sourceBundlePath, canonicalBundlePath, "--json"],
+2 -4
View File
@@ -2,8 +2,6 @@ import { rm } from "node:fs/promises";
import { join } from "node:path"; import { join } from "node:path";
import { pathToFileURL } from "node:url"; import { pathToFileURL } from "node:url";
import { json } from "./lib/verify-package-core.mjs";
/** Install the packed CLI globally with and without optional dependencies and verify PTY degradation. */ /** Install the packed CLI globally with and without optional dependencies and verify PTY degradation. */
export async function verifyPackageInstall({ export async function verifyPackageInstall({
tarball, tarball,
@@ -39,7 +37,7 @@ export async function verifyPackageInstall({
"lib/node_modules/rea-agents/dist/process/capture/ProcessCaptureCapability.js", "lib/node_modules/rea-agents/dist/process/capture/ProcessCaptureCapability.js",
), ),
).href; ).href;
const processCaptureCapability = json( const processCaptureCapability = JSON.parse(
( (
await commands.exec( await commands.exec(
process.execPath, process.execPath,
@@ -84,7 +82,7 @@ export async function verifyPackageInstall({
"lib/node_modules/rea-agents/dist/process/capture/ProcessCaptureCapability.js", "lib/node_modules/rea-agents/dist/process/capture/ProcessCaptureCapability.js",
), ),
).href; ).href;
const noOptionalCapability = json( const noOptionalCapability = JSON.parse(
( (
await commands.exec( await commands.exec(
process.execPath, process.execPath,
+7 -8
View File
@@ -4,7 +4,6 @@ import { join } from "node:path";
import { createEvidence } from "../dist/domain/evidence.js"; import { createEvidence } from "../dist/domain/evidence.js";
import { buildManagedPeFixture } from "./fixtures/managed/pe.mjs"; import { buildManagedPeFixture } from "./fixtures/managed/pe.mjs";
import { functionDossier } from "./fixtures/managed/function-dossier.mjs"; import { functionDossier } from "./fixtures/managed/function-dossier.mjs";
import { json } from "./lib/verify-package-core.mjs";
const buildManagedFixtures = async (workspace) => { const buildManagedFixtures = async (workspace) => {
const managedPath = join(workspace, "managed-fixture.exe"); const managedPath = join(workspace, "managed-fixture.exe");
@@ -44,7 +43,7 @@ const verifyManagedArtifact = async ({
managedPath, managedPath,
environment, environment,
}) => { }) => {
const managedArtifact = json( const managedArtifact = JSON.parse(
await commands.run( await commands.run(
cli, cli,
["inspect-managed-artifact", managedPath, "--json"], ["inspect-managed-artifact", managedPath, "--json"],
@@ -66,7 +65,7 @@ const verifyManagedMembers = async ({
managedPath, managedPath,
environment, environment,
}) => { }) => {
const managedMembers = json( const managedMembers = JSON.parse(
await commands.run( await commands.run(
cli, cli,
["inspect-managed-members", managedPath, "--json"], ["inspect-managed-members", managedPath, "--json"],
@@ -111,7 +110,7 @@ const verifyManagedReconstruction = async ({
], ],
notes: ["packaged synthetic reconstruction import"], notes: ["packaged synthetic reconstruction import"],
}; };
const managedReconstruction = json( const managedReconstruction = JSON.parse(
await commands.run( await commands.run(
cli, cli,
[ [
@@ -138,7 +137,7 @@ const verifyManagedBoundaries = async ({
managedPath, managedPath,
environment, environment,
}) => { }) => {
const managedBoundaries = json( const managedBoundaries = JSON.parse(
await commands.run( await commands.run(
cli, cli,
["inspect-managed-native-boundaries", managedPath, "--json"], ["inspect-managed-native-boundaries", managedPath, "--json"],
@@ -174,7 +173,7 @@ const verifyManagedApplicationGraph = async ({
"inspect_managed_native_boundaries", "inspect_managed_native_boundaries",
), ),
}; };
const managedApplicationGraph = json( const managedApplicationGraph = JSON.parse(
await commands.run( await commands.run(
cli, cli,
[ [
@@ -260,7 +259,7 @@ const verifyManagedNativeVerification = async ({
), ),
], ],
}; };
const managedNativeVerification = json( const managedNativeVerification = JSON.parse(
await commands.run( await commands.run(
cli, cli,
[ [
@@ -289,7 +288,7 @@ const verifyManagedComparison = async ({
managedRightPath, managedRightPath,
environment, environment,
}) => { }) => {
const managedComparison = json( const managedComparison = JSON.parse(
await commands.run( await commands.run(
cli, cli,
["compare-managed-members", managedPath, managedRightPath, "--json"], ["compare-managed-members", managedPath, managedRightPath, "--json"],
+5 -5
View File
@@ -11,7 +11,7 @@ import { StdioClientTransport } from "@modelcontextprotocol/client/stdio";
import { resolveMcpStartupBudgets } from "../dist/config/mcpStartupBudgets.js"; import { resolveMcpStartupBudgets } from "../dist/config/mcpStartupBudgets.js";
import { parseEvidence } from "../dist/domain/evidence.js"; import { parseEvidence } from "../dist/domain/evidence.js";
import * as prompts from "./verify-package-prompts.mjs"; import * as prompts from "./verify-package-prompts.mjs";
import { json, verifyCompleteToolCatalog } from "./lib/verify-package-core.mjs"; import { verifyCompleteToolCatalog } from "./lib/verify-package-core.mjs";
import { withVerifierCleanup } from "./lib/verifier-cleanup.mjs"; import { withVerifierCleanup } from "./lib/verifier-cleanup.mjs";
const verifyMcpToolsAndPrompts = async (client, mcpOptions) => { const verifyMcpToolsAndPrompts = async (client, mcpOptions) => {
@@ -95,7 +95,7 @@ const verifyMcpNonLinuxCurrentDocument = async (
mcpOptions, mcpOptions,
current, current,
) => { ) => {
if (json(prompts.mcpText(current)).normalized_result !== "fixture") if (JSON.parse(prompts.mcpText(current)).normalized_result !== "fixture")
throw new Error("packaged MCP bridge call failed"); throw new Error("packaged MCP bridge call failed");
const batch = await client.callTool( const batch = await client.callTool(
{ {
@@ -104,7 +104,7 @@ const verifyMcpNonLinuxCurrentDocument = async (
}, },
mcpOptions, mcpOptions,
); );
const batchResult = json(prompts.mcpText(batch)).normalized_result; const batchResult = JSON.parse(prompts.mcpText(batch)).normalized_result;
if ( if (
batch.isError === true || batch.isError === true ||
batchResult?.total !== 1 || batchResult?.total !== 1 ||
@@ -178,7 +178,7 @@ const verifyMcpInlineArtifactEvidence = async (
inspected.structuredContent?.normalized_result, inspected.structuredContent?.normalized_result,
); );
assert.deepEqual( assert.deepEqual(
json(prompts.mcpText(inspected)), JSON.parse(prompts.mcpText(inspected)),
inspected.structuredContent, inspected.structuredContent,
); );
const compared = await client.callTool( const compared = await client.callTool(
@@ -251,7 +251,7 @@ export async function verifyPackageMcp({
evidenceRoot, evidenceRoot,
artifactArchive, artifactArchive,
}) { }) {
const diagnosed = json( const diagnosed = JSON.parse(
( (
await commands.exec(cli, ["mcp", "doctor", "--json"], { await commands.exec(cli, ["mcp", "doctor", "--json"], {
env: environment, env: environment,
+6 -8
View File
@@ -1,5 +1,3 @@
import { json } from "./lib/verify-package-core.mjs";
/** Run platform-specific deep-analysis smoke tests. */ /** Run platform-specific deep-analysis smoke tests. */
export async function verifyPackagePlatform({ export async function verifyPackagePlatform({
commands, commands,
@@ -15,7 +13,7 @@ export async function verifyPackagePlatform({
); );
assertLinuxPackageProviderFailure(unsupportedExecution); assertLinuxPackageProviderFailure(unsupportedExecution);
} else { } else {
const overview = json( const overview = JSON.parse(
await commands.run( await commands.run(
cli, cli,
["analyze", process.execPath, "--provider", "hopper", "--json"], ["analyze", process.execPath, "--provider", "hopper", "--json"],
@@ -26,7 +24,7 @@ export async function verifyPackagePlatform({
throw new Error( throw new Error(
`packaged Hopper-backed analyze CLI failed: ${JSON.stringify(overview)}`, `packaged Hopper-backed analyze CLI failed: ${JSON.stringify(overview)}`,
); );
const inspected = json( const inspected = JSON.parse(
await commands.run( await commands.run(
cli, cli,
["inspect", process.execPath, "--provider", "hopper", "--json"], ["inspect", process.execPath, "--provider", "hopper", "--json"],
@@ -35,7 +33,7 @@ export async function verifyPackagePlatform({
); );
if (!hasPositiveProcedureCount(inspected)) if (!hasPositiveProcedureCount(inspected))
throw new Error("packaged inspect CLI failed"); throw new Error("packaged inspect CLI failed");
const functionResult = json( const functionResult = JSON.parse(
await commands.run( await commands.run(
cli, cli,
[ [
@@ -57,7 +55,7 @@ export async function verifyPackagePlatform({
throw new Error( throw new Error(
`packaged function CLI failed: ${JSON.stringify(functionResult)}`, `packaged function CLI failed: ${JSON.stringify(functionResult)}`,
); );
const xrefs = json( const xrefs = JSON.parse(
await commands.run( await commands.run(
cli, cli,
["xrefs", process.execPath, "0x1000", "--provider", "hopper", "--json"], ["xrefs", process.execPath, "0x1000", "--provider", "hopper", "--json"],
@@ -69,7 +67,7 @@ export async function verifyPackagePlatform({
JSON.stringify(xrefs.normalized_result) !== JSON.stringify(["0x1000"]) JSON.stringify(xrefs.normalized_result) !== JSON.stringify(["0x1000"])
) )
throw new Error(`packaged xrefs CLI failed: ${JSON.stringify(xrefs)}`); throw new Error(`packaged xrefs CLI failed: ${JSON.stringify(xrefs)}`);
const trace = json( const trace = JSON.parse(
await commands.run( await commands.run(
cli, cli,
[ [
@@ -108,7 +106,7 @@ export const isUnsupportedHopperLaunchFailure = (failure) => {
/** Require an exact pre-execution rejection, observed helper exit, or missing-Xvfb diagnostic. */ /** Require an exact pre-execution rejection, observed helper exit, or missing-Xvfb diagnostic. */
export const assertLinuxPackageProviderFailure = (execution) => { export const assertLinuxPackageProviderFailure = (execution) => {
const failure = json(execution.stdout); const failure = JSON.parse(execution.stdout);
const details = failure?.details; const details = failure?.details;
const diagnostic = details?.diagnostics; const diagnostic = details?.diagnostics;
const missingDisplayDependency = const missingDisplayDependency =
+22 -21
View File
@@ -11,7 +11,7 @@ import { dirname, join } from "node:path";
import { TOOL_CONTRACTS } from "../dist/contracts/toolContracts.js"; import { TOOL_CONTRACTS } from "../dist/contracts/toolContracts.js";
import { PRODUCT_IDENTITY } from "../dist/identity.js"; import { PRODUCT_IDENTITY } from "../dist/identity.js";
import { json, pathExists } from "./lib/verify-package-core.mjs"; import { pathExists } from "./lib/verify-package-core.mjs";
import { parse as parseJsonc } from "jsonc-parser"; import { parse as parseJsonc } from "jsonc-parser";
import { skillReferenceIssues } from "./lib/docs-facts.mjs"; import { skillReferenceIssues } from "./lib/docs-facts.mjs";
import { import {
@@ -61,7 +61,7 @@ const verifySetupPlan = async ({
["setup", "--all-detected", "--dry-run", "--json"], ["setup", "--all-detected", "--dry-run", "--json"],
environment, environment,
); );
const planned = json(plannedExecution.stdout); const planned = JSON.parse(plannedExecution.stdout);
if (supportedSetupHost) { if (supportedSetupHost) {
const plannedActions = Array.isArray(planned?.plannedActions) const plannedActions = Array.isArray(planned?.plannedActions)
? planned.plannedActions ? planned.plannedActions
@@ -114,7 +114,7 @@ const verifyAbsentOpenCodeSetup = async ({
["setup", "--yes", "--client", "opencode", "--skill=false", "--json"], ["setup", "--yes", "--client", "opencode", "--skill=false", "--json"],
{ ...environment, XDG_CONFIG_HOME: xdgConfigHome }, { ...environment, XDG_CONFIG_HOME: xdgConfigHome },
); );
const result = json(execution.stdout); const result = JSON.parse(execution.stdout);
const config = JSON.parse(await readFile(configPath, "utf8")); const config = JSON.parse(await readFile(configPath, "utf8"));
if ( if (
execution.status !== 0 || execution.status !== 0 ||
@@ -163,8 +163,8 @@ const verifyAbsentClaudeCodeSetup = async ({
args, args,
childEnvironment, childEnvironment,
); );
const first = json(firstExecution.stdout); const first = JSON.parse(firstExecution.stdout);
const config = json(await readFile(configPath, "utf8")); const config = JSON.parse(await readFile(configPath, "utf8"));
const registration = first.doctor.identity?.registrations?.find( const registration = first.doctor.identity?.registrations?.find(
({ client }) => client === "claude_code", ({ client }) => client === "claude_code",
); );
@@ -186,7 +186,7 @@ const verifyAbsentClaudeCodeSetup = async ({
args, args,
childEnvironment, childEnvironment,
); );
const repeat = json(repeatExecution.stdout); const repeat = JSON.parse(repeatExecution.stdout);
if ( if (
repeatExecution.status !== 0 || repeatExecution.status !== 0 ||
repeat.status !== "ready" || repeat.status !== "ready" ||
@@ -214,13 +214,13 @@ const verifySetupApply = async ({
["setup", "--yes", "--all-detected", "--json"], ["setup", "--yes", "--all-detected", "--json"],
environment, environment,
); );
const first = json(firstExecution.stdout); const first = JSON.parse(firstExecution.stdout);
const alignedExecution = await commands.runWithStatus( const alignedExecution = await commands.runWithStatus(
cli, cli,
["setup", "--all-detected", "--json"], ["setup", "--all-detected", "--json"],
environment, environment,
); );
const aligned = json(alignedExecution.stdout); const aligned = JSON.parse(alignedExecution.stdout);
const secondExecution = await commands.runWithStatus( const secondExecution = await commands.runWithStatus(
cli, cli,
[ [
@@ -236,7 +236,7 @@ const verifySetupApply = async ({
], ],
environment, environment,
); );
const second = json(secondExecution.stdout); const second = JSON.parse(secondExecution.stdout);
if (supportedSetupHost) { if (supportedSetupHost) {
if ( if (
first.status !== status || first.status !== status ||
@@ -267,7 +267,7 @@ const verifySetupApply = async ({
/** Verify the live registration and exact pre-setup backup bytes. */ /** Verify the live registration and exact pre-setup backup bytes. */
export const assertClientConfig = async (cli, configPath, original) => { export const assertClientConfig = async (cli, configPath, original) => {
const config = json(await readFile(configPath, "utf8")); const config = JSON.parse(await readFile(configPath, "utf8"));
if ( if (
config.existing !== true || config.existing !== true ||
config.mcpServers?.rea?.command !== cli || config.mcpServers?.rea?.command !== cli ||
@@ -285,8 +285,7 @@ const assertOpenCodeConfig = async ({
}) => { }) => {
const contents = await readFile(configPath, "utf8"); const contents = await readFile(configPath, "utf8");
const errors = []; const errors = [];
const parsed = parseJsonc(contents, errors, { allowTrailingComma: true }); const config = parseJsonc(contents, errors, { allowTrailingComma: true });
const config = parsed;
const mcp = config?.mcp; const mcp = config?.mcp;
if ( if (
errors.length !== 0 || errors.length !== 0 ||
@@ -357,7 +356,7 @@ const assertAlignedDoctor = async (commands, cli, environment) => {
["doctor", "--json"], ["doctor", "--json"],
environment, environment,
); );
const alignedDoctor = json(alignedDoctorExecution.stdout); const alignedDoctor = JSON.parse(alignedDoctorExecution.stdout);
if ( if (
alignedDoctorExecution.status !== (alignedDoctor.healthy ? 0 : 1) || alignedDoctorExecution.status !== (alignedDoctor.healthy ? 0 : 1) ||
alignedDoctor.identity?.skill?.state !== "aligned" || alignedDoctor.identity?.skill?.state !== "aligned" ||
@@ -425,7 +424,8 @@ const verifySetupFailureRecovery = async ({
["setup", "--yes", "--all-detected", "--json"], ["setup", "--yes", "--all-detected", "--json"],
environment, environment,
); );
const failed = json(failedExecution.stdout); const failed = JSON.parse(failedExecution.stdout);
const cursorAfterFailure = JSON.parse(await readFile(cursorConfig, "utf8"));
if ( if (
failed.status !== "needs_human" || failed.status !== "needs_human" ||
failedExecution.status !== 1 || failedExecution.status !== 1 ||
@@ -433,8 +433,8 @@ const verifySetupFailureRecovery = async ({
failed.appliedActions.length !== 0 || failed.appliedActions.length !== 0 ||
!failed.remediation?.includes("Claude Desktop") || !failed.remediation?.includes("Claude Desktop") ||
(await readFile(claudeConfig, "utf8")) !== "malformed" || (await readFile(claudeConfig, "utf8")) !== "malformed" ||
json(await readFile(cursorConfig, "utf8")).existing !== true || cursorAfterFailure.existing !== true ||
json(await readFile(cursorConfig, "utf8")).mcpServers?.rea !== undefined cursorAfterFailure.mcpServers?.rea !== undefined
) )
throw new Error( throw new Error(
`packaged setup mutated clients after a preflight failure: ${JSON.stringify(failed)}`, `packaged setup mutated clients after a preflight failure: ${JSON.stringify(failed)}`,
@@ -445,11 +445,12 @@ const verifySetupFailureRecovery = async ({
["setup", "--yes", "--all-detected", "--json"], ["setup", "--yes", "--all-detected", "--json"],
environment, environment,
); );
const recovered = json(recoveredExecution.stdout); const recovered = JSON.parse(recoveredExecution.stdout);
if ( if (
recovered.status !== status || recovered.status !== status ||
recoveredExecution.status !== (status === "ready" ? 0 : 1) || recoveredExecution.status !== (status === "ready" ? 0 : 1) ||
json(await readFile(cursorConfig, "utf8")).mcpServers?.rea?.command !== cli JSON.parse(await readFile(cursorConfig, "utf8")).mcpServers?.rea
?.command !== cli
) )
throw new Error("packaged setup did not recover"); throw new Error("packaged setup did not recover");
}; };
@@ -464,7 +465,7 @@ const verifyDanglingSymlink = async ({ commands, cli, environment, home }) => {
["setup", "--yes", "--client", "gemini_cli", "--json"], ["setup", "--yes", "--client", "gemini_cli", "--json"],
environment, environment,
); );
const dangling = json(danglingExecution.stdout); const dangling = JSON.parse(danglingExecution.stdout);
if ( if (
dangling.status !== "needs_human" || dangling.status !== "needs_human" ||
danglingExecution.status !== 1 || danglingExecution.status !== 1 ||
@@ -496,8 +497,8 @@ const verifyUninstall = async ({
["uninstall", "--json"], ["uninstall", "--json"],
environment, environment,
); );
const uninstall = json(uninstallExecution.stdout); const uninstall = JSON.parse(uninstallExecution.stdout);
const cursorAfterUninstall = json(await readFile(cursorTarget, "utf8")); const cursorAfterUninstall = JSON.parse(await readFile(cursorTarget, "utf8"));
const codexAfterUninstall = await readFile(codexTarget, "utf8"); const codexAfterUninstall = await readFile(codexTarget, "utf8");
const openCodeErrors = []; const openCodeErrors = [];
const openCodeAfterUninstall = parseJsonc( const openCodeAfterUninstall = parseJsonc(
+1 -3
View File
@@ -1,5 +1,3 @@
import { json } from "./lib/verify-package-core.mjs";
/** Verify that an unknown --provider is rejected by the packaged CLI. */ /** Verify that an unknown --provider is rejected by the packaged CLI. */
export async function verifyUnknownProvider({ commands, cli, environment }) { export async function verifyUnknownProvider({ commands, cli, environment }) {
const unknownProviderExecution = await commands.runWithStatus( const unknownProviderExecution = await commands.runWithStatus(
@@ -7,7 +5,7 @@ export async function verifyUnknownProvider({ commands, cli, environment }) {
["analyze", process.execPath, "--provider", "missing-provider", "--json"], ["analyze", process.execPath, "--provider", "missing-provider", "--json"],
environment, environment,
); );
const unknownProvider = json(unknownProviderExecution.stdout); const unknownProvider = JSON.parse(unknownProviderExecution.stdout);
if ( if (
unknownProviderExecution.status !== 1 || unknownProviderExecution.status !== 1 ||
unknownProvider.details?.selection_reason !== "unknown_provider" || unknownProvider.details?.selection_reason !== "unknown_provider" ||
+2 -3
View File
@@ -4,7 +4,6 @@ import { readFile, writeFile, mkdir } from "node:fs/promises";
import { dirname, join } from "node:path"; import { dirname, join } from "node:path";
import { pathToFileURL } from "node:url"; import { pathToFileURL } from "node:url";
import { json } from "./lib/verify-package-core.mjs";
import { withVerifierCleanup } from "./lib/verifier-cleanup.mjs"; import { withVerifierCleanup } from "./lib/verifier-cleanup.mjs";
/** Exercise the packaged updater with real npm and a local release registry fixture. */ /** Exercise the packaged updater with real npm and a local release registry fixture. */
@@ -17,7 +16,7 @@ export async function verifyPackageUpdate({
commands, commands,
}) { }) {
const metadataPath = join(packageRoot, "package.json"); const metadataPath = join(packageRoot, "package.json");
const metadata = json(await readFile(metadataPath, "utf8")); const metadata = JSON.parse(await readFile(metadataPath, "utf8"));
const archive = await readFile(tarball); const archive = await readFile(tarball);
const entry = join(packageRoot, "scripts", "rea.mjs"); const entry = join(packageRoot, "scripts", "rea.mjs");
const home = join(workspace, "update-home"); const home = join(workspace, "update-home");
@@ -144,7 +143,7 @@ process.stdout.write(JSON.stringify(result));
if (result.status === "failed") process.exitCode = 1; if (result.status === "failed") process.exitCode = 1;
`, `,
); );
const result = json( const result = JSON.parse(
( (
await commands.exec(process.execPath, [harness], { await commands.exec(process.execPath, [harness], {
env: runtimeEnvironment, env: runtimeEnvironment,
@@ -0,0 +1,83 @@
import { fileURLToPath } from "node:url";
import { expect } from "vitest";
import { z } from "zod";
import { processTest } from "../../support/process/processFixture.js";
const commandsModule = new URL(
"../../../scripts/lib/verify-commands.mjs",
import.meta.url,
).href;
const verifierModule = new URL(
"../../../scripts/lib/verifier-run.mjs",
import.meta.url,
).href;
const repository = fileURLToPath(new URL("../../../", import.meta.url));
const commandOutput = "authored native verifier command completed\n";
const reportSchema = z.object({
command: z.object({ stdout: z.string(), stderr: z.string() }),
verifier: z.object({
process_lineage: z.discriminatedUnion("status", [
z.object({
status: z.literal("verified"),
descendants: z.array(
z.object({
pid: z.number().int().positive(),
parent_pid: z.number().int().positive(),
process_group_id: z.number().int().positive(),
}),
),
}),
z.object({ status: z.literal("unavailable"), reason: z.string() }),
]),
}),
});
// This exercises the public source loader and real command cleanup. The lineage
// receipt is sampled inside the driver before its exit releases loader children.
// Windows has no native Job Object lease for this verifier lineage observation.
processTest.skipIf(process.platform === "win32")(
"releases a cold native verifier source loader before reporting command cleanup complete",
{ timeout: 30_000 },
async ({ processes }) => {
const result = await processes.run(
process.execPath,
[
"--input-type=module",
"-e",
`
import { createVerifierRun, completeVerifierRun } from ${JSON.stringify(verifierModule)};
const run = createVerifierRun();
const { createVerifierCommands } = await import(${JSON.stringify(commandsModule)});
const commands = await createVerifierCommands();
let command;
try {
command = await commands.exec(process.execPath, [
"-e", ${JSON.stringify(`process.stdout.write(${JSON.stringify(commandOutput)})`)},
], { timeout: 5000 });
} finally {
await commands.close();
}
const verifier = await completeVerifierRun(run);
process.stdout.write(JSON.stringify({ command, verifier }));
`,
],
{
cwd: repository,
// Installed tsx reads this switch before choosing its transform cache.
// A fresh process must transform source even when disk cache is warm.
env: { ...process.env, TSX_DISABLE_CACHE: "1" },
timeoutMs: 20_000,
},
);
expect(result.exitCode, result.stderr).toBe(0);
expect(result.signal, result.stderr).toBeNull();
const report = reportSchema.parse(JSON.parse(result.stdout));
expect(report.command).toEqual({ stdout: commandOutput, stderr: "" });
expect(report.verifier.process_lineage).toEqual({
status: "verified",
descendants: [],
});
},
);