import { spawn } from 'node:child_process'; import { readFile, readdir, stat } from 'node:fs/promises'; import { arch as hostArch, platform as hostPlatform } from 'node:os'; import { dirname, isAbsolute, join, relative, resolve, sep, } from 'node:path'; import YAML from 'yaml'; import { PI_RUNTIME_CLI_ENTRY, PI_RUNTIME_MANIFEST, PI_RUNTIME_PACKAGE, PI_RUNTIME_VERSION, } from './pi-runtime-bundle.mjs'; import { inspectPackagedClosure, packagedResourcesDirectory, } from '../probe-pi-packaged-runtime.mjs'; const PRODUCT_NAME = 'Makelore'; const LINUX_EXECUTABLE_NAME = 'niancode'; const EXTENSION_CONTRACT_MARKERS = Object.freeze([ 'Makelore runtime bridge rejected the request', 'subagent.dispatch', 'makelore.write-lease', 'MAKELORE_PI_BRIDGE_URL', ]); const PI_AI_PROVIDER_PREFIX = 'pi-runtime/node_modules/@earendil-works/pi-ai/dist/providers/'; async function pathExists(path) { try { await stat(path); return true; } catch { return false; } } function portable(path) { return path.split(sep).join('/'); } function normalizeLockedVersion(value) { return typeof value === 'string' ? value.split('(', 1)[0] : null; } function runCommand(executable, args, options = {}) { return new Promise((resolvePromise, reject) => { const child = spawn(executable, args, { cwd: options.cwd, env: options.env ?? process.env, stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true, }); let stdout = ''; let stderr = ''; child.stdout.on('data', (chunk) => { stdout += chunk.toString(); }); child.stderr.on('data', (chunk) => { stderr += chunk.toString(); }); child.once('error', reject); child.once('exit', (code, signal) => { if (code === 0) resolvePromise({ stdout, stderr }); else reject(new Error( `${executable} exited with code ${code ?? 'null'} signal ${signal ?? 'none'}: ${stderr || stdout}`, )); }); }); } export function defaultProductExecutable(projectRoot, currentPlatform = hostPlatform()) { const root = resolve(projectRoot); if (currentPlatform === 'win32') { return join(root, 'release', 'win-unpacked', `${PRODUCT_NAME}.exe`); } if (currentPlatform === 'darwin') { return join(root, 'release', 'mac', `${PRODUCT_NAME}.app`, 'Contents', 'MacOS', PRODUCT_NAME); } if (currentPlatform === 'linux') { return join(root, 'release', 'linux-unpacked', LINUX_EXECUTABLE_NAME); } throw new Error(`Unsupported product artifact platform: ${currentPlatform}`); } export function assertNodeEngineCompatible(engine, nodeVersion) { const match = /^>=(\d+)\.(\d+)\.(\d+)$/.exec(engine ?? ''); if (!match) throw new Error(`Unsupported Pi Node engine expression: ${engine ?? 'missing'}`); const required = match.slice(1).map(Number); const actualMatch = /^(\d+)\.(\d+)\.(\d+)/.exec(nodeVersion ?? ''); if (!actualMatch) throw new Error(`Invalid packaged Node version: ${nodeVersion ?? 'missing'}`); const actual = actualMatch.slice(1).map(Number); for (let index = 0; index < required.length; index += 1) { if (actual[index] > required[index]) return; if (actual[index] < required[index]) { throw new Error(`Packaged Node ${nodeVersion} does not satisfy Pi engine ${engine}`); } } } export function validatePiArtifactMetadata({ rootPackage, lockfile, packagedPackage, runtimePackage, manifest, runtimePlatform, }) { const rootDependency = rootPackage.dependencies?.[PI_RUNTIME_PACKAGE]; const packagedDependency = packagedPackage.dependencies?.[PI_RUNTIME_PACKAGE]; const lockDependency = lockfile.importers?.['.']?.dependencies?.[PI_RUNTIME_PACKAGE]; const lockedVersion = normalizeLockedVersion(lockDependency?.version); const versions = { expected: PI_RUNTIME_VERSION, rootDependency, packagedDependency, lockSpecifier: lockDependency?.specifier ?? null, lockedVersion, runtimePackage: runtimePackage.version, manifest: manifest.runtime?.version ?? null, }; const mismatched = Object.entries(versions) .filter(([key, value]) => key !== 'expected' && value !== PI_RUNTIME_VERSION); if (mismatched.length > 0) { throw new Error(`Pi artifact versions do not match: ${JSON.stringify(versions)}`); } if (runtimePackage.name !== PI_RUNTIME_PACKAGE) { throw new Error(`Packaged Pi package name is ${runtimePackage.name ?? 'missing'}`); } if (runtimePackage.bin?.pi !== PI_RUNTIME_CLI_ENTRY) { throw new Error(`Packaged Pi CLI entry is ${runtimePackage.bin?.pi ?? 'missing'}`); } if (manifest.runtime?.packageName !== PI_RUNTIME_PACKAGE || manifest.runtime?.cliEntry !== PI_RUNTIME_CLI_ENTRY) { throw new Error(`Packaged Pi manifest identity is invalid: ${JSON.stringify(manifest.runtime)}`); } if (manifest.target?.platform !== runtimePlatform.platform || manifest.target?.arch !== runtimePlatform.arch) { throw new Error( `Packaged Pi target ${manifest.target?.platform ?? 'missing'}-${manifest.target?.arch ?? 'missing'} ` + `does not match executable ${runtimePlatform.platform}-${runtimePlatform.arch}`, ); } assertNodeEngineCompatible(manifest.runtime?.nodeEngine, runtimePlatform.node); return versions; } export function collectAbsoluteManifestValues(value, at = '$', results = []) { if (typeof value === 'string') { if (isAbsolute(value) || /^[A-Za-z]:[\\/]/.test(value)) results.push({ at, value }); return results; } if (Array.isArray(value)) { value.forEach((entry, index) => collectAbsoluteManifestValues(entry, `${at}[${index}]`, results)); return results; } if (value && typeof value === 'object') { for (const [key, entry] of Object.entries(value)) { collectAbsoluteManifestValues(entry, `${at}.${key}`, results); } } return results; } export async function collectForbiddenResourcePaths(root, pattern = /opencode/i) { const matches = []; const visit = async (directory) => { if (!await pathExists(directory)) return; for (const entry of await readdir(directory, { withFileTypes: true })) { const path = join(directory, entry.name); if (pattern.test(entry.name)) matches.push(portable(relative(root, path))); if (entry.isDirectory()) await visit(path); } }; await visit(root); return matches.sort(); } export function classifyOpenCodeResourcePaths(paths) { const upstreamPiProvider = paths.filter((path) => path.startsWith(PI_AI_PROVIDER_PREFIX)); const productOwned = paths.filter((path) => !path.startsWith(PI_AI_PROVIDER_PREFIX)); return { productOwned, upstreamPiProvider }; } async function filesContainingNeedles(root, needles) { const matches = []; const visit = async (path) => { const details = await stat(path); if (details.isDirectory()) { for (const entry of await readdir(path, { withFileTypes: true })) { await visit(join(path, entry.name)); } return; } const contents = await readFile(path); const found = needles.filter((needle) => needle.length > 0 && contents.includes(needle)); if (found.length > 0) matches.push({ path, needles: found.map((value) => value.toString()) }); }; await visit(root); return matches; } async function inspectProductRuntime(executable, resourcesDirectory) { const script = String.raw` const { createRequire } = require('node:module'); const path = require('node:path'); const resources = process.env.MAKELORE_PI_PRODUCT_RESOURCES; const appRequire = createRequire(path.join(resources, 'app.asar', 'package.json')); const packagedPackage = appRequire('./package.json'); process.stdout.write(JSON.stringify({ platform: process.platform, arch: process.arch, node: process.versions.node, electron: process.versions.electron, packagedPackage, })); `; const { stdout } = await runCommand(executable, ['-e', script], { env: { ...process.env, ELECTRON_RUN_AS_NODE: '1', MAKELORE_PI_PRODUCT_RESOURCES: resourcesDirectory, }, }); return JSON.parse(stdout.trim()); } async function packagedSkillIds(resourcesDirectory) { const root = join(resourcesDirectory, 'resources', 'coding-skills'); if (!await pathExists(root)) throw new Error(`Packaged coding skills are missing: ${root}`); const entries = await readdir(root, { withFileTypes: true }); const ids = []; for (const entry of entries) { if (!entry.isDirectory()) continue; if (!await pathExists(join(root, entry.name, 'SKILL.md'))) { throw new Error(`Packaged coding skill has no SKILL.md: ${entry.name}`); } ids.push(entry.name); } return ids.sort(); } async function sourceSkillIds(projectRoot) { const root = join(projectRoot, 'resources', 'coding-skills'); const entries = await readdir(root, { withFileTypes: true }); return entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort(); } export async function verifyPiProductArtifact({ projectRoot, executable }) { const root = resolve(projectRoot); const appExecutable = resolve(executable ?? defaultProductExecutable(root)); if (!await pathExists(appExecutable)) throw new Error(`Product executable is missing: ${appExecutable}`); const resourcesDirectory = packagedResourcesDirectory(appExecutable); const runtimeRoot = join(resourcesDirectory, 'pi-runtime'); const appAsar = join(resourcesDirectory, 'app.asar'); for (const required of [runtimeRoot, appAsar]) { if (!await pathExists(required)) throw new Error(`Product artifact resource is missing: ${required}`); } const [rootPackageSource, lockfileSource, runtimePackageSource, manifestSource] = await Promise.all([ readFile(join(root, 'package.json'), 'utf8'), readFile(join(root, 'pnpm-lock.yaml'), 'utf8'), readFile(join(runtimeRoot, 'package.json'), 'utf8'), readFile(join(runtimeRoot, PI_RUNTIME_MANIFEST), 'utf8'), ]); const rootPackage = JSON.parse(rootPackageSource); const lockfile = YAML.parse(lockfileSource); const runtimePackage = JSON.parse(runtimePackageSource); const manifest = JSON.parse(manifestSource); const runtimePlatform = await inspectProductRuntime(appExecutable, resourcesDirectory); const versions = validatePiArtifactMetadata({ rootPackage, lockfile, packagedPackage: runtimePlatform.packagedPackage, runtimePackage, manifest, runtimePlatform, }); const absoluteManifestValues = collectAbsoluteManifestValues(manifest); if (absoluteManifestValues.length > 0) { throw new Error(`Pi runtime manifest contains absolute paths: ${JSON.stringify(absoluteManifestValues)}`); } const openCodeResourcePaths = classifyOpenCodeResourcePaths( await collectForbiddenResourcePaths(resourcesDirectory), ); if (openCodeResourcePaths.productOwned.length > 0) { throw new Error( `Product-owned resources contain OpenCode paths: ${openCodeResourcePaths.productOwned.join(', ')}`, ); } const expectedSkills = await sourceSkillIds(root); const actualSkills = await packagedSkillIds(resourcesDirectory); if (JSON.stringify(actualSkills) !== JSON.stringify(expectedSkills)) { throw new Error(`Packaged coding skills differ: expected ${expectedSkills}, got ${actualSkills}`); } const appAsarContents = await readFile(appAsar); const missingExtensionMarkers = EXTENSION_CONTRACT_MARKERS.filter( (marker) => !appAsarContents.includes(Buffer.from(marker)), ); if (missingExtensionMarkers.length > 0) { throw new Error( `Packaged app.asar does not contain Pi extension contract markers: ${missingExtensionMarkers.join(', ')}`, ); } const sourceNeedles = [ Buffer.from(root), Buffer.from(portable(root)), ]; const devPathResidue = [ ...await filesContainingNeedles(appAsar, sourceNeedles), ...await filesContainingNeedles(runtimeRoot, sourceNeedles), ]; if (devPathResidue.length > 0) { throw new Error(`Product artifact contains development path residue: ${JSON.stringify(devPathResidue)}`); } const packagedClosure = await inspectPackagedClosure( appExecutable, resourcesDirectory, manifest.runtimeAssets, ); return { schemaVersion: 1, artifact: { executable: appExecutable, resourcesDirectory, appAsar, runtimeRoot, cliPath: join(runtimeRoot, ...PI_RUNTIME_CLI_ENTRY.split('/')), }, platform: { platform: runtimePlatform.platform, arch: runtimePlatform.arch, electron: runtimePlatform.electron, node: runtimePlatform.node, }, versions, manifest: { target: manifest.target, packageCount: manifest.productionPackages.length, assetCount: manifest.runtimeAssets.length, nodeEngine: manifest.runtime.nodeEngine, }, packagedClosure, extension: { contractMarkers: EXTENSION_CONTRACT_MARKERS, packaged: true, executionProof: 'smoke:pi:real final-product extension/subagent run', }, skills: actualSkills, openCodeResourcePaths: { ...openCodeResourcePaths, upstreamDecision: openCodeResourcePaths.upstreamPiProvider.length > 0 ? 'retained-required-files-from-exact-pinned-pi-production-package' : 'none', }, developmentPathResidue: [], result: 'pass', }; } export const PI_PRODUCT_ARTIFACT_DEFAULTS = Object.freeze({ platform: hostPlatform(), arch: hostArch(), extensionContractMarkers: EXTENSION_CONTRACT_MARKERS, });