fix(gateway): fall back to junction when symlink unavailable on Windows
ensureExtensionDepsResolvable called symlinkSync without a type argument and without path normalization. On Windows without Developer Mode or admin rights, plain symlinkSync throws EPERM; the failure was silently swallowed, leaving extension-owned packages unresolvable from shared dist/ chunks and breaking gateway startup. Extract the link logic into electron/gateway/fs-link.ts: - linkDirSafe prefers junction on Windows (works without elevation), falls back to a plain dir symlink only if junction creation fails (e.g. cross-volume). - normalizeFsPath centralizes the \\?\ extended-length + UNC prefixing that was previously an inline helper in config-sync.ts. Also drop the now-redundant inline fsPath helper in config-sync.ts and replace the two bare symlinkSync calls with linkDirSafe. Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
This commit is contained in:
@@ -1,20 +1,9 @@
|
||||
import { app } from 'electron';
|
||||
import path from 'path';
|
||||
import { existsSync, readFileSync, mkdirSync, readdirSync, rmSync, symlinkSync } from 'fs';
|
||||
import { existsSync, readFileSync, mkdirSync, readdirSync, rmSync } from 'fs';
|
||||
import { homedir } from 'os';
|
||||
import { join } from 'path';
|
||||
|
||||
function fsPath(filePath: string): string {
|
||||
if (process.platform !== 'win32') return filePath;
|
||||
if (!filePath) return filePath;
|
||||
if (filePath.startsWith('\\\\?\\')) return filePath;
|
||||
const windowsPath = filePath.replace(/\//g, '\\');
|
||||
if (!path.win32.isAbsolute(windowsPath)) return windowsPath;
|
||||
if (windowsPath.startsWith('\\\\')) {
|
||||
return `\\\\?\\UNC\\${windowsPath.slice(2)}`;
|
||||
}
|
||||
return `\\\\?\\${windowsPath}`;
|
||||
}
|
||||
import { linkDirSafe, normalizeFsPath as fsPath } from './fs-link';
|
||||
import { getAllSettings } from '../utils/store';
|
||||
import { getApiKey, getDefaultProvider, getProvider } from '../utils/secure-storage';
|
||||
import { getProviderEnvVar, getKeyableProviderTypes } from '../utils/provider-registry';
|
||||
@@ -245,7 +234,7 @@ function ensureExtensionDepsResolvable(openclawDir: string): void {
|
||||
if (existsSync(dest)) continue;
|
||||
try {
|
||||
mkdirSync(join(topNM, pkg.name), { recursive: true });
|
||||
symlinkSync(join(scopeDir, sub.name), dest);
|
||||
linkDirSafe(join(scopeDir, sub.name), dest);
|
||||
linkedCount++;
|
||||
} catch { /* skip on error — non-fatal */ }
|
||||
}
|
||||
@@ -254,7 +243,7 @@ function ensureExtensionDepsResolvable(openclawDir: string): void {
|
||||
if (existsSync(dest)) continue;
|
||||
try {
|
||||
mkdirSync(topNM, { recursive: true });
|
||||
symlinkSync(join(extNM, pkg.name), dest);
|
||||
linkDirSafe(join(extNM, pkg.name), dest);
|
||||
linkedCount++;
|
||||
} catch { /* skip on error — non-fatal */ }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user