From 87f1d9b4e874f63a61d337357796db8e27a4f18f Mon Sep 17 00:00:00 2001 From: Tam Nhu Tran Date: Wed, 2 Sep 2026 11:10:29 -0400 Subject: [PATCH] fix(cliproxy): correct ARM release asset architecture boundaries (#1725) --- src/cliproxy/binary/platform-detector.ts | 8 +- .../__tests__/backend-selection.test.js | 73 ++++++++++++++++++- 2 files changed, 77 insertions(+), 4 deletions(-) diff --git a/src/cliproxy/binary/platform-detector.ts b/src/cliproxy/binary/platform-detector.ts index fdb78d83..9721afb0 100644 --- a/src/cliproxy/binary/platform-detector.ts +++ b/src/cliproxy/binary/platform-detector.ts @@ -84,7 +84,10 @@ const RELEASE_ARCH_MAP: Record = { }; const PLUS_NO_PLUGIN_ASSET_MIN_VERSION = '7.1.68-0'; -const PLUS_AARCH64_ASSET_MIN_VERSION = '7.1.45-1'; +const AARCH64_ASSET_MIN_VERSION: Readonly> = { + original: '6.9.48', + plus: '6.10.0-0', +}; export function mapNodeArchToReleaseArch(nodeArch: string): SupportedArch | undefined { const arch = ARCH_MAP[nodeArch]; @@ -122,9 +125,8 @@ function getReleaseArchForBackend( releaseArch: SupportedArch ): SupportedArch { if ( - backend === 'plus' && publicArch === 'arm64' && - !isAtLeastVersion(version, PLUS_AARCH64_ASSET_MIN_VERSION) + !isAtLeastVersion(version, AARCH64_ASSET_MIN_VERSION[backend]) ) { return 'arm64'; } diff --git a/src/cliproxy/config/__tests__/backend-selection.test.js b/src/cliproxy/config/__tests__/backend-selection.test.js index e48d1091..54bec9a0 100644 --- a/src/cliproxy/config/__tests__/backend-selection.test.js +++ b/src/cliproxy/config/__tests__/backend-selection.test.js @@ -86,13 +86,84 @@ describe('Backend Selection', () => { ); }); }); - it('generates correct binary name for original backend', () => { const info = platformDetector.detectPlatform('6.6.51', 'original'); assert(info.binaryName.startsWith('CLIProxyAPI_6.6.51_')); assert(!info.binaryName.includes('CLIProxyAPIPlus')); }); + it('selects arm64 vs aarch64 release assets across original and plus boundaries', () => { + // Original pre-rename boundaries (<= 6.9.47) use arm64 + for (const version of [undefined, '6.9.45', '6.9.47']) { + const effectiveVersion = version || platformDetector.BACKEND_CONFIG.original.fallbackVersion; + withMockedProcessPlatform('darwin', 'arm64', () => { + const info = platformDetector.detectPlatform(version, 'original'); + assert.strictEqual(info.arch, 'arm64'); + assert.strictEqual(info.binaryName, `CLIProxyAPI_${effectiveVersion}_darwin_arm64.tar.gz`); + assert.strictEqual( + platformDetector.getDownloadUrl(version, 'original'), + `https://github.com/router-for-me/CLIProxyAPI/releases/download/v${effectiveVersion}/CLIProxyAPI_${effectiveVersion}_darwin_arm64.tar.gz` + ); + }); + + withMockedProcessPlatform('linux', 'arm64', () => { + const info = platformDetector.detectPlatform(version, 'original'); + assert.strictEqual(info.arch, 'arm64'); + assert.strictEqual(info.binaryName, `CLIProxyAPI_${effectiveVersion}_linux_arm64.tar.gz`); + assert.strictEqual( + platformDetector.getDownloadUrl(version, 'original'), + `https://github.com/router-for-me/CLIProxyAPI/releases/download/v${effectiveVersion}/CLIProxyAPI_${effectiveVersion}_linux_arm64.tar.gz` + ); + }); + + withMockedProcessPlatform('win32', 'arm64', () => { + const info = platformDetector.detectPlatform(version, 'original'); + assert.strictEqual(info.arch, 'arm64'); + assert.strictEqual(info.binaryName, `CLIProxyAPI_${effectiveVersion}_windows_arm64.zip`); + assert.strictEqual( + platformDetector.getDownloadUrl(version, 'original'), + `https://github.com/router-for-me/CLIProxyAPI/releases/download/v${effectiveVersion}/CLIProxyAPI_${effectiveVersion}_windows_arm64.zip` + ); + }); + } + + // Original post-rename boundary (>= 6.9.48) uses aarch64 while public arch remains arm64 + withMockedProcessPlatform('darwin', 'arm64', () => { + const info = platformDetector.detectPlatform('6.9.48', 'original'); + assert.strictEqual(info.arch, 'arm64'); + assert.strictEqual(info.binaryName, 'CLIProxyAPI_6.9.48_darwin_aarch64.tar.gz'); + assert.strictEqual( + platformDetector.getDownloadUrl('6.9.48', 'original'), + 'https://github.com/router-for-me/CLIProxyAPI/releases/download/v6.9.48/CLIProxyAPI_6.9.48_darwin_aarch64.tar.gz' + ); + }); + + // Plus fallback / pre-rename (< 6.10.0-0) uses arm64 + withMockedProcessPlatform('darwin', 'arm64', () => { + const info = platformDetector.detectPlatform('6.9.45-0', 'plus'); + assert.strictEqual(info.arch, 'arm64'); + assert.strictEqual(info.binaryName, 'CLIProxyAPIPlus_6.9.45-0_darwin_arm64.tar.gz'); + }); + + // Plus post-rename (>= 6.10.0-0) uses aarch64 + withMockedProcessPlatform('darwin', 'arm64', () => { + const info = platformDetector.detectPlatform('6.10.0-0', 'plus'); + assert.strictEqual(info.arch, 'arm64'); + assert.strictEqual(info.binaryName, 'CLIProxyAPIPlus_6.10.0-0_darwin_aarch64.tar.gz'); + }); + + // x64 remains amd64 for both backends + withMockedProcessPlatform('linux', 'x64', () => { + assert.strictEqual( + platformDetector.detectPlatform('6.9.45', 'original').binaryName, + 'CLIProxyAPI_6.9.45_linux_amd64.tar.gz' + ); + assert.strictEqual( + platformDetector.detectPlatform('6.9.45-0', 'plus').binaryName, + 'CLIProxyAPIPlus_6.9.45-0_linux_amd64.tar.gz' + ); + }); + }); it('uses static no-plugin assets when the integrated Linux image opts in', () => { withEnvironmentVariable('CCS_CLIPROXY_NO_PLUGIN_ASSET', '1', () => { withMockedProcessPlatform('linux', 'x64', () => {