feat: prepare Zhinian desktop client for pilot release
This commit is contained in:
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user