feat: prepare Zhinian desktop pilot
This commit is contained in:
@@ -6,6 +6,7 @@ import { createRequire } from 'node:module';
|
||||
import { dirname, isAbsolute, join, normalize } from 'path';
|
||||
import { homedir } from 'os';
|
||||
import { cpSync, existsSync, mkdirSync, readFileSync, realpathSync, rmSync } from 'fs';
|
||||
import { cleanupOpenClawRuntimeNativeClipboard } from './optional-native-cleanup';
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
|
||||
@@ -33,6 +34,8 @@ const REQUIRED_OPENCLAW_CONTEXT_MODULES = [
|
||||
'qrcode-terminal/vendor/QRCode/index.js',
|
||||
'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js',
|
||||
] as const;
|
||||
const YINIAN_OPENCLAW_RUNTIME_PATCH_MARKER = '.yinian-runtime-patch.json';
|
||||
const YINIAN_OPENCLAW_RUNTIME_PATCH_VERSION = '2026-05-07-desktop-fast-chat-v1';
|
||||
|
||||
export {
|
||||
quoteForCmd,
|
||||
@@ -172,6 +175,25 @@ function hasRequiredOpenClawContextModules(dir: string): boolean {
|
||||
}
|
||||
}
|
||||
|
||||
function readYinianOpenClawRuntimePatchVersion(dir: string): string | undefined {
|
||||
try {
|
||||
const markerPath = join(dir, YINIAN_OPENCLAW_RUNTIME_PATCH_MARKER);
|
||||
if (!existsSync(fsPath(markerPath))) return undefined;
|
||||
const marker = JSON.parse(readFileSync(fsPath(markerPath), 'utf-8')) as { version?: string };
|
||||
return marker.version;
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function hasYinianOpenClawRuntimePatch(dir: string): boolean {
|
||||
return readYinianOpenClawRuntimePatchVersion(dir) === YINIAN_OPENCLAW_RUNTIME_PATCH_VERSION;
|
||||
}
|
||||
|
||||
function hasPackagedOpenClawRuntimeRequirements(dir: string): boolean {
|
||||
return hasRequiredOpenClawContextModules(dir) && hasYinianOpenClawRuntimePatch(dir);
|
||||
}
|
||||
|
||||
function samePath(left: string, right: string): boolean {
|
||||
try {
|
||||
return realpathSync(fsPath(left)) === realpathSync(fsPath(right));
|
||||
@@ -253,10 +275,12 @@ function findExternalOpenClawDir(excludedDirs: string[]): string | null {
|
||||
seen.add(candidate);
|
||||
if (excludedDirs.some((excluded) => samePath(candidate, excluded))) continue;
|
||||
if (!isValidOpenClawPackageDir(candidate)) continue;
|
||||
if (hasRequiredOpenClawContextModules(candidate)) return candidate;
|
||||
logOpenClawRuntime('[openclaw-runtime] Ignoring external OpenClaw installation because required app dependencies are missing', {
|
||||
if (hasPackagedOpenClawRuntimeRequirements(candidate)) return candidate;
|
||||
logOpenClawRuntime('[openclaw-runtime] Ignoring external OpenClaw installation because it is not a patched Yinian runtime', {
|
||||
candidate,
|
||||
requiredModules: REQUIRED_OPENCLAW_CONTEXT_MODULES,
|
||||
runtimePatchVersion: readYinianOpenClawRuntimePatchVersion(candidate) ?? null,
|
||||
expectedRuntimePatchVersion: YINIAN_OPENCLAW_RUNTIME_PATCH_VERSION,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -271,7 +295,7 @@ function installBundledOpenClawToManagedRuntime(bundledDir: string, managedDir:
|
||||
? readOpenClawVersion(managedDir)
|
||||
: undefined;
|
||||
|
||||
if (managedVersion && bundledVersion && managedVersion === bundledVersion && hasRequiredOpenClawContextModules(managedDir)) {
|
||||
if (managedVersion && bundledVersion && managedVersion === bundledVersion && hasPackagedOpenClawRuntimeRequirements(managedDir)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -279,6 +303,12 @@ function installBundledOpenClawToManagedRuntime(bundledDir: string, managedDir:
|
||||
rmSync(fsPath(tempDir), { recursive: true, force: true });
|
||||
mkdirSync(fsPath(dirname(tempDir)), { recursive: true });
|
||||
cpSync(fsPath(bundledDir), fsPath(tempDir), { recursive: true, dereference: true });
|
||||
const removedClipboardPackages = cleanupOpenClawRuntimeNativeClipboard(tempDir);
|
||||
if (removedClipboardPackages > 0) {
|
||||
logOpenClawRuntime('[openclaw-runtime] Removed optional native clipboard packages from managed runtime', {
|
||||
removedClipboardPackages,
|
||||
});
|
||||
}
|
||||
rmSync(fsPath(managedDir), { recursive: true, force: true });
|
||||
cpSync(fsPath(tempDir), fsPath(managedDir), { recursive: true, dereference: true });
|
||||
rmSync(fsPath(tempDir), { recursive: true, force: true });
|
||||
@@ -303,7 +333,7 @@ function resolveOpenClawRuntime(): OpenClawRuntimeResolution {
|
||||
return cachedOpenClawRuntime;
|
||||
}
|
||||
|
||||
if (hasRequiredOpenClawContextModules(managedDir)) {
|
||||
if (hasPackagedOpenClawRuntimeRequirements(managedDir)) {
|
||||
cachedOpenClawRuntime = {
|
||||
dir: managedDir,
|
||||
source: 'managed',
|
||||
@@ -337,7 +367,7 @@ function resolveOpenClawRuntime(): OpenClawRuntimeResolution {
|
||||
}
|
||||
}
|
||||
|
||||
if (hasRequiredOpenClawContextModules(managedDir)) {
|
||||
if (hasPackagedOpenClawRuntimeRequirements(managedDir)) {
|
||||
cachedOpenClawRuntime = {
|
||||
dir: managedDir,
|
||||
source: 'managed',
|
||||
@@ -356,9 +386,11 @@ function resolveOpenClawRuntime(): OpenClawRuntimeResolution {
|
||||
}
|
||||
|
||||
if (isValidOpenClawPackageDir(managedDir)) {
|
||||
logOpenClawRuntime('[openclaw-runtime] Ignoring managed OpenClaw runtime because required app dependencies are missing', {
|
||||
logOpenClawRuntime('[openclaw-runtime] Ignoring managed OpenClaw runtime because it is not a patched Yinian runtime', {
|
||||
managedDir,
|
||||
requiredModules: REQUIRED_OPENCLAW_CONTEXT_MODULES,
|
||||
runtimePatchVersion: readYinianOpenClawRuntimePatchVersion(managedDir) ?? null,
|
||||
expectedRuntimePatchVersion: YINIAN_OPENCLAW_RUNTIME_PATCH_VERSION,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -415,10 +447,11 @@ export function reinstallManagedOpenClawRuntime(): OpenClawRuntimeResolution {
|
||||
installedFromBundled = installBundledOpenClawToManagedRuntime(bundledDir, managedDir);
|
||||
}
|
||||
|
||||
const managedReady = hasPackagedOpenClawRuntimeRequirements(managedDir);
|
||||
cachedOpenClawRuntime = {
|
||||
dir: hasRequiredOpenClawContextModules(managedDir) ? managedDir : bundledDir,
|
||||
source: hasRequiredOpenClawContextModules(managedDir) ? 'managed' : isValidOpenClawPackageDir(bundledDir) ? 'bundled' : 'missing',
|
||||
version: readOpenClawVersion(hasRequiredOpenClawContextModules(managedDir) ? managedDir : bundledDir),
|
||||
dir: managedReady ? managedDir : bundledDir,
|
||||
source: managedReady ? 'managed' : isValidOpenClawPackageDir(bundledDir) ? 'bundled' : 'missing',
|
||||
version: readOpenClawVersion(managedReady ? managedDir : bundledDir),
|
||||
bundledDir,
|
||||
managedDir,
|
||||
installedFromBundled,
|
||||
|
||||
Reference in New Issue
Block a user