@@ -63,6 +63,7 @@ const DEFAULT_CONFIG: BinaryManagerConfig = {
6363 binPath : getBinDir ( ) ,
6464 maxRetries : 3 ,
6565 verbose : false ,
66+ forceVersion : false ,
6667} ;
6768
6869/**
@@ -88,6 +89,12 @@ export class BinaryManager {
8889 if ( fs . existsSync ( binaryPath ) ) {
8990 this . log ( `Binary exists: ${ binaryPath } ` ) ;
9091
92+ // Skip auto-update if forceVersion is set (user requested specific version)
93+ if ( this . config . forceVersion ) {
94+ this . log ( `Force version mode: skipping auto-update` ) ;
95+ return this . getBinaryPath ( ) ;
96+ }
97+
9198 // Check for updates in background (non-blocking for UX)
9299 try {
93100 const updateResult = await this . checkForUpdates ( ) ;
@@ -114,16 +121,21 @@ export class BinaryManager {
114121 // Download, verify, extract
115122 this . log ( 'Binary not found, downloading...' ) ;
116123
117- // Check latest version before first download
118- try {
119- const latestVersion = await this . fetchLatestVersion ( ) ;
120- if ( latestVersion && this . isNewerVersion ( latestVersion , this . config . version ) ) {
121- this . log ( `Using latest version: ${ latestVersion } (instead of ${ this . config . version } )` ) ;
122- this . config . version = latestVersion ;
124+ // Skip auto-upgrade to latest if forceVersion is set
125+ if ( ! this . config . forceVersion ) {
126+ // Check latest version before first download
127+ try {
128+ const latestVersion = await this . fetchLatestVersion ( ) ;
129+ if ( latestVersion && this . isNewerVersion ( latestVersion , this . config . version ) ) {
130+ this . log ( `Using latest version: ${ latestVersion } (instead of ${ this . config . version } )` ) ;
131+ this . config . version = latestVersion ;
132+ }
133+ } catch {
134+ // Use pinned version if API fails
135+ this . log ( `Using pinned version: ${ this . config . version } ` ) ;
123136 }
124- } catch {
125- // Use pinned version if API fails
126- this . log ( `Using pinned version: ${ this . config . version } ` ) ;
137+ } else {
138+ this . log ( `Force version mode: using specified version ${ this . config . version } ` ) ;
127139 }
128140
129141 await this . downloadAndInstall ( ) ;
@@ -900,4 +912,54 @@ export function getCLIProxyPath(): string {
900912 return manager . getBinaryPath ( ) ;
901913}
902914
915+ /**
916+ * Get installed CLIProxyAPI version from .version file
917+ * Returns the fallback version if not installed or version file missing
918+ */
919+ export function getInstalledCliproxyVersion ( ) : string {
920+ const versionFile = path . join ( getBinDir ( ) , '.version' ) ;
921+ if ( fs . existsSync ( versionFile ) ) {
922+ try {
923+ return fs . readFileSync ( versionFile , 'utf8' ) . trim ( ) ;
924+ } catch {
925+ return CLIPROXY_FALLBACK_VERSION ;
926+ }
927+ }
928+ return CLIPROXY_FALLBACK_VERSION ;
929+ }
930+
931+ /**
932+ * Install a specific version of CLIProxyAPI
933+ * Deletes existing binary and downloads the specified version
934+ *
935+ * @param version Version to install (e.g., "6.5.40")
936+ * @param verbose Enable verbose logging
937+ */
938+ export async function installCliproxyVersion ( version : string , verbose = false ) : Promise < void > {
939+ // Use forceVersion to prevent auto-upgrade to latest
940+ const manager = new BinaryManager ( { version, verbose, forceVersion : true } ) ;
941+
942+ // Delete existing binary if present
943+ if ( manager . isBinaryInstalled ( ) ) {
944+ const currentVersion = getInstalledCliproxyVersion ( ) ;
945+ if ( verbose ) {
946+ console . log ( `[i] Removing existing CLIProxyAPI v${ currentVersion } ` ) ;
947+ }
948+ manager . deleteBinary ( ) ;
949+ }
950+
951+ // Install specified version (forceVersion prevents auto-upgrade)
952+ await manager . ensureBinary ( ) ;
953+ }
954+
955+ /**
956+ * Fetch the latest CLIProxyAPI version from GitHub API
957+ * @returns Latest version string (e.g., "6.5.40")
958+ */
959+ export async function fetchLatestCliproxyVersion ( ) : Promise < string > {
960+ const manager = new BinaryManager ( ) ;
961+ const result = await manager . checkForUpdates ( ) ;
962+ return result . latestVersion ;
963+ }
964+
903965export default BinaryManager ;
0 commit comments