feat: prepare Zhinian desktop client for pilot release

This commit is contained in:
inman
2026-04-29 10:23:20 +08:00
parent f9361e686a
commit 47b83b79fc
149 changed files with 15341 additions and 3590 deletions

View File

@@ -20,13 +20,13 @@ import { getApiKey, getDefaultProvider, getProvider } from '../utils/secure-stor
import { getProviderEnvVar, getKeyableProviderTypes } from '../utils/provider-registry';
import { getOpenClawDir, getOpenClawEntryPath, isOpenClawPresent } from '../utils/paths';
import { getUvMirrorEnv } from '../utils/uv-env';
import { cleanupDanglingWeChatPluginState, listConfiguredChannelsFromConfig, readOpenClawConfig } from '../utils/channel-config';
import { cleanupDanglingWeChatPluginState, listConfiguredChannelsFromConfig, readOpenClawConfig, writeOpenClawConfig, type ChannelConfigData } from '../utils/channel-config';
import { sanitizeOpenClawConfig, batchSyncConfigFields } from '../utils/openclaw-auth';
import { buildProxyEnv, resolveProxySettings } from '../utils/proxy';
import { syncProxyConfigToOpenClaw } from '../utils/openclaw-proxy';
import { logger } from '../utils/logger';
import { prependPathEntry } from '../utils/env-path';
import { copyPluginFromNodeModules, fixupPluginManifest, cpSyncSafe } from '../utils/plugin-install';
import { copyPluginFromNodeModules, ensureCloudSyncPluginInstalled, fixupPluginManifest, cpSyncSafe } from '../utils/plugin-install';
import { stripSystemdSupervisorEnv } from './config-sync-env';
@@ -60,6 +60,69 @@ const CHANNEL_PLUGIN_MAP: Record<string, { dirName: string; npmName: string }> =
* plugin and must be removed.
*/
const BUILTIN_CHANNEL_EXTENSIONS = ['discord', 'telegram', 'qqbot'];
const CLOUD_SYNC_PLUGIN_ID = 'cloud-sync';
const DEFAULT_CLOUD_SYNC_SERVER_URL = 'https://onefeel.brother7.cn';
function isPlainRecord(value: unknown): value is Record<string, unknown> {
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
}
function normalizeServerUrl(value: string | undefined): string | undefined {
const trimmed = value?.trim();
if (!trimmed) return undefined;
return trimmed.replace(/\/+$/, '');
}
export function deriveCloudSyncServerUrl(): string {
const explicit = normalizeServerUrl(
process.env.YINIAN_CLOUD_SYNC_SERVER_URL ?? process.env.CLOUDCLAW_SERVER_URL,
);
if (explicit) return explicit;
const apiBaseUrl = normalizeServerUrl(process.env.YINIAN_API_BASE_URL);
if (apiBaseUrl) {
return apiBaseUrl.replace(/\/ingress$/i, '');
}
return DEFAULT_CLOUD_SYNC_SERVER_URL;
}
export async function ensureCloudSyncPluginConfigured(): Promise<void> {
if (process.env.YINIAN_CLOUD_SYNC_ENABLED === '0') {
return;
}
const installResult = ensureCloudSyncPluginInstalled();
if (installResult.warning) {
logger.warn(`[plugin] Cloud Sync: ${installResult.warning}`);
}
if (!installResult.installed) {
return;
}
const serverUrl = deriveCloudSyncServerUrl();
const config = await readOpenClawConfig();
config.plugins ??= {};
config.plugins.enabled = true;
const allow = Array.isArray(config.plugins.allow) ? config.plugins.allow : [];
if (!allow.includes(CLOUD_SYNC_PLUGIN_ID)) {
config.plugins.allow = [...allow, CLOUD_SYNC_PLUGIN_ID];
}
config.plugins.entries ??= {};
const existingEntry = config.plugins.entries[CLOUD_SYNC_PLUGIN_ID];
const entry: ChannelConfigData = isPlainRecord(existingEntry) ? { ...existingEntry } : {};
const existingEntryConfig = isPlainRecord(entry.config) ? entry.config : {};
entry.enabled = true;
entry.config = {
...existingEntryConfig,
serverUrl,
};
config.plugins.entries[CLOUD_SYNC_PLUGIN_ID] = entry;
await writeOpenClawConfig(config);
}
function cleanupStaleBuiltInExtensions(): void {
for (const ext of BUILTIN_CHANNEL_EXTENSIONS) {
@@ -89,12 +152,15 @@ function buildBundledPluginSources(pluginDirName: string): string[] {
return app.isPackaged
? [
join(process.resourcesPath, 'openclaw-plugins', pluginDirName),
join(process.resourcesPath, 'resources', 'openclaw-plugins', pluginDirName),
join(process.resourcesPath, 'app.asar.unpacked', 'build', 'openclaw-plugins', pluginDirName),
join(process.resourcesPath, 'app.asar.unpacked', 'openclaw-plugins', pluginDirName),
]
: [
join(app.getAppPath(), 'build', 'openclaw-plugins', pluginDirName),
join(app.getAppPath(), 'resources', 'openclaw-plugins', pluginDirName),
join(process.cwd(), 'build', 'openclaw-plugins', pluginDirName),
join(process.cwd(), 'resources', 'openclaw-plugins', pluginDirName),
];
}
@@ -295,6 +361,12 @@ export async function syncGatewayConfigBeforeLaunch(
logger.warn('Failed to clean dangling WeChat plugin state before launch:', err);
}
try {
await ensureCloudSyncPluginConfigured();
} catch (err) {
logger.warn('Failed to configure Cloud Sync plugin before launch:', err);
}
// Remove stale copies of built-in extensions (Discord, Telegram) that
// override OpenClaw's working built-in plugins and break channel loading.
try {