feat: qualify Pi runtime cutover foundation

This commit is contained in:
2026-08-22 18:35:13 +08:00
parent fba68e86d9
commit 2bc423ebc5
8 changed files with 3182 additions and 2 deletions

View File

@@ -0,0 +1,322 @@
import { spawn } from 'node:child_process';
import { mkdtemp, mkdir, readFile, readdir, rm, stat, writeFile } from 'node:fs/promises';
import { arch, platform, tmpdir } from 'node:os';
import { dirname, join, relative, resolve, sep } from 'node:path';
import { pathToFileURL } from 'node:url';
import { Arch, Platform, build } from 'electron-builder';
import {
parseProbeArgs,
resolvePiRuntime,
runProbe,
stagePiRuntime,
validatePiIdentity,
validateStagedClosure,
} from './probe-pi-runtime.mjs';
const PRODUCT_NAME = 'MakelorePiProbe';
const ARTIFACT_LABEL = 'controlled-electron-builder-dir-app-asar';
async function pathExists(path) {
try {
await stat(path);
return true;
} catch {
return false;
}
}
function currentTarget() {
let platformTarget;
if (platform() === 'win32') platformTarget = Platform.WINDOWS;
else if (platform() === 'darwin') platformTarget = Platform.MAC;
else if (platform() === 'linux') platformTarget = Platform.LINUX;
else throw new Error(`Unsupported packaging platform: ${platform()}`);
const architecture = Arch[arch()];
if (architecture == null) throw new Error(`Unsupported packaging architecture: ${arch()}`);
return { platformTarget, architecture };
}
async function findPackagedExecutable(root) {
const matches = [];
const visit = async (directory) => {
for (const entry of await readdir(directory, { withFileTypes: true })) {
const path = join(directory, entry.name);
if (entry.isDirectory()) await visit(path);
else if (
(platform() === 'win32' && entry.name === `${PRODUCT_NAME}.exe`)
|| (platform() === 'darwin'
&& entry.name === PRODUCT_NAME
&& directory.endsWith(`${sep}Contents${sep}MacOS`))
|| (platform() === 'linux' && entry.name === PRODUCT_NAME)
) matches.push(path);
}
};
await visit(root);
if (matches.length !== 1) {
throw new Error(`Expected one packaged ${PRODUCT_NAME} executable, found ${matches.length}`);
}
return matches[0];
}
export function packagedResourcesDirectory(executable, currentPlatform = platform()) {
return currentPlatform === 'darwin'
? resolve(executable, '..', '..', 'Resources')
: join(dirname(executable), 'resources');
}
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}`,
));
});
});
}
async function inspectPackagedClosure(executable, resourcesDirectory, assets) {
const script = String.raw`
const fs = require('node:fs');
const path = require('node:path');
const resources = process.env.PI_PROBE_RESOURCES_DIRECTORY;
if (!resources) throw new Error('PI_PROBE_RESOURCES_DIRECTORY is required');
const root = path.join(resources, 'app.asar');
const unpackedRoot = path.join(resources, 'app.asar.unpacked');
const packageJson = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
const shrinkwrap = JSON.parse(fs.readFileSync(path.join(root, 'npm-shrinkwrap.json'), 'utf8'));
const assets = JSON.parse(process.env.PI_PROBE_ASSETS_JSON);
const libc = process.platform === 'linux'
? (process.report?.getReport?.().header?.glibcVersionRuntime ? 'glibc' : 'musl')
: undefined;
const constraintMatches = (constraints, current) => {
if (!constraints || constraints.length === 0 || !current) return true;
const positive = constraints.filter((value) => !value.startsWith('!'));
const negative = constraints.filter((value) => value.startsWith('!')).map((value) => value.slice(1));
return !negative.includes(current) && (positive.length === 0 || positive.includes(current));
};
const supportsCurrentPlatform = (entry) => constraintMatches(entry.os, process.platform)
&& constraintMatches(entry.cpu, process.arch)
&& constraintMatches(entry.libc, libc);
const missingPackages = [];
const relocatedPackages = [];
let expectedPackages = 0;
let platformSkippedPackages = 0;
for (const [packagePath, entry] of Object.entries(shrinkwrap.packages || {})) {
if (!packagePath || entry.dev) continue;
if (!supportsCurrentPlatform(entry)) {
platformSkippedPackages += 1;
continue;
}
expectedPackages += 1;
const exactPath = path.join(root, ...packagePath.split('/'));
if (fs.existsSync(exactPath)) continue;
const nestedMarker = '/node_modules/';
const packageTail = packagePath.includes(nestedMarker)
? packagePath.slice(packagePath.lastIndexOf(nestedMarker) + nestedMarker.length)
: packagePath.slice('node_modules/'.length);
const nameParts = packageTail.split('/');
const packageName = nameParts[0].startsWith('@') ? nameParts.slice(0, 2).join('/') : nameParts[0];
const flattenedPath = path.join(root, 'node_modules', ...packageName.split('/'));
const flattenedPackageJson = path.join(flattenedPath, 'package.json');
if (fs.existsSync(flattenedPackageJson)) {
const flattenedVersion = JSON.parse(fs.readFileSync(flattenedPackageJson, 'utf8')).version;
if (flattenedVersion === entry.version) {
relocatedPackages.push({ from: packagePath, to: 'node_modules/' + packageName, version: entry.version });
continue;
}
}
missingPackages.push(packagePath);
}
const missingAssets = assets.filter((asset) => !fs.existsSync(path.join(root, ...asset.split('/'))));
const missingUnpackedNativeAssets = assets
.filter((asset) => asset.endsWith('.node'))
.filter((asset) => !fs.existsSync(path.join(unpackedRoot, ...asset.split('/'))));
process.stdout.write(JSON.stringify({
packageName: packageJson.name,
packageVersion: packageJson.version,
cliExists: fs.existsSync(path.join(root, 'dist', 'cli.js')),
lockedPackages: Math.max(0, Object.keys(shrinkwrap.packages || {}).length - 1),
expectedPackages,
platformSkippedPackages,
missingPackages,
relocatedPackages,
assetCount: assets.length,
missingAssets,
missingUnpackedNativeAssets,
}));
`;
const { stdout } = await runCommand(executable, ['-e', script], {
env: {
...process.env,
ELECTRON_RUN_AS_NODE: '1',
PI_PROBE_RESOURCES_DIRECTORY: resourcesDirectory,
PI_PROBE_ASSETS_JSON: JSON.stringify(assets),
},
});
const result = JSON.parse(stdout.trim());
if (
!result.cliExists
|| result.missingPackages.length > 0
|| result.missingAssets.length > 0
|| result.missingUnpackedNativeAssets.length > 0
) {
throw new Error(`Packaged Pi closure is incomplete: ${JSON.stringify(result)}`);
}
return result;
}
function assertControlledOutput(projectRoot, outputDirectory) {
const relativePath = relative(projectRoot, outputDirectory);
if (!relativePath || relativePath.startsWith('..') || resolve(projectRoot, relativePath) !== outputDirectory) {
throw new Error(`Refusing uncontrolled packaged-probe output: ${outputDirectory}`);
}
if (relativePath.split(sep).join('/') !== 'release/pi-runtime-probe') {
throw new Error(`Unexpected packaged-probe output directory: ${outputDirectory}`);
}
}
async function buildControlledArtifact(projectRoot, appDirectory, outputDirectory) {
const electronPackage = JSON.parse(await readFile(join(projectRoot, 'node_modules', 'electron', 'package.json'), 'utf8'));
const { platformTarget, architecture } = currentTarget();
const buildResources = join(appDirectory, 'build-resources');
await mkdir(buildResources);
const builderArtifacts = await build({
// Use the staged Pi root as the project root so this controlled probe does
// not inherit Makelore's production hooks or unrelated extraResources.
projectDir: appDirectory,
targets: platformTarget.createTarget('dir', architecture),
publish: 'never',
config: {
appId: 'app.niancode.desktop.pi-probe',
productName: PRODUCT_NAME,
electronVersion: electronPackage.version,
electronDist: join(projectRoot, 'node_modules', 'electron', 'dist'),
directories: {
output: outputDirectory,
buildResources,
},
files: [
'dist/**/*',
'package.json',
'npm-shrinkwrap.json',
'node_modules/**/*',
],
asar: true,
asarUnpack: ['**/*.node'],
npmRebuild: false,
win: {
executableName: PRODUCT_NAME,
signAndEditExecutable: false,
verifyUpdateCodeSignature: false,
},
mac: {
identity: null,
hardenedRuntime: false,
},
linux: {
executableName: PRODUCT_NAME,
},
},
});
return builderArtifacts;
}
export async function runPackagedProbe(options, projectRoot = process.cwd()) {
const resolvedProjectRoot = resolve(projectRoot);
const outputDirectory = resolve(resolvedProjectRoot, 'release', 'pi-runtime-probe');
assertControlledOutput(resolvedProjectRoot, outputDirectory);
const scratchRoot = await mkdtemp(join(tmpdir(), 'makelore-pi-packaged-probe-'));
const appDirectory = join(scratchRoot, 'app');
try {
const sourceRuntime = await resolvePiRuntime(resolvedProjectRoot);
const identity = await validatePiIdentity(sourceRuntime);
await stagePiRuntime(sourceRuntime, appDirectory);
const stagedClosure = await validateStagedClosure(appDirectory);
await rm(outputDirectory, { recursive: true, force: true, maxRetries: 5, retryDelay: 200 });
await mkdir(dirname(outputDirectory), { recursive: true });
const builderArtifacts = await buildControlledArtifact(
resolvedProjectRoot,
appDirectory,
outputDirectory,
);
const executable = await findPackagedExecutable(outputDirectory);
const resourcesDirectory = packagedResourcesDirectory(executable);
const appAsar = join(resourcesDirectory, 'app.asar');
const cliPath = join(appAsar, 'dist', 'cli.js');
if (!await pathExists(appAsar)) throw new Error(`Packaged app.asar is missing: ${appAsar}`);
const packagedClosure = await inspectPackagedClosure(
executable,
resourcesDirectory,
stagedClosure.assets,
);
const runtime = await runProbe({
...options,
reportPath: undefined,
stage: false,
keepStage: false,
electronExecutablePath: executable,
cliPath,
artifactLabel: ARTIFACT_LABEL,
}, resolvedProjectRoot);
const report = {
schemaVersion: 1,
generatedAt: new Date().toISOString(),
identity,
artifact: {
label: ARTIFACT_LABEL,
outputDirectory,
executable,
appAsar,
appAsarUnpacked: join(resourcesDirectory, 'app.asar.unpacked'),
builderArtifacts,
},
stagedClosure,
packagedClosure,
runtime,
result: runtime.result,
decision: 'incomplete',
};
if (options.reportPath) {
await mkdir(dirname(options.reportPath), { recursive: true });
await writeFile(options.reportPath, `${JSON.stringify(report, null, 2)}\n`);
}
return report;
} finally {
await rm(scratchRoot, { recursive: true, force: true, maxRetries: 5, retryDelay: 200 });
}
}
async function main() {
const options = parseProbeArgs(process.argv.slice(2));
if (options.help) {
process.stdout.write('Usage: node scripts/probe-pi-packaged-runtime.mjs [probe options]\n');
return;
}
if (options.stage || options.keepStage || options.electronExecutablePath) {
throw new Error('Packaged probe owns staging and runtime paths; do not pass staging or runtime override flags');
}
const report = await runPackagedProbe(options);
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
if (report.result === 'fail') process.exitCode = 1;
}
const isMain = process.argv[1]
&& pathToFileURL(resolve(process.argv[1])).href === import.meta.url;
if (isMain) {
main().catch((error) => {
process.stderr.write(`${error.stack ?? error.message}\n`);
process.exitCode = 1;
});
}

View File

@@ -0,0 +1,324 @@
import { createServer } from 'node:http';
import { mkdtemp, mkdir, rm, writeFile } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { dirname, join, resolve } from 'node:path';
import { pathToFileURL } from 'node:url';
import {
MAKELore_PROVIDER_PROTOCOLS,
parseProbeArgs,
resolvePiRuntime,
runProviderQualification,
validatePiIdentity,
} from './probe-pi-runtime.mjs';
const LOCAL_API_KEY_ENV = 'PI_PROBE_LOCAL_CONTRACT_KEY';
const LOCAL_API_KEY = 'pi-local-contract-only';
const CUSTOM_HEADER = 'x-makelore-pi-probe';
const IMAGE_BASE64 = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAusB9Y9Z4N8AAAAASUVORK5CYII=';
function readRequestBody(request) {
return new Promise((resolvePromise, reject) => {
const chunks = [];
request.on('data', (chunk) => chunks.push(chunk));
request.once('end', () => {
try {
resolvePromise(JSON.parse(Buffer.concat(chunks).toString('utf8')));
} catch (error) {
reject(error);
}
});
request.once('error', reject);
});
}
function writeSse(response, event) {
if (response.destroyed || response.writableEnded) return;
response.write(`event: ${event.type}\ndata: ${JSON.stringify(event)}\n\n`);
}
function finishResponse(response, events) {
setTimeout(() => {
if (response.destroyed || response.writableEnded) return;
for (const event of events) writeSse(response, event);
response.end();
}, 250);
}
function respondOpenAiCompletions(response, body) {
const id = `chatcmpl-local-${Date.now()}`;
response.writeHead(200, { 'content-type': 'text/event-stream' });
response.write(`data: ${JSON.stringify({
id,
object: 'chat.completion.chunk',
created: Math.floor(Date.now() / 1000),
model: body.model,
choices: [{ index: 0, delta: { role: 'assistant', content: 'PI_PROVIDER_OK' }, finish_reason: null }],
})}\n\n`);
setTimeout(() => {
if (response.destroyed || response.writableEnded) return;
response.write(`data: ${JSON.stringify({
id,
object: 'chat.completion.chunk',
created: Math.floor(Date.now() / 1000),
model: body.model,
choices: [{ index: 0, delta: {}, finish_reason: 'stop' }],
usage: { prompt_tokens: 1, completion_tokens: 1, total_tokens: 2 },
})}\n\n`);
response.end('data: [DONE]\n\n');
}, 250);
}
function responseEnvelope(id, model, status, output = []) {
return {
id,
object: 'response',
created_at: Math.floor(Date.now() / 1000),
status,
model,
output,
error: null,
incomplete_details: null,
usage: status === 'completed'
? {
input_tokens: 1,
input_tokens_details: { cached_tokens: 0 },
output_tokens: 1,
output_tokens_details: { reasoning_tokens: 0 },
total_tokens: 2,
}
: null,
};
}
function respondOpenAiResponses(response, body) {
const id = `resp_local_${Date.now()}`;
const item = {
id: `msg_local_${Date.now()}`,
type: 'message',
status: 'completed',
role: 'assistant',
content: [{ type: 'output_text', text: 'PI_PROVIDER_OK', annotations: [] }],
};
response.writeHead(200, { 'content-type': 'text/event-stream' });
writeSse(response, { type: 'response.created', response: responseEnvelope(id, body.model, 'in_progress') });
writeSse(response, { type: 'response.output_item.added', output_index: 0, item: { ...item, status: 'in_progress', content: [] } });
writeSse(response, {
type: 'response.output_text.delta',
item_id: item.id,
output_index: 0,
content_index: 0,
delta: 'PI_PROVIDER_OK',
});
finishResponse(response, [
{ type: 'response.output_item.done', output_index: 0, item },
{ type: 'response.completed', response: responseEnvelope(id, body.model, 'completed', [item]) },
]);
}
function respondAnthropic(response, body) {
const id = `msg_local_${Date.now()}`;
response.writeHead(200, { 'content-type': 'text/event-stream' });
writeSse(response, {
type: 'message_start',
message: {
id,
type: 'message',
role: 'assistant',
model: body.model,
content: [],
stop_reason: null,
stop_sequence: null,
usage: { input_tokens: 1, output_tokens: 0 },
},
});
writeSse(response, { type: 'content_block_start', index: 0, content_block: { type: 'text', text: '' } });
writeSse(response, { type: 'content_block_delta', index: 0, delta: { type: 'text_delta', text: 'PI_PROVIDER_OK' } });
finishResponse(response, [
{ type: 'content_block_stop', index: 0 },
{
type: 'message_delta',
delta: { stop_reason: 'end_turn', stop_sequence: null },
usage: { output_tokens: 1 },
},
{ type: 'message_stop' },
]);
}
function protocolFromPath(pathname) {
return MAKELore_PROVIDER_PROTOCOLS.find((protocol) => pathname.startsWith(`/${protocol}/`));
}
async function startContractServer(requests) {
const server = createServer(async (request, response) => {
response.once('error', () => undefined);
try {
const body = await readRequestBody(request);
const protocol = protocolFromPath(request.url ?? '');
if (!protocol) {
response.writeHead(404).end();
return;
}
requests.push({
protocol,
method: request.method,
path: request.url,
headers: request.headers,
model: body.model,
hasImage: JSON.stringify(body).includes(IMAGE_BASE64),
});
if (protocol === 'anthropic-messages') respondAnthropic(response, body);
else if (protocol === 'openai-responses') respondOpenAiResponses(response, body);
else respondOpenAiCompletions(response, body);
} catch (error) {
if (!response.headersSent) response.writeHead(400, { 'content-type': 'application/json' });
if (!response.destroyed && !response.writableEnded) {
response.end(JSON.stringify({ error: error instanceof Error ? error.message : String(error) }));
}
}
});
await new Promise((resolvePromise, reject) => {
server.once('error', reject);
server.listen(0, '127.0.0.1', resolvePromise);
});
const address = server.address();
if (!address || typeof address === 'string') throw new Error('Local provider server did not expose a TCP port');
return {
port: address.port,
close: () => new Promise((resolvePromise, reject) => {
server.close((error) => (error ? reject(error) : resolvePromise()));
}),
};
}
function expectedPath(protocol) {
const endpoint = protocol === 'openai-responses'
? 'responses'
: protocol === 'anthropic-messages'
? 'messages'
: 'chat/completions';
return `/${protocol}/v1/${endpoint}`;
}
function validateCapturedRequests(protocol, modelId, requests) {
const matching = requests.filter((request) => request.protocol === protocol);
const authHeader = protocol === 'anthropic-messages' ? 'x-api-key' : 'authorization';
const expectedAuth = protocol === 'anthropic-messages' ? LOCAL_API_KEY : `Bearer ${LOCAL_API_KEY}`;
const problems = [];
if (matching.length !== 4) problems.push(`expected 4 requests, got ${matching.length}`);
if (matching.some((request) => request.method !== 'POST')) problems.push('non-POST request');
if (matching.some((request) => request.path !== expectedPath(protocol))) problems.push('unexpected endpoint path');
if (matching.some((request) => request.headers[authHeader] !== expectedAuth)) problems.push('credential header mismatch');
if (matching.some((request) => request.headers[CUSTOM_HEADER] !== protocol)) problems.push('custom header mismatch');
if (matching.some((request) => request.model !== modelId)) problems.push('model mismatch');
if (matching.filter((request) => request.hasImage).length < 2) problems.push('image payload missing from initial turns');
if (problems.length > 0) throw new Error(`${protocol} local contract failed: ${problems.join('; ')}`);
return {
requestCount: matching.length,
method: 'POST',
path: expectedPath(protocol),
credentialHeader: authHeader,
customHeader: CUSTOM_HEADER,
modelId,
imageRequests: matching.filter((request) => request.hasImage).length,
};
}
export async function runLocalProviderContracts(options, projectRoot = process.cwd()) {
const scratchRoot = await mkdtemp(join(tmpdir(), 'makelore-pi-provider-contracts-'));
const requests = [];
const previousApiKey = process.env[LOCAL_API_KEY_ENV];
const server = await startContractServer(requests);
process.env[LOCAL_API_KEY_ENV] = LOCAL_API_KEY;
try {
const sourceRuntime = await resolvePiRuntime(projectRoot);
const identity = await validatePiIdentity(sourceRuntime);
const runtime = options.electronExecutablePath
? {
...sourceRuntime,
electronExecutable: options.electronExecutablePath,
cliPath: options.cliPath,
}
: sourceRuntime;
const imagePath = join(scratchRoot, 'pixel.png');
await writeFile(imagePath, Buffer.from(IMAGE_BASE64, 'base64'));
const protocols = [];
for (const protocol of MAKELore_PROVIDER_PROTOCOLS) {
const protocolRoot = join(scratchRoot, protocol);
await mkdir(protocolRoot);
const fixturePath = join(protocolRoot, 'fixture.json');
const modelId = `makelore-local-${protocol}`;
const baseUrl = protocol === 'anthropic-messages'
? `http://127.0.0.1:${server.port}/${protocol}`
: `http://127.0.0.1:${server.port}/${protocol}/v1`;
await writeFile(fixturePath, `${JSON.stringify({
id: `makelore-local-${protocol}`,
apiProtocol: protocol,
baseUrl,
apiKeyEnv: LOCAL_API_KEY_ENV,
headers: { [CUSTOM_HEADER]: protocol },
model: { id: modelId, input: ['text', 'image'] },
}, null, 2)}\n`);
const qualification = await runProviderQualification(
runtime,
protocolRoot,
fixturePath,
imagePath,
options.timeoutMs,
);
protocols.push({
protocol,
qualification,
requestContract: validateCapturedRequests(protocol, modelId, requests),
});
}
const report = {
schemaVersion: 1,
generatedAt: new Date().toISOString(),
identity,
runtime: {
artifact: options.artifactLabel ?? 'workspace-install',
executable: runtime.electronExecutable,
cliPath: runtime.cliPath,
},
scope: {
network: '127.0.0.1 only',
realProvider: false,
limitation: 'Validates Pi HTTP/SSE request contracts and worker behavior; does not qualify a real provider account.',
},
protocols,
result: 'pass',
};
if (options.reportPath) {
await mkdir(dirname(options.reportPath), { recursive: true });
await writeFile(options.reportPath, `${JSON.stringify(report, null, 2)}\n`);
}
return report;
} finally {
if (previousApiKey === undefined) delete process.env[LOCAL_API_KEY_ENV];
else process.env[LOCAL_API_KEY_ENV] = previousApiKey;
await server.close();
await rm(scratchRoot, { recursive: true, force: true, maxRetries: 5, retryDelay: 200 });
}
}
async function main() {
const options = parseProbeArgs(process.argv.slice(2));
if (options.help) {
process.stdout.write('Usage: node scripts/probe-pi-provider-contracts.mjs [probe options]\n');
return;
}
if (options.stage || options.keepStage || options.providerFixturePath || options.imagePath) {
throw new Error('Local provider contract probe owns its fixtures and does not accept staging/provider fixture flags');
}
const report = await runLocalProviderContracts(options);
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
}
const isMain = process.argv[1]
&& pathToFileURL(resolve(process.argv[1])).href === import.meta.url;
if (isMain) {
main().catch((error) => {
process.stderr.write(`${error.stack ?? error.message}\n`);
process.exitCode = 1;
});
}

1102
scripts/probe-pi-runtime.mjs Normal file

File diff suppressed because it is too large Load Diff