在 Makelore 构建并预检静态发布产物

This commit is contained in:
2026-08-12 21:19:39 +08:00
parent 3a80625fe2
commit 5b44864265
26 changed files with 1275 additions and 217 deletions

View File

@@ -4,7 +4,8 @@
*/
import { app, BrowserWindow, nativeImage, shell } from 'electron';
import type { Server } from 'node:http';
import { join } from 'path';
import { createServer } from 'node:http';
import { join } from 'node:path';
import { OpencodeManager } from '../opencode/manager';
import { buildOpencodeRuntimeConfigFromNianCodeProviders } from '../opencode/provider-config';
import {
@@ -66,6 +67,7 @@ import { AgentBrowserModule, ElectronAgentBrowserAdapter } from '../agent-browse
import { browserOAuthManager } from '../utils/browser-oauth';
import { createProjectProgressSync } from '../services/project-progress-sync';
import { createWorksSubmissionBindingStore } from '../services/works-submission-binding';
import { createStaticArtifactSnapshot } from '../services/static-release-server';
import {
consumeWorksSquareStartupRuntimeCleanupRequired,
getWorksSquareSessionRestoreStatus,
@@ -162,6 +164,7 @@ let hostApiServer: Server | null = null;
let projectProgressSync: ReturnType<typeof createProjectProgressSync> | null = null;
let worksSubmissionBinding: ReturnType<typeof createWorksSubmissionBindingStore> | null = null;
let agentBrowser: AgentBrowserModule | null = null;
let applicationInitialization: Promise<void> | null = null;
let imageWorkspaceModule: DesignWorkspaceModule | null = null;
const mainWindowFocusState = createMainWindowFocusState();
const quitLifecycleState = createQuitLifecycleState();
@@ -653,7 +656,8 @@ if (gotTheLock) {
// Application lifecycle
app.whenReady().then(() => {
void initialize().catch((error) => {
applicationInitialization = initialize();
void applicationInitialization.catch((error) => {
logger.error('Application initialization failed:', error);
});
@@ -754,20 +758,52 @@ if (gotTheLock) {
// Export for testing
export { mainWindow, opencodeManager, opencodeProjectStore };
export async function runLocalPreviewPreflightE2E(url: string): Promise<{ ok: true }> {
if (!isE2EMode || !agentBrowser) throw new Error('E2E local preview preflight is unavailable');
const projectPath = join(app.getPath('temp'), 'makelore-local-preview-preflight-e2e');
await agentBrowser.open({
projectId: 'local-preview-preflight-e2e',
projectPath,
url,
visible: false,
export async function runLocalPreviewPreflightE2E(
scenario: 'success' | 'external' = 'success',
): Promise<{ ok: boolean; externalRequests: number; code?: string }> {
if (!isE2EMode) throw new Error('E2E local preview preflight is unavailable');
const initialization = applicationInitialization;
if (!initialization) {
throw new Error('E2E local preview preflight is not ready');
}
await initialization;
const browser = agentBrowser;
if (!browser) {
throw new Error('E2E local preview preflight is not ready');
}
let externalRequests = 0;
const externalServer = createServer((_request, response) => {
externalRequests += 1;
response.end('blocked');
});
try {
return await agentBrowser.preflightCurrentProject(projectPath);
await new Promise<void>((resolveListen, reject) => {
externalServer.once('error', reject);
externalServer.listen(0, '127.0.0.1', resolveListen);
});
const address = externalServer.address();
if (!address || typeof address === 'string') throw new Error('E2E external server unavailable');
const externalScript = scenario === 'external'
? `<script src="http://127.0.0.1:${address.port}/blocked.js"></script>`
: '';
const artifact = createStaticArtifactSnapshot([{
path: 'index.html',
bytes: Buffer.from(`<!doctype html><meta name="viewport" content="width=device-width,initial-scale=1"><main style="width:100vw;height:100vh">Playable</main>${externalScript}`),
}]);
try {
await browser.preflightStaticArtifact(artifact);
return { ok: true, externalRequests };
} catch (error) {
return {
ok: false,
externalRequests,
code: error && typeof error === 'object' && 'code' in error
? String(error.code)
: 'PUBLISH_PREFLIGHT_UNAVAILABLE',
};
}
} finally {
await agentBrowser.close(projectPath).catch(() => undefined);
await agentBrowser.resetProfile(projectPath).catch(() => undefined);
await new Promise<void>((resolveClose) => externalServer.close(() => resolveClose()));
}
}