mirror of
https://github.com/morluto/rea.git
synced 2026-10-26 17:35:11 +00:00
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:
1 parent
791524c2fa
commit
48ff37f6ea
14 files changed
+149
-80
No files matched your search
@@ -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,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 } =
|
||||||
|
|||||||
@@ -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"],
|
||||||
|
|||||||
@@ -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,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,
|
||||||
|
|||||||
@@ -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,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,
|
||||||
|
|||||||
@@ -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"],
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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 =
|
||||||
|
|||||||
@@ -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,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" ||
|
||||||
|
|||||||
@@ -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: [],
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
Reference in new issue
Block a user