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

@@ -8,6 +8,14 @@ const BASE_URL = `https://nodejs.org/dist/v${NODE_VERSION}`;
const OUTPUT_BASE = path.join(ROOT_DIR, 'resources', 'bin');
const TARGETS = {
'darwin-x64': {
filename: `node-v${NODE_VERSION}-darwin-x64.tar.gz`,
sourceDir: `node-v${NODE_VERSION}-darwin-x64`,
},
'darwin-arm64': {
filename: `node-v${NODE_VERSION}-darwin-arm64.tar.gz`,
sourceDir: `node-v${NODE_VERSION}-darwin-arm64`,
},
'win32-x64': {
filename: `node-v${NODE_VERSION}-win-x64.zip`,
sourceDir: `node-v${NODE_VERSION}-win-x64`,
@@ -19,6 +27,7 @@ const TARGETS = {
};
const PLATFORM_GROUPS = {
mac: ['darwin-x64', 'darwin-arm64'],
win: ['win32-x64', 'win32-arm64'],
};
@@ -36,11 +45,14 @@ async function setupTarget(id) {
echo(chalk.blue`\n📦 Setting up Node.js for ${id}...`);
// Only remove the target binary, not the entire directory,
// to avoid deleting uv.exe or other binaries placed by other download scripts.
const outputNode = path.join(targetDir, 'node.exe');
if (await fs.pathExists(outputNode)) {
await fs.remove(outputNode);
const outputNode = path.join(targetDir, id.startsWith('win32-') ? 'node.exe' : 'node');
const outputNpmDir = path.join(targetDir, 'lib', 'node_modules', 'npm');
const outputNpmCli = path.join(outputNpmDir, 'bin', 'npm-cli.js');
if (process.env.FORCE_BUNDLED_NODE_REFRESH !== '1'
&& await fs.pathExists(outputNode)
&& await fs.pathExists(outputNpmCli)) {
echo(chalk.green`✅ Already prepared: ${outputNode}`);
return;
}
await fs.remove(tempDir);
await fs.ensureDir(targetDir);
@@ -48,33 +60,52 @@ async function setupTarget(id) {
try {
echo`⬇️ Downloading: ${downloadUrl}`;
const response = await fetch(downloadUrl);
if (!response.ok) throw new Error(`Failed to download: ${response.statusText}`);
const response = await fetchWithRetry(downloadUrl);
const buffer = await response.arrayBuffer();
await fs.writeFile(archivePath, Buffer.from(buffer));
echo`📂 Extracting...`;
if (os.platform() === 'win32') {
if (target.filename.endsWith('.zip')) {
const { execFileSync } = await import('child_process');
const psCommand = `Add-Type -AssemblyName System.IO.Compression.FileSystem; [System.IO.Compression.ZipFile]::ExtractToDirectory('${archivePath.replace(/'/g, "''")}', '${tempDir.replace(/'/g, "''")}')`;
execFileSync('powershell.exe', ['-NoProfile', '-Command', psCommand], { stdio: 'inherit' });
if (os.platform() === 'win32') {
const psCommand = `Add-Type -AssemblyName System.IO.Compression.FileSystem; [System.IO.Compression.ZipFile]::ExtractToDirectory('${archivePath.replace(/'/g, "''")}', '${tempDir.replace(/'/g, "''")}')`;
execFileSync('powershell.exe', ['-NoProfile', '-Command', psCommand], { stdio: 'inherit' });
} else {
await $`unzip -q -o ${archivePath} -d ${tempDir}`;
}
} else {
await $`unzip -q -o ${archivePath} -d ${tempDir}`;
await $`tar -xzf ${archivePath} -C ${tempDir}`;
}
const expectedNode = path.join(tempDir, target.sourceDir, 'node.exe');
const nodeFileName = id.startsWith('win32-') ? 'node.exe' : 'node';
const expectedNode = path.join(tempDir, target.sourceDir, 'bin', nodeFileName);
const legacyExpectedNode = path.join(tempDir, target.sourceDir, nodeFileName);
if (await fs.pathExists(expectedNode)) {
await fs.move(expectedNode, outputNode, { overwrite: true });
} else if (await fs.pathExists(legacyExpectedNode)) {
await fs.move(legacyExpectedNode, outputNode, { overwrite: true });
} else {
echo(chalk.yellow`🔍 node.exe not found in expected directory, searching...`);
const files = await glob('**/node.exe', { cwd: tempDir, absolute: true });
echo(chalk.yellow`🔍 ${nodeFileName} not found in expected directory, searching...`);
const files = await glob(`**/${nodeFileName}`, { cwd: tempDir, absolute: true });
if (files.length > 0) {
await fs.move(files[0], outputNode, { overwrite: true });
} else {
throw new Error('Could not find node.exe in extracted files.');
throw new Error(`Could not find ${nodeFileName} in extracted files.`);
}
}
if (!id.startsWith('win32-')) {
await fs.chmod(outputNode, 0o755);
}
const sourceNpmDir = path.join(tempDir, target.sourceDir, 'lib', 'node_modules', 'npm');
if (await fs.pathExists(sourceNpmDir)) {
await fs.ensureDir(path.dirname(outputNpmDir));
await fs.copy(sourceNpmDir, outputNpmDir, { overwrite: true });
} else {
echo(chalk.yellow`⚠️ npm package not found in Node archive for ${id}; only node binary was copied.`);
}
echo(chalk.green`✅ Success: ${outputNode}`);
} finally {
await fs.remove(archivePath);
@@ -82,11 +113,32 @@ async function setupTarget(id) {
}
}
async function fetchWithRetry(url, attempts = 3) {
let lastError;
for (let attempt = 1; attempt <= attempts; attempt += 1) {
try {
const response = await fetch(url);
if (!response.ok) throw new Error(`Failed to download: ${response.status} ${response.statusText}`);
return response;
} catch (error) {
lastError = error;
if (attempt < attempts) {
echo(chalk.yellow`⚠️ Download failed (attempt ${attempt}/${attempts}), retrying...`);
await new Promise((resolve) => setTimeout(resolve, 1500 * attempt));
}
}
}
throw lastError;
}
const downloadAll = argv.all;
const platform = argv.platform;
const target = argv.target;
if (downloadAll) {
echo(chalk.cyan`🌐 Downloading Node.js binaries for all Windows targets...`);
if (target) {
await setupTarget(String(target));
} else if (downloadAll) {
echo(chalk.cyan`🌐 Downloading Node.js binaries for all bundled targets...`);
for (const id of Object.keys(TARGETS)) {
await setupTarget(id);
}
@@ -104,7 +156,7 @@ if (downloadAll) {
} else {
const currentId = `${os.platform()}-${os.arch()}`;
if (TARGETS[currentId]) {
echo(chalk.cyan`💻 Detected Windows system: ${currentId}`);
echo(chalk.cyan`💻 Detected system: ${currentId}`);
await setupTarget(currentId);
} else {
echo(chalk.cyan`🎯 Defaulting to Windows multi-arch Node.js download`);