合并远程主分支客户端收口

This commit is contained in:
2026-08-13 17:13:36 +08:00
240 changed files with 4900 additions and 20399 deletions

View File

@@ -16,17 +16,19 @@ import { resolveOpencodeRuntimePaths } from '../opencode/paths';
import {
resolveBundledAgentBrowserPluginPath,
resolveBundledCourseSkillsDir,
resolveBundledSuperpowersDir,
} from '../opencode/superpowers';
} from '../opencode/course-skills';
import {
createElectronProjectStorage,
createProjectStore,
type OpencodeProjectStore,
} from '../opencode/project-store';
import { readProjectConfig } from '../opencode/project-config';
import { warmupOpencodeRuntime } from '../opencode/startup-warmup';
import { registerIpcHandlers } from './ipc-handlers';
import { createTray } from './tray';
import { createMenu } from './menu';
import { registerZoomShortcuts } from './zoom-shortcuts';
import { getNativeWindowMaterialOptions } from './window-material';
import { appUpdater, registerUpdateHandlers } from './updater';
import { logger } from '../utils/logger';
@@ -90,6 +92,39 @@ const WINDOWS_APP_USER_MODEL_ID = 'app.niancode.desktop';
const isE2EMode = process.env.NIANCODE_E2E === '1';
const requestedUserDataDir = process.env.NIANCODE_USER_DATA_DIR?.trim();
async function buildMakeloreOpencodeRuntimeConfig() {
return await buildOpencodeRuntimeConfigFromNianCodeProviders({
mcpServers: {
[PLAYWRIGHT_MCP_SERVER_ID]: resolvePlaywrightMcpServer(),
},
});
}
function scheduleOpencodeRuntimeWarmup(): void {
if (isE2EMode) return;
void warmupOpencodeRuntime({
hasAuthenticatedSession: () => Boolean(getWorksSquareSessionSnapshot()),
getStatus: () => opencodeManager.getStatus(),
getActiveProject: () => opencodeProjectStore.getActiveProject(),
readProjectConfig,
getConfiguredProviderCount: async () => {
const runtime = await buildMakeloreOpencodeRuntimeConfig();
return Object.keys(runtime.config.provider).length;
},
start: () => opencodeManager.start(),
onError: (error, phase) => {
logger.warn(`[opencode-runtime] Startup warmup ${phase} failed`, error);
},
}).then((result) => {
if (result.started) {
logger.info('[opencode-runtime] Startup warmup completed');
}
}).catch((error) => {
logger.warn('[opencode-runtime] Startup warmup could not be scheduled', error);
});
}
if (isE2EMode && requestedUserDataDir) {
app.setPath('userData', requestedUserDataDir);
}
@@ -205,14 +240,17 @@ function createWindow(): BrowserWindow {
const isWindows = process.platform === 'win32';
const useCustomTitleBar = isWindows;
const shouldSkipSetupForE2E = process.env.NIANCODE_E2E_SKIP_SETUP === '1';
const minimumWorkspaceColumnWidth = 256;
const minimumWorkspaceWidth = minimumWorkspaceColumnWidth * 4;
const win = new BrowserWindow({
title: 'Makelore',
width: 1280,
height: 800,
minWidth: 1100,
minWidth: minimumWorkspaceWidth,
minHeight: 700,
icon: getAppIcon(),
...getNativeWindowMaterialOptions(process.platform),
webPreferences: {
preload: join(__dirname, '../preload/index.js'),
nodeIntegration: false,
@@ -221,7 +259,10 @@ function createWindow(): BrowserWindow {
webviewTag: false,
},
titleBarStyle: isMac ? 'hiddenInset' : useCustomTitleBar ? 'hidden' : 'default',
trafficLightPosition: isMac ? { x: 16, y: 16 } : undefined,
// Keep the native traffic lights on the same centerline as the 40px
// renderer title bar. The native glyphs sit about 7px below the
// configured origin, so y=13 centers them on the renderer controls.
trafficLightPosition: isMac ? { x: 16, y: 13 } : undefined,
frame: isMac || !useCustomTitleBar,
show: false,
});
@@ -534,6 +575,11 @@ async function initialize(): Promise<void> {
browserOAuthManager.on('oauth:error', (error) => {
hostEventBus.emit('oauth:error', error);
});
// Start the local Code runtime in the background once the Main process has
// restored session state and registered the Host API. Chat still retains
// its lazy-start fallback for first-run and failed-warmup cases.
scheduleOpencodeRuntimeWarmup();
}
if (gotTheLock) {
@@ -579,11 +625,6 @@ if (gotTheLock) {
platform: process.platform,
arch: process.arch,
});
const bundledSuperpowersDir = resolveBundledSuperpowersDir({
isPackaged: app.isPackaged,
resourcesPath: process.resourcesPath,
appPath: app.getAppPath(),
});
const bundledCourseSkillsDir = resolveBundledCourseSkillsDir({
isPackaged: app.isPackaged,
resourcesPath: process.resourcesPath,
@@ -599,17 +640,12 @@ if (gotTheLock) {
binPath: opencodePaths.binPath,
preflightPreferredPort: true,
userDataDir: app.getPath('userData'),
bundledSuperpowersDir,
bundledCourseSkillsDir,
bundledAgentBrowserPluginPath,
pythonRuntime,
uvRuntime,
runtimeConfigProvider: async () => {
const runtime = await buildOpencodeRuntimeConfigFromNianCodeProviders({
mcpServers: {
[PLAYWRIGHT_MCP_SERVER_ID]: resolvePlaywrightMcpServer(),
},
});
const runtime = await buildMakeloreOpencodeRuntimeConfig();
return {
...runtime,
config: runtime.config as unknown as Record<string, unknown>,

View File

@@ -0,0 +1,23 @@
import type { BrowserWindowConstructorOptions } from 'electron';
type NativeWindowMaterialOptions = Pick<
BrowserWindowConstructorOptions,
'backgroundColor' | 'transparent' | 'vibrancy' | 'visualEffectState'
>;
/**
* Use the native macOS material only where Electron and the window manager
* support it. Other platforms keep the normal opaque window as a safe fallback.
*/
export function getNativeWindowMaterialOptions(
platform: NodeJS.Platform,
): NativeWindowMaterialOptions {
if (platform !== 'darwin') return {};
return {
backgroundColor: '#00000000',
transparent: true,
vibrancy: 'under-window',
visualEffectState: 'active',
};
}