fix: preserve CLIProxy platform arch compatibility

This commit is contained in:
Tam Nhu Tran committed 2026-05-04 11:39:47 -04:00
1 parent 4a0620d6c5
commit 9a687fc03c
3 files changed
+49 -13

No files matched your search

+17 -9
View File
@@ -2,7 +2,7 @@
* Platform Detector for CLIProxyAPI Binary Downloads * Platform Detector for CLIProxyAPI Binary Downloads
* *
* Detects OS and architecture to determine correct binary asset. * Detects OS and architecture to determine correct binary asset.
* Supports 6 platforms: darwin/linux/windows x amd64/aarch64 * Supports 6 platforms: darwin/linux/windows x amd64/arm64
*/ */
import { import {
@@ -64,9 +64,7 @@ export const CLIPROXY_FAULTY_RANGE = { min: '6.6.81-0', max: '6.6.88-0' };
/** @deprecated Use CLIPROXY_FALLBACK_VERSION instead */ /** @deprecated Use CLIPROXY_FALLBACK_VERSION instead */
export const CLIPROXY_VERSION = CLIPROXY_FALLBACK_VERSION; export const CLIPROXY_VERSION = CLIPROXY_FALLBACK_VERSION;
/** /** Platform mapping from Node.js values to CCS public architecture labels. */
* Platform mapping from Node.js values to CLIProxyAPI naming
*/
const OS_MAP: Record<string, SupportedOS | undefined> = { const OS_MAP: Record<string, SupportedOS | undefined> = {
darwin: 'darwin', darwin: 'darwin',
linux: 'linux', linux: 'linux',
@@ -75,11 +73,19 @@ const OS_MAP: Record<string, SupportedOS | undefined> = {
const ARCH_MAP: Record<string, SupportedArch | undefined> = { const ARCH_MAP: Record<string, SupportedArch | undefined> = {
x64: 'amd64', x64: 'amd64',
arm64: 'arm64',
};
/** CLIProxy release assets use aarch64 while Node.js reports arm64. */
const RELEASE_ARCH_MAP: Record<SupportedArch, SupportedArch> = {
amd64: 'amd64',
arm64: 'aarch64', arm64: 'aarch64',
aarch64: 'aarch64',
}; };
export function mapNodeArchToReleaseArch(nodeArch: string): SupportedArch | undefined { export function mapNodeArchToReleaseArch(nodeArch: string): SupportedArch | undefined {
return ARCH_MAP[nodeArch]; const arch = ARCH_MAP[nodeArch];
return arch ? RELEASE_ARCH_MAP[arch] : undefined;
} }
/** /**
@@ -96,7 +102,8 @@ export function detectPlatform(
const nodeArch = process.arch; const nodeArch = process.arch;
const os = OS_MAP[nodePlatform]; const os = OS_MAP[nodePlatform];
const arch = mapNodeArchToReleaseArch(nodeArch); const arch = ARCH_MAP[nodeArch];
const releaseArch = mapNodeArchToReleaseArch(nodeArch);
if (!os) { if (!os) {
throw new Error( throw new Error(
@@ -105,7 +112,7 @@ export function detectPlatform(
); );
} }
if (!arch) { if (!arch || !releaseArch) {
throw new Error( throw new Error(
`Unsupported CPU architecture: ${nodeArch}\n` + `Supported: x64 (amd64), arm64 (aarch64)` `Unsupported CPU architecture: ${nodeArch}\n` + `Supported: x64 (amd64), arm64 (aarch64)`
); );
@@ -114,7 +121,7 @@ export function detectPlatform(
const config = BACKEND_CONFIG[backend]; const config = BACKEND_CONFIG[backend];
const ver = version || config.fallbackVersion; const ver = version || config.fallbackVersion;
const extension: ArchiveExtension = os === 'windows' ? 'zip' : 'tar.gz'; const extension: ArchiveExtension = os === 'windows' ? 'zip' : 'tar.gz';
const binaryName = `${config.binaryPrefix}_${ver}_${os}_${arch}.${extension}`; const binaryName = `${config.binaryPrefix}_${ver}_${os}_${releaseArch}.${extension}`;
return { return {
os, os,
@@ -206,7 +213,8 @@ export function getPlatformDescription(): string {
const platform = detectPlatform(); const platform = detectPlatform();
const osName = const osName =
platform.os === 'darwin' ? 'macOS' : platform.os === 'linux' ? 'Linux' : 'Windows'; platform.os === 'darwin' ? 'macOS' : platform.os === 'linux' ? 'Linux' : 'Windows';
const archName = platform.arch === 'aarch64' ? 'ARM64' : platform.arch; const archName =
platform.arch === 'arm64' || platform.arch === 'aarch64' ? 'ARM64' : platform.arch;
return `${osName} ${archName}`; return `${osName} ${archName}`;
} catch { } catch {
return `${process.platform} ${process.arch} (unsupported)`; return `${process.platform} ${process.arch} (unsupported)`;
@@ -9,6 +9,21 @@ describe('Backend Selection', () => {
const platformDetector = require('../../../../dist/cliproxy/binary/platform-detector'); const platformDetector = require('../../../../dist/cliproxy/binary/platform-detector');
const types = require('../../../../dist/cliproxy/types'); const types = require('../../../../dist/cliproxy/types');
function withMockedProcessPlatform(platform, arch, callback) {
const originalPlatform = Object.getOwnPropertyDescriptor(process, 'platform');
const originalArch = Object.getOwnPropertyDescriptor(process, 'arch');
Object.defineProperty(process, 'platform', { value: platform, configurable: true });
Object.defineProperty(process, 'arch', { value: arch, configurable: true });
try {
callback();
} finally {
Object.defineProperty(process, 'platform', originalPlatform);
Object.defineProperty(process, 'arch', originalArch);
}
}
describe('BACKEND_CONFIG', () => { describe('BACKEND_CONFIG', () => {
it('has correct configuration for original backend', () => { it('has correct configuration for original backend', () => {
const config = platformDetector.BACKEND_CONFIG.original; const config = platformDetector.BACKEND_CONFIG.original;
@@ -39,6 +54,19 @@ describe('Backend Selection', () => {
assert.strictEqual(platformDetector.mapNodeArchToReleaseArch('x64'), 'amd64'); assert.strictEqual(platformDetector.mapNodeArchToReleaseArch('x64'), 'amd64');
}); });
it('keeps public ARM64 arch compatibility while using aarch64 release assets', () => {
withMockedProcessPlatform('darwin', 'arm64', () => {
const info = platformDetector.detectPlatform('6.10.4', 'original');
assert.strictEqual(info.arch, 'arm64');
assert.strictEqual(info.binaryName, 'CLIProxyAPI_6.10.4_darwin_aarch64.tar.gz');
assert.strictEqual(
platformDetector.getDownloadUrl('6.10.4', 'original'),
'https://github.com/router-for-me/CLIProxyAPI/releases/download/v6.10.4/CLIProxyAPI_6.10.4_darwin_aarch64.tar.gz'
);
});
});
it('generates correct binary name for original backend', () => { it('generates correct binary name for original backend', () => {
const info = platformDetector.detectPlatform('6.6.51', 'original'); const info = platformDetector.detectPlatform('6.6.51', 'original');
assert(info.binaryName.startsWith('CLIProxyAPI_6.6.51_')); assert(info.binaryName.startsWith('CLIProxyAPI_6.6.51_'));
@@ -34,8 +34,8 @@ import { PLUS_ONLY_PROVIDERS } from '../../types';
describe('types.ts backward compatibility', () => { describe('types.ts backward compatibility', () => {
it('exports all platform types', () => { it('exports all platform types', () => {
const os: SupportedOS = 'darwin'; const os: SupportedOS = 'darwin';
const arch: SupportedArch = 'aarch64'; const arch: SupportedArch = 'arm64';
const nodeArch: SupportedArch = 'arm64'; const releaseArch: SupportedArch = 'aarch64';
const ext: ArchiveExtension = 'tar.gz'; const ext: ArchiveExtension = 'tar.gz';
const info: PlatformInfo = { const info: PlatformInfo = {
os, os,
@@ -44,8 +44,8 @@ describe('types.ts backward compatibility', () => {
extension: ext, extension: ext,
}; };
expect(info.os).toBe('darwin'); expect(info.os).toBe('darwin');
expect(info.arch).toBe('aarch64'); expect(info.arch).toBe('arm64');
expect(nodeArch).toBe('arm64'); expect(releaseArch).toBe('aarch64');
}); });
it('exports all binary types', () => { it('exports all binary types', () => {