Files
makelore/scripts/run-pi-subagent-packaged-smoke.mjs

651 lines
28 KiB
JavaScript

#!/usr/bin/env node
import { _electron as electron } from '@playwright/test';
import { execFile } from 'node:child_process';
import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';
import { createServer } from 'node:net';
import { tmpdir } from 'node:os';
import { dirname, join, resolve } from 'node:path';
import { pathToFileURL } from 'node:url';
import { performance } from 'node:perf_hooks';
import { promisify } from 'node:util';
import { defaultProductExecutable } from './lib/pi-product-artifact.mjs';
const execFileAsync = promisify(execFile);
function parseArgs(argv, projectRoot = process.cwd()) {
const options = {
projectRoot: resolve(projectRoot),
runtimeRoot: undefined,
electronExecutable: undefined,
reportPath: undefined,
verifyCleanupFailure: true,
};
for (let index = 0; index < argv.length; index += 1) {
const argument = argv[index];
if (argument === '--') continue;
const value = argv[index + 1];
if (!value || value.startsWith('--')) throw new Error(`${argument} requires a value`);
if (argument === '--runtime-root') options.runtimeRoot = resolve(value);
else if (argument === '--electron-executable') options.electronExecutable = resolve(value);
else if (argument === '--report') options.reportPath = resolve(value);
else throw new Error(`Unknown argument: ${argument}`);
index += 1;
}
options.electronExecutable ??= defaultProductExecutable(options.projectRoot);
return options;
}
async function allocatePort() {
return await new Promise((resolvePort, reject) => {
const server = createServer();
server.once('error', reject);
server.listen(0, '127.0.0.1', () => {
const address = server.address();
if (!address || typeof address === 'string') {
server.close(() => reject(new Error('Failed to allocate PI proof Host API port')));
return;
}
server.close((error) => error ? reject(error) : resolvePort(address.port));
});
});
}
function assertPackagedMain(result) {
if (result?.packagedMain?.isPackaged !== true || result?.packagedMain?.appPathUsesAsar !== true) {
throw new Error(`PI proof did not execute from packaged app.asar Main: ${JSON.stringify(result?.packagedMain)}`);
}
}
function assertActivePressure(pressure) {
const expected = {
parentWorkers: 4,
childWorkers: 4,
parentProcesses: 4,
childProcesses: 4,
liveProcesses: 8,
parentProviderRequests: 4,
childProviderRequests: 4,
processBudget: 8,
childPermits: 4,
dispatches: 4,
writeLeases: 4,
};
const actual = {
parentWorkers: pressure?.parentWorkers,
childWorkers: pressure?.childWorkers,
parentProcesses: pressure?.parentProcessIds?.length,
childProcesses: pressure?.childProcessIds?.length,
liveProcesses: pressure?.liveProcessIds?.length,
parentProviderRequests: pressure?.providerRequests?.parent,
childProviderRequests: pressure?.providerRequests?.child,
processBudget: pressure?.processBudget?.active,
childPermits: pressure?.childPermits?.active,
dispatches: pressure?.dispatches?.active,
writeLeases: pressure?.writeLeases?.active,
};
if (JSON.stringify(actual) !== JSON.stringify(expected)) {
throw new Error(`PI pressure did not reach 4 parent + 4 child state: ${JSON.stringify(actual)}`);
}
}
function assertReleasedPressure(pressure) {
const counts = [
pressure?.parentWorkers,
pressure?.childWorkers,
pressure?.parentProcessIds?.length,
pressure?.childProcessIds?.length,
pressure?.liveProcessIds?.length,
pressure?.providerRequests?.parent,
pressure?.providerRequests?.child,
pressure?.processBudget?.active,
pressure?.processBudget?.waiting,
pressure?.childPermits?.active,
pressure?.childPermits?.waiting,
pressure?.dispatches?.active,
pressure?.dispatches?.parents,
pressure?.writeLeases?.active,
pressure?.writeLeases?.waiting,
];
if (counts.some((value) => value !== 0)) {
throw new Error(`PI pressure resources were not fully released: ${JSON.stringify(pressure)}`);
}
}
function assertManagedTurns(extension) {
const expectedMilestones = 'worker.queue_wait,resources.ready,worker.spawn,rpc.ready,session.open,prompt.accepted,agent.start,provider.first_event,agent.settled';
const expectedDelayMs = extension?.providerFirstEventDelayMs;
if (!Number.isFinite(expectedDelayMs) || expectedDelayMs < 1) {
throw new Error(`PI proof did not expose a controlled Provider first-event delay: ${expectedDelayMs}`);
}
for (const turn of extension?.managedTurns ?? []) {
if (turn.milestones.map(({ milestone }) => milestone).join(',') !== expectedMilestones) {
throw new Error(`PI managed turn timeline is incomplete: ${JSON.stringify(turn)}`);
}
const agentStart = turn.milestones.find(({ milestone }) => milestone === 'agent.start');
const providerFirstEvent = turn.milestones.find(({ milestone }) => milestone === 'provider.first_event');
if (agentStart?.source !== 'pi.agent_start'
|| providerFirstEvent?.source !== 'pi.assistant_message_start'
|| providerFirstEvent.at <= agentStart.at
|| providerFirstEvent.durationMs < Math.floor(expectedDelayMs * 0.75)) {
throw new Error(`PI Provider first-event milestone is not Provider-response-backed: ${JSON.stringify(turn)}`);
}
}
}
function assertProxyStatus(status) {
if (status?.currentHostTokenAvailable !== true
|| status?.realTurnVerified !== false
|| status?.activeProviderRequests?.child !== 1
|| status?.providerRequests?.parent < 1
|| status?.providerRequests?.child !== 1
|| status?.processes?.supported !== true
|| status?.processes?.parent?.length !== 1
|| status?.processes?.child?.length !== 1
|| Object.values(status?.tokenSafety ?? {}).some((safe) => safe !== true)) {
throw new Error(`Packaged Main proxy status is incomplete: ${JSON.stringify(status)}`);
}
}
function assertProxyProof(proof) {
if (proof?.providerMode !== 'loopback-through-authenticated-host-proxy'
|| proof?.realTurnVerified !== false
|| proof?.firstConversation?.count !== 1
|| proof?.firstConversation?.bindingEstablished !== true
|| proof?.firstConversation?.workerStatus !== 'ready'
|| proof?.firstConversation?.runStatus !== 'idle'
|| proof?.firstConversation?.userInputProjected !== true
|| proof?.firstConversation?.parentResponseProjected !== true
|| proof?.currentHostTokenUsedBy?.join(',') !== 'parent,child'
|| proof?.released?.workers !== 0
|| Object.values(proof?.tokenSafety ?? {}).some((safe) => safe !== true)) {
throw new Error(`Packaged Main proxy proof failed: ${JSON.stringify(proof)}`);
}
}
async function waitForActiveProxyProof(electronApplication) {
const deadline = Date.now() + 30_000;
let latest;
while (Date.now() < deadline) {
latest = await evaluateProof(electronApplication, 'proxy.status');
if (latest?.proxy?.activeProviderRequests?.child === 1
&& latest?.proxy?.processes?.parent?.length === 1
&& latest?.proxy?.processes?.child?.length === 1) {
return latest;
}
await new Promise((resolveWait) => setTimeout(resolveWait, 200));
}
throw new Error(`Packaged Main proxy child did not become active: ${JSON.stringify(latest?.proxy)}`);
}
async function waitForResilienceProof(electronApplication, predicate, message) {
const deadline = Date.now() + 30_000;
let latest;
while (Date.now() < deadline) {
latest = await evaluateProof(electronApplication, 'resilience.status');
if (predicate(latest?.resilience)) return latest;
await new Promise((resolveWait) => setTimeout(resolveWait, 100));
}
throw new Error(`${message}: ${JSON.stringify(latest?.resilience)}`);
}
function assertResilienceTerminal(
status,
expectedRunStatus = 'error',
expectedErrorCode = 'CODING_RUNTIME_START_FAILED',
) {
if (status?.target?.workerStatus !== 'error'
|| status?.target?.runStatus !== expectedRunStatus
|| status?.target?.errorCode !== expectedErrorCode
|| status?.target?.recoverable !== true
|| status?.target?.bindingPreserved !== true
|| status?.other?.bindingPreserved !== true) {
throw new Error(`Packaged resilience target did not converge: ${JSON.stringify(status)}`);
}
}
async function recoverSelectedConversation(page, electronApplication) {
await page.getByRole('button', { name: '恢复' }).first().click({ timeout: 10_000 });
const recovered = await waitForResilienceProof(
electronApplication,
(status) => status?.target?.workerStatus === 'ready' && status?.target?.runStatus === 'idle',
'Packaged resilience target did not recover',
);
const composer = page.getByRole('textbox');
await composer.waitFor({ state: 'visible', timeout: 10_000 });
if (!await composer.isEnabled()) throw new Error('Recovered resilience composer is disabled');
return recovered;
}
async function evaluateProof(electronApplication, action) {
return await electronApplication.evaluate(async (_electron, requestedAction) => {
const proof = globalThis.__niancodeRunPiReleaseProofE2E;
if (typeof proof !== 'function') throw new Error('Packaged Main has no PI release proof entry');
return await proof(requestedAction);
}, action);
}
async function closeApplication(electronApplication) {
await Promise.race([
electronApplication.close().catch(() => undefined),
new Promise((resolveTimeout) => setTimeout(resolveTimeout, 5_000)),
]);
}
async function windowsDescendantProcessIds(rootPid) {
if (process.platform !== 'win32') return [];
const script = 'Get-CimInstance Win32_Process | Select-Object ProcessId, ParentProcessId | ConvertTo-Json -Compress';
const { stdout } = await execFileAsync(
'powershell.exe',
['-NoProfile', '-NonInteractive', '-Command', script],
{ windowsHide: true, maxBuffer: 4 * 1024 * 1024 },
);
const parsed = stdout.trim() ? JSON.parse(stdout) : [];
const processes = (Array.isArray(parsed) ? parsed : [parsed]).flatMap((entry) => {
const pid = Number(entry?.ProcessId);
const parentPid = Number(entry?.ParentProcessId);
return Number.isSafeInteger(pid) && Number.isSafeInteger(parentPid) ? [{ pid, parentPid }] : [];
});
const descendants = new Set();
const frontier = [rootPid];
while (frontier.length > 0) {
const parentPid = frontier.shift();
for (const processEntry of processes) {
if (processEntry.parentPid !== parentPid || descendants.has(processEntry.pid)) continue;
descendants.add(processEntry.pid);
frontier.push(processEntry.pid);
}
}
return [...descendants];
}
function processIsAlive(pid) {
try {
process.kill(pid, 0);
return true;
} catch {
return false;
}
}
export async function runPackagedProductProof(options) {
const scratchRoot = await mkdtemp(join(tmpdir(), 'makelore-pi-final-product-proof-'));
const homeDir = join(scratchRoot, 'home');
const userDataDir = join(scratchRoot, 'user-data');
await Promise.all([
mkdir(join(homeDir, '.config'), { recursive: true }),
mkdir(join(homeDir, 'AppData', 'Local'), { recursive: true }),
mkdir(join(homeDir, 'AppData', 'Roaming'), { recursive: true }),
mkdir(userDataDir, { recursive: true }),
]);
const hostApiPort = await allocatePort();
let electronApplication;
let pressureActive = false;
let proxyActive = false;
let resilienceActive = false;
try {
electronApplication = await electron.launch({
executablePath: options.electronExecutable,
env: {
...process.env,
HOME: homeDir,
USERPROFILE: homeDir,
APPDATA: join(homeDir, 'AppData', 'Roaming'),
LOCALAPPDATA: join(homeDir, 'AppData', 'Local'),
XDG_CONFIG_HOME: join(homeDir, '.config'),
NIANCODE_E2E: '1',
NIANCODE_E2E_SKIP_SETUP: '1',
NIANCODE_USER_DATA_DIR: userDataDir,
NIANCODE_PORT_NIANCODE_HOST_API: String(hostApiPort),
...(process.platform === 'linux' ? { ELECTRON_DISABLE_SANDBOX: '1' } : {}),
},
timeout: 90_000,
});
const page = await electronApplication.firstWindow();
await page.waitForLoadState('domcontentloaded');
const extension = await evaluateProof(electronApplication, 'extension');
assertPackagedMain(extension);
assertManagedTurns(extension.extension);
if (extension.extension?.subagentStatus !== 'complete'
|| extension.extension?.childToolNames?.join(',') !== 'find,grep,ls,read'
|| !extension.extension?.parentToolNames?.includes('subagent')
|| extension.extension?.parentProcessIds?.length < 2
|| extension.extension?.childProcessIds?.length !== 1
|| extension.extension?.providerRequests?.child !== 1
|| extension.extension?.managedTurns?.length !== 2) {
throw new Error(`Final ASAR extension/subagent proof failed: ${JSON.stringify(extension.extension)}`);
}
const pressureStart = await evaluateProof(electronApplication, 'pressure.start');
pressureActive = true;
assertPackagedMain(pressureStart);
assertActivePressure(pressureStart.pressure);
const uiStartedAt = performance.now();
await page.getByTestId('ai-module-option-programming').click();
await page.getByTestId('main-layout').waitFor({ state: 'visible', timeout: 10_000 });
const uiInteractiveMs = Math.round(performance.now() - uiStartedAt);
const pressureFinish = await evaluateProof(electronApplication, 'pressure.finish');
pressureActive = false;
assertPackagedMain(pressureFinish);
assertReleasedPressure(pressureFinish.pressure);
let failureCleanup;
if (options.verifyCleanupFailure === true) {
const failureStart = await evaluateProof(electronApplication, 'pressure.start');
pressureActive = true;
assertPackagedMain(failureStart);
assertActivePressure(failureStart.pressure);
let injectedFailure;
try {
await evaluateProof(electronApplication, 'pressure.finish.inject-failure');
} catch (error) {
injectedFailure = error;
}
if (!injectedFailure
|| !String(injectedFailure).includes('PI release pressure cleanup failed: parents.settle')) {
throw new Error(`PI pressure cleanup failure injection did not fail as expected: ${String(injectedFailure)}`);
}
const retryFinish = await evaluateProof(electronApplication, 'pressure.finish');
pressureActive = false;
assertPackagedMain(retryFinish);
assertReleasedPressure(retryFinish.pressure);
failureCleanup = {
injectedAt: 'parents.settle',
firstFinish: 'failed-as-injected',
retry: 'pass',
released: retryFinish.pressure,
};
}
const proxyStart = await evaluateProof(electronApplication, 'proxy.start');
proxyActive = true;
assertPackagedMain(proxyStart);
if (proxyStart?.proxy?.providerMode !== 'works_square_ai_gateway_proxy'
|| proxyStart?.proxy?.currentHostTokenAvailable !== true
|| proxyStart?.proxy?.realTurnVerified !== false) {
throw new Error(`Packaged Main proxy setup failed: ${JSON.stringify(proxyStart?.proxy)}`);
}
await page.reload();
await page.waitForLoadState('domcontentloaded');
const moduleSelection = page.getByTestId('ai-module-selection-page');
if (await moduleSelection.count()) {
await page.getByTestId('ai-module-option-programming').click();
await page.getByTestId('main-layout').waitFor({ state: 'visible', timeout: 10_000 });
}
await page.evaluate(() => { window.location.hash = '/chat'; });
const composer = page.getByRole('textbox');
await composer.waitFor({ state: 'visible', timeout: 30_000 });
await composer.fill('Exercise the packaged Main proxy Conversation');
if (!await composer.isEnabled()) throw new Error('Packaged proxy first Conversation composer is disabled');
const beforeSubmitText = await page.locator('body').innerText();
if (beforeSubmitText.includes('本地编程运行时暂时不可用')
|| beforeSubmitText.includes('正在重新连接本地 Agent')) {
throw new Error(`Packaged proxy first Conversation exposed a runtime banner: ${beforeSubmitText}`);
}
await page.getByRole('button', { name: '发送' }).click({ timeout: 30_000 });
let proxyStatus;
try {
proxyStatus = await waitForActiveProxyProof(electronApplication);
} catch (error) {
const bodyText = await page.locator('body').innerText().catch(() => '<unavailable>');
throw new Error(`${error instanceof Error ? error.message : String(error)}; UI=${bodyText}`);
}
assertPackagedMain(proxyStatus);
assertProxyStatus(proxyStatus.proxy);
await evaluateProof(electronApplication, 'proxy.release-child');
await page.getByText('REAL_PARENT_COMPLETE').waitFor({ state: 'visible', timeout: 30_000 });
const afterTurnText = await page.locator('body').innerText();
if (afterTurnText.includes('本地编程运行时暂时不可用')
|| afterTurnText.includes('正在重新连接本地 Agent')) {
throw new Error(`Packaged proxy Conversation did not leave recovery cleanly: ${afterTurnText}`);
}
if (!await composer.isEnabled()) throw new Error('Packaged proxy composer is not editable after the turn');
const proxyFinish = await evaluateProof(electronApplication, 'proxy.finish');
proxyActive = false;
assertPackagedMain(proxyFinish);
assertProxyProof(proxyFinish.proxy);
const resilienceStart = await evaluateProof(electronApplication, 'resilience.start');
resilienceActive = true;
assertPackagedMain(resilienceStart);
if (resilienceStart?.resilience?.bindingsEstablished !== true
|| resilienceStart?.resilience?.otherRunAccepted !== true
|| resilienceStart?.resilience?.realTurnVerified !== false) {
throw new Error(`Packaged resilience setup failed: ${JSON.stringify(resilienceStart?.resilience)}`);
}
await page.reload();
await page.waitForLoadState('domcontentloaded');
if (await page.getByTestId('ai-module-selection-page').count()) {
await page.getByTestId('ai-module-option-programming').click();
await page.getByTestId('main-layout').waitFor({ state: 'visible', timeout: 10_000 });
}
await page.evaluate(() => { window.location.hash = '/chat'; });
const resilienceComposer = page.getByRole('textbox');
await resilienceComposer.waitFor({ state: 'visible', timeout: 30_000 });
await resilienceComposer.fill('RESILIENCE_TARGET_ACTIVE');
await page.getByRole('button', { name: '发送' }).click({ timeout: 30_000 });
const activeResilience = await waitForResilienceProof(
electronApplication,
(status) => status?.target?.runStatus === 'running'
&& status?.other?.runStatus === 'running'
&& status?.resources?.subagents?.activeChildPermits === 1
&& status?.resources?.subagents?.activeDispatches === 1
&& status?.resources?.extension?.registrations?.child === 1
&& status?.resources?.extension?.writeLeases?.active === 1
&& status?.processes?.parent?.length === 2
&& status?.processes?.child?.length === 1,
'Packaged resilience parent/child/write-lease fault state did not become active',
);
const requestsBeforeExit = activeResilience.resilience.providerRequests;
const exitFailure = await evaluateProof(electronApplication, 'resilience.inject-exit');
assertPackagedMain(exitFailure);
assertResilienceTerminal(exitFailure.resilience.status);
if (exitFailure.resilience.terminalizationMs > 2_000) {
throw new Error(`Packaged worker exit convergence exceeded 2s: ${exitFailure.resilience.terminalizationMs}`);
}
const releasedAfterExit = await waitForResilienceProof(
electronApplication,
(status) => status?.other?.runStatus === 'running'
&& status?.resources?.subagents?.activeChildPermits === 0
&& status?.resources?.subagents?.activeDispatches === 0
&& status?.resources?.extension?.registrations?.child === 0
&& status?.resources?.extension?.writeLeases?.active === 0
&& status?.processes?.child?.length === 0,
'Target crash did not release child and write-lease resources or preserve the other run',
);
await page.getByText('本地 Agent 已中断,原请求未自动重发。').waitFor({ state: 'visible', timeout: 10_000 });
const composerAfterExit = await page.getByTestId('coding-message-composer').innerText();
if (composerAfterExit.includes('当前对话正在处理') || composerAfterExit.includes('生成中')) {
throw new Error(`Packaged resilience UI remained busy after worker exit: ${composerAfterExit}`);
}
if (!await resilienceComposer.isEnabled()) {
throw new Error('Packaged resilience composer stayed disabled after worker exit');
}
const abortAfterExit = await evaluateProof(electronApplication, 'resilience.abort-after-exit');
assertPackagedMain(abortAfterExit);
assertResilienceTerminal(abortAfterExit.resilience);
const recoveredAfterExit = await recoverSelectedConversation(page, electronApplication);
if (JSON.stringify(recoveredAfterExit.resilience.providerRequests) !== JSON.stringify(requestsBeforeExit)) {
throw new Error('Recover replayed the uncertain accepted prompt after worker exit');
}
await resilienceComposer.fill('RESILIENCE_RECOVERED_TURN');
await page.getByRole('button', { name: '发送' }).click({ timeout: 30_000 });
await page.getByText('RESILIENCE_RECOVERED_COMPLETE').waitFor({ state: 'visible', timeout: 30_000 });
await evaluateProof(electronApplication, 'resilience.release-parents');
await waitForResilienceProof(
electronApplication,
(status) => status?.other?.runStatus === 'idle' && status?.target?.runStatus === 'idle',
'Isolation control Conversation did not settle after release',
);
await resilienceComposer.fill('RESILIENCE_PROTOCOL_ACTIVE');
await page.getByRole('button', { name: '发送' }).click({ timeout: 30_000 });
const protocolActive = await waitForResilienceProof(
electronApplication,
(status) => status?.target?.runStatus === 'running'
&& status?.activeProviderRequests?.parent === 1,
'Protocol invalidation target did not become active',
);
const protocolFailure = await evaluateProof(electronApplication, 'resilience.inject-protocol');
assertPackagedMain(protocolFailure);
assertResilienceTerminal(
protocolFailure.resilience.status,
'error',
'CODING_RUNTIME_PROTOCOL_ERROR',
);
if (protocolFailure.resilience.terminalizationMs > 2_000) {
throw new Error(`Packaged protocol convergence exceeded 2s: ${protocolFailure.resilience.terminalizationMs}`);
}
await page.getByText('本地 Agent 已中断,原请求未自动重发。').waitFor({ state: 'visible', timeout: 10_000 });
const recoveredAfterProtocol = await recoverSelectedConversation(page, electronApplication);
if (JSON.stringify(recoveredAfterProtocol.resilience.providerRequests)
!== JSON.stringify(protocolFailure.resilience.status.providerRequests)) {
throw new Error('Recover replayed the uncertain prompt after protocol invalidation');
}
await resilienceComposer.fill('RESILIENCE_SETTLED_BEFORE_CLOSE');
await page.getByRole('button', { name: '发送' }).click({ timeout: 30_000 });
await page.getByText('RESILIENCE_SETTLED_COMPLETE').waitFor({ state: 'visible', timeout: 30_000 });
const settledBeforeClose = await waitForResilienceProof(
electronApplication,
(status) => status?.target?.runStatus === 'idle' && status?.target?.workerStatus === 'ready',
'Settled-before-close target did not reach its authoritative terminal event',
);
const settledClose = await evaluateProof(electronApplication, 'resilience.inject-exit');
assertPackagedMain(settledClose);
assertResilienceTerminal(settledClose.resilience.status, 'idle');
await recoverSelectedConversation(page, electronApplication);
const resilienceFinish = await evaluateProof(electronApplication, 'resilience.finish');
resilienceActive = false;
assertPackagedMain(resilienceFinish);
if (resilienceFinish?.resilience?.released?.workers !== 0
|| resilienceFinish?.resilience?.released?.processes !== 0
|| Object.values(resilienceFinish?.resilience?.lifecycle ?? {}).some((value) => value !== true)
|| resilienceFinish?.resilience?.realTurnVerified !== false) {
throw new Error(`Packaged resilience proof failed: ${JSON.stringify(resilienceFinish?.resilience)}`);
}
const mainProcessId = electronApplication.process().pid;
const proofProcessIds = [
mainProcessId,
...await windowsDescendantProcessIds(mainProcessId),
];
await closeApplication(electronApplication);
electronApplication = undefined;
const exitDeadline = Date.now() + 5_000;
let lingeringProcessIds = proofProcessIds.filter(processIsAlive);
while (lingeringProcessIds.length > 0 && Date.now() < exitDeadline) {
await new Promise((resolveWait) => setTimeout(resolveWait, 100));
lingeringProcessIds = proofProcessIds.filter(processIsAlive);
}
if (lingeringProcessIds.length > 0) {
throw new Error(`Packaged proof left Electron/Pi processes alive: ${lingeringProcessIds.join(',')}`);
}
const report = {
schemaVersion: 1,
generatedAt: new Date().toISOString(),
executable: options.electronExecutable,
runtimeRoot: options.runtimeRoot ?? null,
packagedMain: extension.packagedMain,
extension: extension.extension,
pressure: {
processKind: 'final-product-executable-with-ELECTRON_RUN_AS_NODE',
active: pressureStart.pressure,
ui: {
action: 'select Makelore Code and render main layout',
interactive: true,
durationMs: uiInteractiveMs,
},
released: pressureFinish.pressure,
...(failureCleanup ? { failureCleanup } : {}),
},
proxy: {
setup: proxyStart.proxy,
active: proxyStatus.proxy,
completed: proxyFinish.proxy,
ui: {
firstConversationEditable: true,
inputSubmitted: true,
runtimeUnavailableBanner: false,
permanentRecovering: false,
},
realTurnVerified: false,
},
resilience: {
setup: resilienceStart.resilience,
active: activeResilience.resilience,
exit: exitFailure.resilience,
abortAfterExit: abortAfterExit.resilience,
releasedAfterExit: releasedAfterExit.resilience,
protocol: {
active: protocolActive.resilience,
failure: protocolFailure.resilience,
},
settledBeforeClose: {
settled: settledBeforeClose.resilience,
close: settledClose.resilience,
},
completed: resilienceFinish.resilience,
ui: {
terminalErrorVisible: true,
composerUnlocked: true,
recoverAvailable: true,
uncertainPromptReplayed: false,
},
realTurnVerified: false,
},
cleanExit: {
trackedProcessIds: proofProcessIds,
lingeringProcessIds,
},
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 (electronApplication && pressureActive) {
await evaluateProof(electronApplication, 'pressure.finish').catch(() => undefined);
}
if (electronApplication && proxyActive) {
await evaluateProof(electronApplication, 'proxy.release-child').catch(() => undefined);
await evaluateProof(electronApplication, 'proxy.finish').catch(() => undefined);
}
if (electronApplication && resilienceActive) {
await evaluateProof(electronApplication, 'resilience.release-parents').catch(() => undefined);
await evaluateProof(electronApplication, 'resilience.finish').catch(() => undefined);
}
if (electronApplication) await closeApplication(electronApplication);
await rm(scratchRoot, { recursive: true, force: true, maxRetries: 5, retryDelay: 200 });
}
}
async function main() {
const options = parseArgs(process.argv.slice(2));
const report = await runPackagedProductProof(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;
});
}