#!/usr/bin/env -S node --experimental-strip-types --disable-warning=ExperimentalWarning import { execFileSync, spawnSync } from "node:child_process"; import { createHash } from "node:crypto"; import { chmodSync, cpSync, existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, statSync, symlinkSync, utimesSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join, resolve } from "node:path"; import { createAggregateAssert, finishAggregateAssert } from "./aggregate-assert.mjs"; const assert = createAggregateAssert(); if (process.env.ZERO_NATIVE_TEST_SANDBOX !== "1" && process.env.ZERO_NATIVE_TEST_ALLOW_LOCAL !== "1") { console.error("command contract snapshots emit native test artifacts; run `pnpm run command-contracts` for Vercel Sandbox execution or set ZERO_NATIVE_TEST_ALLOW_LOCAL=1 to opt into local artifacts."); process.exit(1); } const outDir = ".zero/command-contracts"; const execMaxBuffer = 64 * 1024 * 1024; const zeroBin = process.env.ZERO_BIN || (existsSync(".zero/bin/zero") ? resolve(".zero/bin/zero") : resolve("bin/zero")); mkdirSync(outDir, { recursive: true }); function graphSidecarPath(sourcePath: string) { return `${sourcePath.slice(0, -2)}.graph`; } function zero(args, options: { allowFailure?: boolean; env?: Record } = {}) { try { const stdout = execFileSync(zeroBin, args, { encoding: "utf8", maxBuffer: execMaxBuffer, stdio: ["ignore", "pipe", "pipe"], env: options.env ? { ...process.env, ...options.env } : process.env }); return { code: 0, stdout }; } catch (error) { if (!options.allowFailure) throw error; return { code: error.status ?? 1, stdout: error.stdout?.toString() ?? "", stderr: error.stderr?.toString() ?? "", }; } } function zeroWithStderr(args, options: { cwd?: string } = {}) { const result = spawnSync(zeroBin, args, { encoding: "utf8", maxBuffer: execMaxBuffer, stdio: ["ignore", "pipe", "pipe"], cwd: options.cwd }); if (result.error) throw result.error; return { code: result.status ?? 1, stdout: result.stdout ?? "", stderr: result.stderr ?? "" }; } function zeroWithInput(args, input: string, options: { allowFailure?: boolean } = {}) { const result = spawnSync(zeroBin, args, { encoding: "utf8", maxBuffer: execMaxBuffer, input, stdio: ["pipe", "pipe", "pipe"] }); if (result.error) throw result.error; const code = result.status ?? 1; if (code !== 0 && !options.allowFailure) { throw new Error(`zero ${args.join(" ")} exited ${code}: ${result.stderr ?? ""}`); } return { code, stdout: result.stdout ?? "", stderr: result.stderr ?? "" }; } function zeroRaw(args, options: { allowFailure?: boolean; env?: Record } = {}) { try { const stdout = execFileSync(zeroBin, args, { encoding: "utf8", maxBuffer: execMaxBuffer, stdio: ["ignore", "pipe", "pipe"], env: options.env ? { ...process.env, ...options.env } : process.env }); return { code: 0, stdout }; } catch (error) { if (!options.allowFailure) throw error; return { code: error.status ?? 1, stdout: error.stdout?.toString() ?? "", stderr: error.stderr?.toString() ?? "", }; } } function assertPatchOkOutput(stdout: string, expectedSaved?: string) { assert.match(stdout, /^program graph patch ok\n/); if (expectedSaved) { assert.match(stdout, new RegExp(`saved: ${expectedSaved.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\n`)); } assert.match(stdout, /graphHash: graph:[0-9a-f]{16}\n/); assert.match(stdout, /applied: \d+ ops?, \d+ nodes? touched\n/); } function json(args, options = {}) { const result = zero(args, options); return { ...result, body: JSON.parse(result.stdout) }; } function jsonRaw(args, options = {}) { const result = zeroRaw(args, options); return { ...result, body: JSON.parse(result.stdout) }; } function projectionSidecarGraphPath(sourcePath: string) { assert(sourcePath.endsWith(".0"), `projection path must end in .0: ${sourcePath}`); return graphSidecarPath(sourcePath); } function importProjectionSidecar(sourcePath: string) { const graphPath = projectionSidecarGraphPath(sourcePath); assert.equal(zero(["import", "--format", "binary", "--out", graphPath, sourcePath]).stdout, ""); return graphPath; } function assertProjectionCheckOk(sourcePath: string) { const graphPath = importProjectionSidecar(sourcePath); assert.equal(zero(["check", graphPath]).stdout, "ok\n"); } function writeProjectionFile(sourcePath: string, contents: string) { rmSync(projectionSidecarGraphPath(sourcePath), { force: true }); writeFileSync(sourcePath, contents); } function repositoryGraphVerifyScript(root, options: { allowFailure?: boolean; target?: string } = {}) { const args = [ "--experimental-strip-types", "--disable-warning=ExperimentalWarning", "scripts/repository-graph-verify-projection.mts", "--root", root, ]; if (options.target) args.push("--target", options.target); try { const stdout = execFileSync( process.execPath, args, { encoding: "utf8", maxBuffer: execMaxBuffer, stdio: ["ignore", "pipe", "pipe"] }, ); return { code: 0, stdout, stderr: "" }; } catch (error) { if (!options.allowFailure) throw error; return { code: error.status ?? 1, stdout: error.stdout?.toString() ?? "", stderr: error.stderr?.toString() ?? "", }; } } function sha256File(path) { return createHash("sha256").update(readFileSync(path)).digest("hex"); } function assertSourceGraph(body, artifact, moduleIdentity, lowering = "typed-program-graph-mir", canonicalSource = true, sourceProjectionState = undefined) { assert.equal(body.graph.artifact, artifact); assert.equal(body.graph.canonicalSource, canonicalSource); assert.equal(body.graph.moduleIdentity, moduleIdentity); assert.match(body.graph.graphHash, /^graph:[0-9a-f]{16}$/); assert.equal(body.graph.lowering, lowering); if (sourceProjectionState !== undefined) assert.equal(body.graph.sourceProjectionState, sourceProjectionState); } const programGraphParseTreeKeys = new Map(); function assertProgramGraphCompilerInput(body, artifact) { assert(body.compilerCaches.every((cache) => cache.sourceKind === "program-graph" && cache.graphHash === body.graph.graphHash)); assert(body.compilerCaches.every((cache) => cache.parserArtifactsInKey === false)); const caches = new Map(); for (const cache of body.compilerCaches) caches.set(cache.name, cache); const assertCacheInputs = (name, includes, excludes = []) => { const cache = caches.get(name); assert(cache, `missing compiler cache ${name}`); for (const key of includes) assert(cache.graphKeyInputs.includes(key), `${name} cache key inputs should include ${key}`); for (const key of excludes) assert(!cache.graphKeyInputs.includes(key), `${name} cache key inputs should not include ${key}`); }; assertCacheInputs("parseTree", ["graphHash", "stdlibGraph", "nodeHashes", "importPaths", "compilerVersion", "packageDependencies"], ["sourceFiles", "targetFacts", "profile"]); assertCacheInputs("interface", ["graphHash", "modulePaths", "symbolFacts", "importGraph"], ["targetFacts", "profile", "compilerVersion", "packageDependencies"]); assertCacheInputs("checkedBody", ["graphHash", "stdlibGraph", "importPaths", "targetFacts", "compilerVersion", "packageDependencies"], ["sourceFiles", "profile"]); assertCacheInputs("specialization", ["graphHash", "stdlibGraph", "importPaths", "targetFacts", "profile", "compilerVersion", "packageDependencies"], ["sourceFiles"]); if (body.graph.lowering === "mapped-final-mir") { assertCacheInputs("mappedFinalMir", ["graphHash", "stdlibGraph", "importPaths", "targetFacts", "compilerVersion", "packageDependencies", "emitKind", "backend"], ["sourceFiles", "profile"]); const mappedMirCache = caches.get("mappedFinalMir"); assert.match(mappedMirCache.path, /\.zero\/cache\/native\/mir-[0-9a-f]+\.zmir$/); assert.equal(mappedMirCache.memoryMapped, true); assert.equal(mappedMirCache.borrowedStorage, true); assert.equal(mappedMirCache.byteLength > 0, true); assert.equal(typeof mappedMirCache.codegenImmediate, "boolean"); assert.equal(typeof mappedMirCache.programReconstructed, "boolean"); assert.equal(body.incrementalInvalidation.graphInput.mappedFinalMir.path, mappedMirCache.path); assert.equal(body.incrementalInvalidation.graphInput.mappedFinalMir.memoryMapped, true); assert.equal(body.incrementalInvalidation.graphInput.mappedFinalMir.borrowedStorage, true); assert.equal(body.incrementalInvalidation.graphInput.mappedFinalMir.codegenImmediate, mappedMirCache.codegenImmediate); assert.equal(body.incrementalInvalidation.graphInput.mappedFinalMir.programReconstructed, mappedMirCache.programReconstructed); } assertCacheInputs("emittedObject", ["graphHash", "stdlibGraph", "importPaths", "targetFacts", "profile", "compilerVersion", "packageDependencies"], ["sourceFiles"]); const parseTreeCache = caches.get("parseTree"); assert.equal(parseTreeCache.invalidatesOn, "ProgramGraph input"); if (programGraphParseTreeKeys.has(artifact)) assert.equal(parseTreeCache.key, programGraphParseTreeKeys.get(artifact)); else programGraphParseTreeKeys.set(artifact, parseTreeCache.key); assert.equal(body.incrementalInvalidation.sourceKind, "program-graph"); assert.equal(body.incrementalInvalidation.graphInput.artifact, artifact); assert.equal(body.incrementalInvalidation.graphInput.graphHash, body.graph.graphHash); assert.equal(body.incrementalInvalidation.graphInput.parserArtifactsInKey, false); assert(body.incrementalInvalidation.graphInput.keyedBy.includes("graphHash")); assert(body.incrementalInvalidation.graphInput.keyedBy.includes("nodeHashes")); assert(body.incrementalInvalidation.graphInput.keyedBy.includes("typeFacts")); assert(body.incrementalInvalidation.graphInput.keyedBy.includes("symbolFacts")); assert(body.incrementalInvalidation.graphInput.keyedBy.includes("modulePaths")); assert(body.incrementalInvalidation.graphInput.keyedBy.includes("importPaths")); assert.equal(body.incrementalInvalidation.changedInputs.graphArtifact, artifact); assert.equal(body.incrementalInvalidation.interfaceFingerprints.sourceKind, "program-graph"); assert.equal(body.incrementalInvalidation.interfaceFingerprints.graphHash, body.graph.graphHash); } function assertRepositoryGraphNativeCheck(body, sourceProjectionState = "clean", options: { graphHirToMirUsed?: boolean } = {}) { const graphHirToMirUsed = options.graphHirToMirUsed === false ? false : true; assert.equal(body.graphCompiler.input, "repository-graph-store"); assert.equal(body.graphCompiler.graphStoreLoaded, true); assert.equal(body.graphCompiler.sourceProjectionRequiredForCompilerInput, false); assert.equal(body.graphCompiler.sourceProjectionState, sourceProjectionState); assert.equal(body.graphCompiler.graphNativeCheckerUsed, true); assert.equal(body.graphCompiler.graphHirToMirUsed, graphHirToMirUsed); assert.equal(body.graphCompiler.unsupportedGraphFacts.count, 0); assert.equal(body.graphCompiler.resolution.ok, true); assert.equal(body.graphCompiler.resolution.state, "resolved-graph-facts"); assert.equal(body.graphCompiler.checking.ok, true); assert.equal(body.graphCompiler.checking.state, "checked-graph-readiness-facts"); assert.equal(body.graphCompiler.checking.scope, "resolution-package-target-and-graph-mir-readiness"); assert.equal(body.graphCompiler.checking.semanticDiagnosticsEnforced, false); assert.equal(body.graphCompiler.checking.authority, "ProgramGraphStore"); assert.equal(body.graphCompiler.checking.sourceTextAuthority, false); assert.equal(body.graphCompiler.semanticFacts.state, "typed-facts"); assert.equal(body.graphCompiler.semanticFacts.ok, true); const targetReady = body.targetReadiness?.ok === true; const compilerInputReady = targetReady && graphHirToMirUsed; assert.equal(body.graphCompiler.defaultReadiness.compilerInputReady, compilerInputReady); assert.equal(body.graphCompiler.defaultReadiness.claim, compilerInputReady ? "ready-for-repository-graph-input" : "blocked"); assert.equal(body.graphCompiler.defaultReadiness.sourceFreeCompile, compilerInputReady); assert.equal(body.graphCompiler.defaultReadiness.sourceProjectionRequired, false); assert.equal(body.graphCompiler.defaultReadiness.sourceProjectionState, sourceProjectionState); assert.equal(body.graphCompiler.defaultReadiness.graphMir.used, graphHirToMirUsed); assert.equal(Object.hasOwn(body.graphCompiler.defaultReadiness, "fallback"), false); assert.equal(body.graphCompiler.defaultReadiness.performance.validationInLoad, true); assert.equal(body.graphCompiler.defaultReadiness.cacheInvalidation.parserArtifactsInKey, false); assert(body.graphCompiler.defaultReadiness.cacheInvalidation.keyedBy.includes("nodeHashes")); assert(body.graphCompiler.defaultReadiness.cacheInvalidation.keyedBy.includes("symbolFacts")); assert(body.graphCompiler.defaultReadiness.cacheInvalidation.keyedBy.includes("modulePaths")); assert(body.graphCompiler.defaultReadiness.cacheInvalidation.keyedBy.includes("importPaths")); assert.equal(body.graphCompiler.defaultReadiness.targetReadinessOk, targetReady); assert.equal(body.compileTime.deterministic, true); assert.equal(body.targetReadiness.languageOk, true); assert.equal(body.safetyFacts.schemaVersion, 1); } const graphHashPrime = 1099511628211n; const graphHashMask = (1n << 64n) - 1n; function graphHashText(hash, text) { for (const byte of Buffer.from(text ?? "")) { hash ^= BigInt(byte); hash = (hash * graphHashPrime) & graphHashMask; } hash ^= 0xffn; return (hash * graphHashPrime) & graphHashMask; } function graphHashU64(hash, value) { let item = BigInt(value); for (let i = 0n; i < 8n; i++) { hash ^= (item >> (i * 8n)) & 0xffn; hash = (hash * graphHashPrime) & graphHashMask; } return hash; } function graphQuotedField(line, field) { const match = line.match(new RegExp(`(?:^| )${field}:"((?:\\\\.|[^"])*)"`)); return match ? JSON.parse(`"${match[1]}"`) : ""; } function graphBareField(line, field, fallback = "") { const match = line.match(new RegExp(`(?:^| )${field}:([^ ]+)`)); return match ? match[1] : fallback; } function graphTopLevelQuoted(line, field) { const match = line.match(new RegExp(`^${field} "([^"]*)"$`)); return match ? match[1] : ""; } function graphNodeHandle(line) { const match = line.match(/^node (#[A-Za-z0-9_.-]+)/); return match ? match[1] : ""; } function graphNodeKind(line) { const match = line.match(/^node #[A-Za-z0-9_.-]+ ([A-Za-z_][A-Za-z0-9_-]*)/); return match ? match[1] : ""; } function graphStoredModuleIdentity(text) { if (!text) return "module:main"; if (text.startsWith("module:") || text.startsWith("package:")) return text; return `module:${text}`; } function graphEdgeRecord(line) { const match = line.match(/^edge (#[A-Za-z0-9_.-]+) ([A-Za-z_][A-Za-z0-9_-]*) ([^ ]+)/); return { line, from: match?.[1] ?? "", kind: match?.[2] ?? "", to: match?.[3] ?? "", target: graphBareField(line, "target", "node"), order: graphBareField(line, "order", "0"), }; } function graphDomainId(domain, hash) { return `${domain}:${hash.toString(16).padStart(16, "0")}`; } function graphNodeDeclaresSymbol(node) { if (!node?.name) return false; return [ "Module", "Const", "CImport", "TypeAlias", "Shape", "Interface", "Enum", "Choice", "Function", "Param", "Field", "EnumCase", "ChoiceCase", "Let", "ErrorVariant", ].includes(node.kind); } function graphNodeHash(line) { let hash = 1469598103934665603n; hash = graphHashText(hash, graphNodeKind(line)); hash = graphHashText(hash, graphQuotedField(line, "name")); hash = graphHashText(hash, graphQuotedField(line, "type")); hash = graphHashText(hash, graphQuotedField(line, "value")); hash = graphHashU64(hash, graphBareField(line, "public", "false") === "true" ? 1n : 0n); hash = graphHashU64(hash, graphBareField(line, "mutable", "false") === "true" ? 1n : 0n); hash = graphHashU64(hash, graphBareField(line, "static", "false") === "true" ? 1n : 0n); hash = graphHashU64(hash, graphBareField(line, "fallible", "false") === "true" ? 1n : 0n); hash = graphHashU64(hash, graphBareField(line, "exportC", "false") === "true" ? 1n : 0n); return graphDomainId("nodehash", hash); } function graphSymbolComponent(text) { let out = ""; for (const ch of text ?? "") out += /^[A-Za-z0-9._@/-]$/.test(ch) ? ch : "_"; return out || "main"; } function graphIdentityName(identity) { if (identity?.startsWith("module:")) return identity.slice("module:".length); if (identity?.startsWith("package:")) return identity.slice("package:".length); return identity || "main"; } function graphModuleScopeName(moduleIdentity, moduleNode) { const moduleName = moduleNode?.name || graphIdentityName(moduleIdentity); if (moduleIdentity?.startsWith("package:")) return `${graphSymbolComponent(graphIdentityName(moduleIdentity))}/${graphSymbolComponent(moduleName)}`; return graphSymbolComponent(moduleName); } function graphImportBindingName(node) { if (node.value) return node.value; const parts = (node.name ?? "").split("."); return parts.at(-1) || node.name || ""; } function graphSymbolName(node) { return node.kind === "Import" ? graphImportBindingName(node) : (node.name ?? ""); } const graphOwnerKinds = new Set([ "alias", "arg", "arm", "body", "cImport", "case", "choice", "const", "constraint", "declaredType", "default", "effect", "else", "enum", "error", "expr", "field", "function", "guard", "import", "interface", "left", "method", "param", "rangeEnd", "returnType", "right", "shape", "statement", "target", "then", "type", "typeArg", "typeParam", "value", "variant", ]); function graphOwnerEdgeForNode(edges, nodeId) { return edges.find((edge) => edge.target === "node" && edge.to === nodeId && graphOwnerKinds.has(edge.kind)) ?? null; } function graphSymbolOwner(nodesById, edges, node) { let current = node?.id ?? ""; for (let depth = 0; current && depth < nodesById.size; depth++) { const ownerEdge = graphOwnerEdgeForNode(edges, current); if (!ownerEdge) return null; const owner = nodesById.get(ownerEdge.from); if (!owner) return null; if (owner.kind === "Module" || graphNodeDeclaresSymbol(owner)) return owner; current = owner.id; } return null; } function graphNodeSymbolNamespace(node, ownerEdge) { switch (node.kind) { case "Module": return "module"; case "Import": return "import"; case "CImport": return "c-import"; case "Const": return "value"; case "Function": return ownerEdge?.kind === "method" ? "method" : "value"; case "TypeAlias": case "Shape": case "Interface": case "Enum": case "Choice": return "type"; case "Param": return "param"; case "Field": return "field"; case "EnumCase": case "ChoiceCase": case "ErrorVariant": return "variant"; case "Let": return "local"; default: return ""; } } function graphLocalSymbolSuffix(node) { if (node.kind !== "Let") return ""; const suffix = node.id.split(".").at(-1) || node.id; return suffix ? `@${graphSymbolComponent(suffix)}` : ""; } function graphNodeSymbolIdFromGraph(moduleIdentity, nodesById, edges, node, depth = 0) { if (!graphNodeDeclaresSymbol(node) || depth > nodesById.size) return ""; const name = graphSymbolName(node); if (!name) return ""; if (node.kind === "Module") return `symbol:${graphModuleScopeName(moduleIdentity, node)}::module`; const ownerEdge = graphOwnerEdgeForNode(edges, node.id); const owner = graphSymbolOwner(nodesById, edges, node); const namespace = graphNodeSymbolNamespace(node, ownerEdge); if (!namespace) return ""; if (owner?.kind === "Module") { return `symbol:${graphModuleScopeName(moduleIdentity, owner)}::${graphSymbolComponent(namespace)}.${graphSymbolComponent(name)}${graphLocalSymbolSuffix(node)}`; } if (owner) { const ownerSymbol = graphNodeSymbolIdFromGraph(moduleIdentity, nodesById, edges, owner, depth + 1); if (ownerSymbol) return `${ownerSymbol}/${graphSymbolComponent(namespace)}.${graphSymbolComponent(name)}${graphLocalSymbolSuffix(node)}`; } return `symbol:${graphSymbolComponent(graphIdentityName(moduleIdentity))}::${graphSymbolComponent(namespace)}.${graphSymbolComponent(name)}${graphLocalSymbolSuffix(node)}`; } function graphNodeTypeId(line) { const type = graphQuotedField(line, "type"); return type ? graphDomainId("type", graphHashText(1469598103934665603n, type)) : ""; } function graphNodeEffectId(line) { const kind = graphNodeKind(line); const name = graphQuotedField(line, "name"); return kind === "EffectRef" && name ? graphDomainId("effect", graphHashText(1469598103934665603n, name)) : ""; } function recomputeGraphHash(text) { const lines = text.trimEnd().split("\n"); const moduleIdentity = graphStoredModuleIdentity(graphTopLevelQuoted(lines.find((line) => line.startsWith("module ")) ?? "", "module")); const nodeRecords = lines.filter((item) => item.startsWith("node ")).map((line) => ({ line, id: graphNodeHandle(line), kind: graphNodeKind(line), name: graphQuotedField(line, "name"), type: graphQuotedField(line, "type"), value: graphQuotedField(line, "value"), })); const edgeRecords = lines.filter((item) => item.startsWith("edge ")).map(graphEdgeRecord); const nodesById = new Map(nodeRecords.map((node) => [node.id, node])); let hash = 1469598103934665603n; hash = graphHashU64(hash, 1n); hash = graphHashText(hash, moduleIdentity); for (const node of nodeRecords) { const line = node.line; hash = graphHashText(hash, node.id); hash = graphHashText(hash, graphQuotedField(line, "nodeHash") || graphNodeHash(line)); hash = graphHashText(hash, graphQuotedField(line, "symbolId") || graphNodeSymbolIdFromGraph(moduleIdentity, nodesById, edgeRecords, node)); hash = graphHashText(hash, graphQuotedField(line, "typeId") || graphNodeTypeId(line)); hash = graphHashText(hash, graphQuotedField(line, "effectId") || graphNodeEffectId(line)); } for (const edge of edgeRecords) { hash = graphHashText(hash, edge.from); hash = graphHashText(hash, edge.to); hash = graphHashText(hash, edge.kind); hash = graphHashText(hash, edge.target); hash = graphHashU64(hash, edge.order); } return `graph:${hash.toString(16).padStart(16, "0")}`; } function repositoryGraphPayload(storeText) { const marker = "\ngraph\n"; const start = storeText.indexOf(marker); assert.notEqual(start, -1); return storeText.slice(start + marker.length); } function repositoryGraphModuleIdentity(storeText, graphText) { const stored = storeText.match(/^moduleIdentity "([^"]+)"$/m)?.[1]; if (stored) return stored; const moduleLine = graphText.split("\n").find((line) => line.startsWith("module ")) ?? ""; return graphStoredModuleIdentity(graphTopLevelQuoted(moduleLine, "module")); } function graphNodeHasSourceMap(line) { return graphQuotedField(line, "path") !== "" || Number.parseInt(graphBareField(line, "line", "0"), 10) > 0 || Number.parseInt(graphBareField(line, "column", "0"), 10) > 0; } function graphNodeIsDeclaration(kind) { return [ "Import", "CImport", "Const", "TypeAlias", "Shape", "Interface", "Enum", "Choice", "Function", "Param", "Field", "EnumCase", "ChoiceCase", "Let", "ErrorVariant", ].includes(kind); } function graphNodeIsScope(kind) { return [ "Module", "Function", "Block", "Shape", "Interface", "Enum", "Choice", ].includes(kind); } function graphTypeIsCapability(type) { return ["World", "Fs", "File", "Net", "HttpClient"].includes(type); } function graphTypeIsOwnership(type) { return type.includes("owned<") || type.includes("MutSpan<") || type.includes("mutref<"); } function graphTypeIsResource(type) { return ["World", "Fs", "File"].includes(type) || type.includes("owned"); } function repositoryGraphCompilerTableCounts(storeText) { const graphText = repositoryGraphPayload(storeText); const moduleIdentity = repositoryGraphModuleIdentity(storeText, graphText); const nodeLines = graphText.split("\n").filter((line) => line.startsWith("node ")); const edgeLines = graphText.split("\n").filter((line) => line.startsWith("edge ")); const projection = storeText.match(/^projection path:/gm)?.length ?? 0; const counts = { schema: 1, package: moduleIdentity.startsWith("package:") ? 1 : 0, module: 0, declaration: 0, scope: 0, import: 0, symbol: 0, type: 0, effect: 0, capability: 0, ownership: 0, resource: 0, node: nodeLines.length, edge: edgeLines.length, projection, sourceMap: 0, }; for (const line of nodeLines) { const kind = graphNodeKind(line); const type = graphQuotedField(line, "type"); const fallible = graphBareField(line, "fallible", "false") === "true"; const mutable = graphBareField(line, "mutable", "false") === "true"; const node = { id: graphNodeHandle(line), kind, name: graphQuotedField(line, "name"), type, value: graphQuotedField(line, "value"), }; if (kind === "Module") counts.module++; if (graphNodeIsDeclaration(kind)) counts.declaration++; if (graphNodeIsScope(kind)) counts.scope++; if (kind === "Import" || kind === "CImport") counts.import++; if (graphQuotedField(line, "symbolId") || graphNodeDeclaresSymbol(node)) counts.symbol++; if (graphQuotedField(line, "typeId") || type) counts.type++; if (graphQuotedField(line, "effectId") || kind === "EffectRef" || fallible) counts.effect++; if (fallible || graphTypeIsCapability(type)) counts.capability++; if (mutable || graphTypeIsOwnership(type)) counts.ownership++; if (graphTypeIsResource(type)) counts.resource++; if (graphNodeHasSourceMap(line)) counts.sourceMap++; } return counts; } function repositoryGraphCompilerTablesLine(storeText) { const counts = repositoryGraphCompilerTableCounts(storeText); return `compilerTables schema:${counts.schema} package:${counts.package} module:${counts.module} declaration:${counts.declaration} scope:${counts.scope} import:${counts.import} symbol:${counts.symbol} type:${counts.type} effect:${counts.effect} capability:${counts.capability} ownership:${counts.ownership} resource:${counts.resource} node:${counts.node} edge:${counts.edge} projection:${counts.projection} sourceMap:${counts.sourceMap}`; } function refreshRepositoryGraphCompilerMetadata(storeText) { const compilerStoreLine = 'compilerStore schemaVersion:1 shape:"compiler-oriented-tables" semanticOk:true semanticValidity:"shape-valid" sourceProjectionRequired:false sourceMapRequired:false storageInterface:"ProgramGraphStore"'; const compilerHashInputsLine = 'compilerHashInputs graphHashExcludes:"source-path,line,column,projection-text" nodeHashExcludes:"source-path,line,column,projection-text" idCollisionFallbackMayUse:"source-path,line,column"'; return storeText .replace(/^compilerStore .*$/m, compilerStoreLine) .replace(/^compilerTables .*$/m, repositoryGraphCompilerTablesLine(storeText)) .replace(/^compilerHashInputs .*$/m, compilerHashInputsLine); } function repeatBuildHash(args, firstPath, repeatOut, repeatPath = repeatOut) { const repeatArgs = [...args]; const outIndex = repeatArgs.indexOf("--out"); assert(outIndex >= 0, "repeat build args should include --out"); repeatArgs[outIndex + 1] = repeatOut; rmSync(repeatPath, { force: true, recursive: true }); rmSync(`${repeatOut}.exe`, { force: true }); const repeatReport = json(repeatArgs).body; assert.equal(repeatReport.generatedCBytes, 0); assert.equal(repeatReport.cBridgeFallback ?? false, false); assert.equal(sha256File(repeatPath), sha256File(firstPath)); return repeatReport; } function hasAarch64Instruction(bytes, expected) { for (let offset = 0; offset + 4 <= bytes.length; offset++) { if (bytes.readUInt32LE(offset) === expected) return true; } return false; } function hasAarch64CondBranch(bytes, cond) { for (let offset = 0; offset + 4 <= bytes.length; offset++) { const instruction = bytes.readUInt32LE(offset); if ((instruction & 0xff000010) === 0x54000000 && (instruction & 0xf) === cond) return true; } return false; } function hasAarch64VoidReturnEpilogue(bytes) { for (let offset = 0; offset + 12 <= bytes.length; offset++) { if (bytes.readUInt32LE(offset) !== 0x52800000) continue; let cursor = offset + 4; const maybeAddSp = bytes.readUInt32LE(cursor); if (((maybeAddSp & 0xffc003ff) >>> 0) === 0x910003ff) cursor += 4; if (cursor + 8 <= bytes.length && bytes.readUInt32LE(cursor) === 0xa8c17bfd && bytes.readUInt32LE(cursor + 4) === 0xd65f03c0) return true; } return false; } function assertMachOLoadCommand(bytes, expectedCommand, expectedSize) { const ncmds = bytes.readUInt32LE(16); for (let offset = 32, i = 0; i < ncmds; i++) { const cmd = bytes.readUInt32LE(offset); const cmdsize = bytes.readUInt32LE(offset + 4); assert(cmdsize >= 8); assert(offset + cmdsize <= bytes.length); if (cmd === expectedCommand) { if (expectedSize !== undefined) assert.equal(cmdsize, expectedSize); return bytes.subarray(offset, offset + cmdsize); } offset += cmdsize; } assert.fail(`missing Mach-O load command 0x${expectedCommand.toString(16)}`); } function elfPackedErrorBytes(code, flagged = false) { // Raises functions pack (code << 32); world-main envelopes fold the error // flag into the same movabs as (code << 32) | 1, since a separate 32-bit // flag mov would zero-extend over the code. const bytes = Buffer.alloc(10); bytes[0] = 0x48; bytes[1] = 0xb8; bytes.writeBigUInt64LE((BigInt(code) << 32n) | (flagged ? 1n : 0n), 2); return bytes; } function hasAnsiControlBytes(text) { return /\x1b\[[0-9;?]*[ -/]*[@-~]|\x1b\][^\x07]*(?:\x07|\x1b\\)/.test(text); } function removeInlineTests(path) { if (!existsSync(path)) return; const source = readFileSync(path, "utf8"); const testStart = source.indexOf("\n\ntest "); if (testStart >= 0) writeFileSync(path, `${source.slice(0, testStart)}\n`); } function tomlQuote(value: unknown) { return JSON.stringify(String(value)); } function tomlArray(values: unknown[]) { return `[${values.map(tomlQuote).join(", ")}]`; } function appendManifestFields(lines: string[], object: Record, order: string[]) { for (const key of order) { if (!(key in object)) continue; const value = object[key]; if (Array.isArray(value)) lines.push(`${key} = ${tomlArray(value)}`); else if (typeof value === "boolean") lines.push(`${key} = ${value ? "true" : "false"}`); else lines.push(`${key} = ${tomlQuote(value)}`); } } function manifestToml(manifest: Record) { const lines = ["[package]"]; appendManifestFields(lines, manifest.package ?? {}, ["name", "version", "license"]); for (const [targetName, target] of Object.entries(manifest.targets ?? {})) { lines.push("", `[targets.${targetName}]`); appendManifestFields(lines, target as Record, ["kind", "main", "graph", "defaultTarget", "devTarget", "releaseProfile"]); } if (manifest.repositoryGraph) { lines.push("", "[repositoryGraph]"); appendManifestFields(lines, manifest.repositoryGraph, ["compilerInput"]); } for (const sectionName of ["deps", "dependencies"]) { if (!manifest[sectionName]) continue; lines.push("", `[${sectionName}]`); for (const [name, value] of Object.entries(manifest[sectionName])) { if (typeof value === "string") lines.push(`${name} = ${tomlQuote(value)}`); } for (const [name, value] of Object.entries(manifest[sectionName])) { if (typeof value === "string") continue; lines.push("", `[${sectionName}.${name}]`); appendManifestFields(lines, value as Record, ["path", "version", "targets", "target"]); } } for (const [name, lib] of Object.entries(manifest.c?.libs ?? {})) { lines.push("", `[c.libs.${name}]`); appendManifestFields(lines, lib as Record, ["headers", "include", "lib", "link", "mode", "pkg_config", "pkgConfig"]); } return `${lines.join("\n").replace(/\n{3,}/g, "\n\n")}\n`; } function writeZeroTomlSync(root: string, manifest: Record) { writeFileSync(join(root, "zero.toml"), manifestToml(manifest)); } function parseSimpleTomlManifest(text: string) { const manifest: Record = {}; let section: string[] = []; for (const rawLine of text.split(/\r?\n/)) { const line = rawLine.trim(); if (!line || line.startsWith("#")) continue; const sectionMatch = line.match(/^\[([A-Za-z0-9_.-]+)\]$/); if (sectionMatch) { section = sectionMatch[1].split("."); let cursor = manifest; for (const part of section) cursor = cursor[part] ??= {}; continue; } const valueMatch = line.match(/^([A-Za-z0-9_.-]+)\s*=\s*"([^"]*)"$/); if (!valueMatch) continue; let cursor = manifest; for (const part of section) cursor = cursor[part] ??= {}; cursor[valueMatch[1]] = valueMatch[2]; } return manifest; } function readGeneratedManifest(root: string) { const tomlPath = join(root, "zero.toml"); if (existsSync(tomlPath)) return parseSimpleTomlManifest(readFileSync(tomlPath, "utf8")); return JSON.parse(readFileSync(join(root, "zero.json"), "utf8")); } function assertTemplateManifest(kind, manifest, readme) { assert.equal(manifest.package.version, "0.1.0"); assert.equal(manifest.targets.cli.defaultTarget, "linux-musl-x64"); assert.equal(manifest.targets.cli.devTarget, "host"); assert.equal(manifest.targets.cli.releaseProfile, "release-small"); if (manifest.docs) { assert.equal(manifest.docs.readme, "README.md"); assert.deepEqual(manifest.docs.examples, [manifest.targets.cli.main]); } assert.match(readme, /zero check/); assert.match(readme, /zero test/); assert.match(readme, /zero dev --json/); if (kind === "lib") { assert.equal(manifest.targets.cli.main, "src/lib.0"); assert.match(readme, /zero doc --json/); } else { assert.equal(manifest.targets.cli.main, "src/main.0"); assert.match(readme, /zero run/); assert.match(readme, /zero build --target linux-musl-x64/); } } function assertDevReport(report, kind) { assert.equal(report.schemaVersion, 1); assert.equal(report.ok, true); assert.equal(report.mode, "watch-plan"); assert.equal(report.generatedCBytes, 0); assert.equal(report.cBridgeFallback, false); assert.equal(report.watch.planOnly, true); assert.equal(report.watch.manifest, "zero.toml"); assert.deepEqual(report.watch.rerun, ["check", "test", "examples"]); assert(Array.isArray(report.watch.packageLocks)); assert(Array.isArray(report.watch.generatedBindingInputs)); assert.equal(report.watch.restartOnSuccess, kind !== "lib"); assert.equal(report.restart.runnableCli, kind !== "lib"); assert.equal(report.trace.enabled, true); assert.equal(report.trace.requested, false); assert.equal(report.trace.phaseTiming, true); assert.equal(report.trace.cacheFacts, true); assert.equal(report.trace.diagnosticsPassthrough, true); assert.equal(report.partialDiagnostics.stable, true); assert.equal(report.partialDiagnostics.whileCodegenPending, true); assert.equal(report.interfaceFingerprints.algorithm, "fnv1a64-zero-interface-v1"); assert.match(report.interfaceFingerprints.targetFactsHash, /^[0-9a-f]{16}$/); assert(report.interfaceFingerprints.modules.length >= 1); assert.equal(report.incrementalInvalidation.partialDiagnosticsStable, true); assert.match(String(report.incrementalInvalidation.cacheHits), /^\d+$/); assert.match(String(report.incrementalInvalidation.cacheMisses), /^\d+$/); assert(report.actions.some((action) => action.kind === "check")); assert(report.actions.some((action) => action.kind === "test")); assert(report.actions.some((action) => action.kind === "examples")); assert(report.actions.some((action) => action.kind === "restart" && action.enabled === (kind !== "lib"))); } function assertReleaseTargetContract(report, expected) { const contract = report.releaseTargetContract; assert(contract, "release target contract should be present"); assert.equal(contract.schemaVersion, 1); assert.equal(contract.target, expected.target); assert.equal(contract.emit, expected.emit); assert.equal(contract.artifactKind, expected.artifactKind); assert.equal(contract.objectFormat, expected.objectFormat); assert.equal(contract.linkerFlavor, expected.linkerFlavor); assert.equal(contract.libc.targetMode, expected.targetLibcMode); assert.equal(contract.libc.artifactMode, "none"); assert.equal(contract.generatedCBytes, 0); assert.equal(contract.cBridgeFallback, false); assert.equal(contract.fallbackPolicy, "explicit-direct-never-c-bridge"); assert.equal(contract.readiness.status, "supported"); assert.equal(contract.readiness.directArtifact, true); assert.equal(contract.sysroot.requiredByArtifact, false); assert.equal(contract.determinism.repeatBuildHash, "checked-by-command-contracts"); assert(contract.capabilityFacts.some((capability) => capability.name === "memory" && capability.available === true)); } function directExeEmitterForTarget(target: string) { if (target.startsWith("linux") && target.includes("arm64")) return "zero-elf-aarch64-exe"; if (target.startsWith("linux")) return "zero-elf64-exe"; if (target === "darwin-x64") return "zero-macho-x64-exe"; if (target.startsWith("darwin")) return "zero-macho64-exe"; if (target === "win32-arm64.exe") return "zero-coff-aarch64-exe"; if (target.startsWith("win32")) return "zero-coff-x64-exe"; return "direct"; } const generatedCBytesBeforeReadOnlyCommands = json(["size", "--json", "examples/memory-package"]).body.generatedCBytes; assert.match(zero(["--version"]).stdout, /^zero 0\.3\.4 \(build (?:[0-9a-f]{7,40}|unknown)\)\n$/); const version = json(["--version", "--json"]).body; assert.equal(version.schemaVersion, 1); assert.equal(version.version, "0.3.4"); assert.match(version.commit, /^(?:[0-9a-f]{7,40}|unknown)$/); assert.equal(version.backend, "zero-c"); assert.equal(typeof version.host, "string"); assert(version.targets.includes("darwin-arm64")); assert(version.targets.includes("linux-musl-x64")); assert(version.targets.includes("win32-x64.exe")); assert.equal(typeof version.targetCompiler.available, "boolean"); const doctor = json(["doctor", "--json"]).body; assert.equal(doctor.schemaVersion, 1); assert(["ok", "warning", "error"].includes(doctor.status)); assert(doctor.checks.some((check) => check.name === "native-c-compiler")); assert(doctor.checks.some((check) => check.name === "target-c-compiler")); assert(doctor.checks.some((check) => check.name === "llvm-toolchain")); assert(["ready", "tool-missing", "unsupported-target"].includes(doctor.llvmToolchain.status)); assert.equal(typeof doctor.llvmToolchain.compiler, "string"); assert.equal(doctor.llvmToolchain.backendLifecycle.stability, "experimental"); assert.equal(doctor.llvmToolchain.backendLifecycle.defaultEligible, false); assert.equal(doctor.llvmToolchain.backendLifecycle.releaseEligible, false); assert(doctor.checks.some((check) => check.name === "cross-executable-builds" && /non-host executable builds|target-capable C compiler available/.test(check.message))); assert(doctor.checks.some((check) => check.name === "path" && /PATH/.test(check.message))); assert(doctor.checks.some((check) => check.name === "host-target" && /host target/.test(check.message))); assert(doctor.checks.some((check) => check.name === "target-sdk-sysroot" && /sysroot|target-capable C compiler/.test(check.message))); assert(doctor.checks.some((check) => check.name === "docs-examples")); for (const [command, expected] of [ [["--help"], /zero init --template cli hello/], [["check", "--help"], /Usage: zero check/], [["build", "--help"], /Usage: zero build/], [["run", "--help"], /Usage: zero run/], [["test", "--help"], /Usage: zero test/], [["fmt", "--help"], /Usage: zero fmt/], [["init", "--help"], /--template cli\|lib\|package/], [["skills", "--help"], /Usage: zero skills/], [["targets", "--help"], /Usage: zero targets/], [["tokens", "--help"], /Usage: zero tokens/], [["parse", "--help"], /Usage: zero parse/], [["query", "--help"], /Usage: zero query \[--json\] \[--fn \] \[--find \] \[--refs \] \[--calls \] \[--node \] \[--depth \] \[--full\] \[--handles\] \[--no-help\] \[graph-input\|name\]/], [["inspect", "--help"], /Usage: zero init \[--template cli\|lib\|package\] \[project-path\]; zero query\|view\|diff\|dump\|inspect\|validate\|source-map\|roundtrip \[--json\] \[graph-input\]/], [["diff", "--help"], /Usage: zero diff \[--fn \] \[graph-input\]/], [["size", "--help"], /Usage: zero size/], [["explain", "--help"], /Usage: zero explain/], [["fix", "--help"], /Usage: zero fix/], ] as Array<[string[], RegExp]>) { assert.match(zero(command).stdout, expected); } const removedNewCommand = zero(["new", "--help"], { allowFailure: true }); assert.notEqual(removedNewCommand.code, 0); assert.match(removedNewCommand.stdout, /zero init --template cli hello/); const tomlInitRoot = join(outDir, "init-toml-manifest"); rmSync(tomlInitRoot, { recursive: true, force: true }); const tomlInit = json(["init", "--json", "--manifest", "toml", tomlInitRoot]).body; assert.equal(tomlInit.ok, true); assert(tomlInit.writes.includes(join(tomlInitRoot, "zero.toml"))); assert(tomlInit.writes.includes(join(tomlInitRoot, "zero.graph"))); assert(existsSync(join(tomlInitRoot, "zero.toml"))); assert(!existsSync(join(tomlInitRoot, "zero.json"))); assert.match(readFileSync(join(tomlInitRoot, "zero.toml"), "utf8"), /\[package\]/); const defaultInitRoot = join(outDir, "init-default-manifest"); rmSync(defaultInitRoot, { recursive: true, force: true }); const defaultInit = json(["init", "--json", defaultInitRoot]).body; assert.equal(defaultInit.ok, true); assert(defaultInit.writes.includes(join(defaultInitRoot, "zero.toml"))); assert(!existsSync(join(defaultInitRoot, "zero.json"))); for (const [code, goodExample, stalePattern] of [ ["STD003", "var bytes: [4]u8 = [0, 0, 0, 0]", /\bmut bytes\b|std\.mem\.fill bytes/], ["TYP026", "alias Bytes = Span", /\btype [A-Z][A-Za-z0-9_]* =/], ["PUB001", "pub const answer: i32 = 42", /pub const answer (42|i32 42)/], ["IFC002", "fn describe(self: ref) -> String", /type Person\n|fn describe (String|i32)|ret self/], ["IFC003", "fn describe(self: ref) -> String", /fn describe (String|i32)|ret self/], ["IFC004", "fn describe(self: ref) -> String", /fn describe (String|i32)|ret self/], ["IFC005", "fn describe(self: ref) -> String", /fn describe (String|i32)|ret self/], ["STC001", "type Buf {", /type Buf\n|len usize/], ["RCV002", "var vec: FixedVec", /\bmut vec\b|vec\.push 1|use `mut`/], ] as Array<[string, string, RegExp]>) { const explanation = json(["explain", "--json", code]).body; assert.equal(explanation.code, code); assert(explanation.examples.good.includes(goodExample), `${code} explain good example should use canonical source`); assert.doesNotMatch( `${explanation.repair.summary}\n${explanation.examples.bad}\n${explanation.examples.good}`, stalePattern, `${code} explain examples should use canonical source syntax`, ); } // Every diagnostic code the compiler can emit must resolve in `zero explain`. const compilerSourceDir = "native/zero-c/src"; const emittableDiagnosticCodes = new Set(); for (const entry of readdirSync(compilerSourceDir)) { if (!entry.endsWith(".c")) continue; const source = readFileSync(join(compilerSourceDir, entry), "utf8"); for (const match of source.matchAll(/"([A-Z]{3,4}[0-9]{3})"/g)) emittableDiagnosticCodes.add(match[1]); } assert(emittableDiagnosticCodes.size > 100, "expected to discover the compiler diagnostic code catalog"); for (const code of [...emittableDiagnosticCodes].sort()) { const explained = json(["explain", "--json", code], { allowFailure: true }); assert.equal(explained.code, 0, `zero explain ${code} must have an explain entry`); assert.equal(explained.body.code, code, `zero explain ${code} must explain the requested code`); } const graphHelp = zero(["inspect", "--help"]).stdout; assert.match(graphHelp, /zero dump\|validate\|roundtrip \[--json\] \[--format text\|binary\] --out \[graph-input\]; zero import \[--json\] \[--format text\|binary\] --out \[project\|zero\.toml\|zero\.json\|file\.0\]/); assert.match(graphHelp, /zero view \[--json\] \[--fn \[--around \|--handles\]\] \[--outline \] \[--out \] \[graph-input\]/); assert.match(graphHelp, /zero diff \[--fn \] \[graph-input\]/); assert.match(graphHelp, /zero source-map \[--json\] \[graph-input\]/); assert.match(graphHelp, /zero query \[--json\] \[--fn \] \[--find \] \[--refs \] \[--calls \] \[--node \] \[--depth \] \[--full\] \[--handles\] \[--no-help\] \[graph-input\|name\]/); assert.match(graphHelp, /zero reconcile \[--json\] --source /); assert.match(graphHelp, /zero status\|verify-projection \[--json\] \[project\|zero\.toml\|zero\.json\|file\.0\|zero\.graph\]/); assert.match(graphHelp, /zero import \[--json\] \[--format text\|binary\] \[project\|zero\.toml\|zero\.json\|file\.0\]/); assert.match(graphHelp, /zero export \[--json\] \[project\|zero\.toml\|zero\.json\|file\.0\]/); assert.match(graphHelp, /zero merge --base --left --right \[--json\] \[project\|zero\.toml\|zero\.json\|file\.0\]/); assert.match(graphHelp, /zero size \[--json\] \[--target \] \[--out \] \[graph-input\]/); assert.match(graphHelp, /Patch usage: zero patch \[--json\] \[--check-only\|--dry-run\] \[--format text\|binary\] \[--out \] \[graph-input\] \(\|--op \|--replace-fn --body-file \|--replace-in-fn --old --new \|--rewrite --to