feat: prepare Zhinian desktop pilot
Some checks failed
Electron E2E / Electron E2E (macos-latest) (push) Has been cancelled
Electron E2E / Electron E2E (ubuntu-latest) (push) Has been cancelled
Electron E2E / Electron E2E (windows-latest) (push) Has been cancelled

This commit is contained in:
inman
2026-05-07 21:49:20 +08:00
parent cddaf37016
commit 0abc48189c
103 changed files with 10975 additions and 2049 deletions

View File

@@ -18,7 +18,7 @@ function fsPath(filePath: string): string {
import { getAllSettings } from '../utils/store';
import { getApiKey, getDefaultProvider, getProvider } from '../utils/secure-storage';
import { getProviderEnvVar, getKeyableProviderTypes } from '../utils/provider-registry';
import { getOpenClawDir, getOpenClawEntryPath, isOpenClawPresent } from '../utils/paths';
import { getOpenClawResolvedDir, isOpenClawPresent } from '../utils/paths';
import { getUvMirrorEnv } from '../utils/uv-env';
import { cleanupDanglingWeChatPluginState, listConfiguredChannelsFromConfig, readOpenClawConfig, writeOpenClawConfig, type ChannelConfigData } from '../utils/channel-config';
import { sanitizeOpenClawConfig, batchSyncConfigFields } from '../utils/openclaw-auth';
@@ -28,6 +28,8 @@ import { logger } from '../utils/logger';
import { prependPathEntry } from '../utils/env-path';
import { copyPluginFromNodeModules, ensureCloudSyncPluginInstalled, fixupPluginManifest, cpSyncSafe } from '../utils/plugin-install';
import { stripSystemdSupervisorEnv } from './config-sync-env';
import { ensureYinianModelRuntimeConfigured } from '../utils/model-diagnostics';
import { cleanupOpenClawUserNativeClipboard } from '../utils/optional-native-cleanup';
export interface GatewayLaunchContext {
@@ -46,12 +48,9 @@ export interface GatewayLaunchContext {
// ── Auto-upgrade bundled plugins on startup ──────────────────────
const CHANNEL_PLUGIN_MAP: Record<string, { dirName: string; npmName: string }> = {
dingtalk: { dirName: 'dingtalk', npmName: '@soimy/dingtalk' },
wecom: { dirName: 'wecom', npmName: '@wecom/wecom-openclaw-plugin' },
feishu: { dirName: 'feishu-openclaw-plugin', npmName: '@larksuite/openclaw-lark' },
'openclaw-weixin': { dirName: 'openclaw-weixin', npmName: '@tencent-weixin/openclaw-weixin' },
};
const REMOVED_CHANNEL_PLUGIN_DIRS = ['dingtalk', 'wecom', 'feishu-openclaw-plugin'];
/**
* OpenClaw 3.22+ ships Discord, Telegram, and other channels as built-in
@@ -239,6 +238,17 @@ function ensureConfiguredPluginsUpgraded(configuredChannels: string[]): void {
function cleanupUnconfiguredChannelPlugins(configuredChannels: string[]): void {
const configuredSet = new Set(configuredChannels);
for (const dirName of REMOVED_CHANNEL_PLUGIN_DIRS) {
const targetDir = join(homedir(), '.openclaw', 'extensions', dirName);
if (!existsSync(fsPath(targetDir))) continue;
logger.info(`[plugin] Removing disabled channel plugin: ${dirName}`);
try {
rmSync(fsPath(targetDir), { recursive: true, force: true });
} catch (err) {
logger.warn(`[plugin] Failed to remove disabled channel plugin ${dirName}:`, err);
}
}
for (const [channelType, pluginInfo] of Object.entries(CHANNEL_PLUGIN_MAP)) {
if (configuredSet.has(channelType)) continue;
@@ -347,6 +357,15 @@ export async function syncGatewayConfigBeforeLaunch(
// node_modules linked on the next Gateway spawn.
resetExtensionDepsLinked();
try {
const removedClipboardPackages = cleanupOpenClawUserNativeClipboard();
if (removedClipboardPackages > 0) {
logger.info(`[plugin] Removed optional native clipboard packages from user OpenClaw directories (${removedClipboardPackages})`);
}
} catch (err) {
logger.warn('Failed to clean optional native clipboard packages:', err);
}
await syncProxyConfigToOpenClaw(appSettings, { preserveExistingWhenDisabled: true });
try {
@@ -395,6 +414,12 @@ export async function syncGatewayConfigBeforeLaunch(
} catch (err) {
logger.warn('Failed to batch-sync config fields to openclaw.json:', err);
}
try {
await ensureYinianModelRuntimeConfigured();
} catch (err) {
logger.warn('Failed to configure Yinian model runtime defaults before launch:', err);
}
}
async function loadProviderEnv(): Promise<{ providerEnv: Record<string, string>; loadedProviderKeyCount: number }> {
@@ -466,8 +491,8 @@ async function resolveChannelStartupPolicy(): Promise<{
}
export async function prepareGatewayLaunchContext(port: number): Promise<GatewayLaunchContext> {
const openclawDir = getOpenClawDir();
const entryScript = getOpenClawEntryPath();
const openclawDir = getOpenClawResolvedDir();
const entryScript = join(openclawDir, 'openclaw.mjs');
if (!isOpenClawPresent()) {
throw new Error(`OpenClaw package not found at: ${openclawDir}`);
@@ -490,6 +515,14 @@ export async function prepareGatewayLaunchContext(port: number): Promise<Gateway
? path.join(process.resourcesPath, 'bin')
: path.join(process.cwd(), 'resources', 'bin', target);
const binPathExists = existsSync(binPath);
const bundledNodePath = path.join(binPath, process.platform === 'win32' ? 'node.exe' : 'node');
const bundledNpmCliPath = path.join(binPath, 'lib', 'node_modules', 'npm', 'bin', 'npm-cli.js');
const bundledPackageManagerEnv = binPathExists && existsSync(bundledNodePath) && existsSync(bundledNpmCliPath)
? {
YINIAN_NODE_EXEC_PATH: bundledNodePath,
YINIAN_NPM_CLI_PATH: bundledNpmCliPath,
}
: {};
const { providerEnv, loadedProviderKeyCount } = await loadProviderEnv();
const { skipChannels, channelStartupSummary } = await resolveChannelStartupPolicy();
@@ -510,6 +543,7 @@ export async function prepareGatewayLaunchContext(port: number): Promise<Gateway
...providerEnv,
...uvEnv,
...proxyEnv,
...bundledPackageManagerEnv,
OPENCLAW_GATEWAY_TOKEN: appSettings.gatewayToken,
OPENCLAW_SKIP_CHANNELS: skipChannels ? '1' : '',
CLAWDBOT_SKIP_CHANNELS: skipChannels ? '1' : '',