( channelOrVersion: string, forceReinstall: boolean = false, )
| 493 | } |
| 494 | |
| 495 | async function updateLatest( |
| 496 | channelOrVersion: string, |
| 497 | forceReinstall: boolean = false, |
| 498 | ): Promise<{ |
| 499 | success: boolean |
| 500 | latestVersion: string |
| 501 | lockFailed?: boolean |
| 502 | lockHolderPid?: number |
| 503 | }> { |
| 504 | const startTime = Date.now() |
| 505 | let version = await getLatestVersion(channelOrVersion) |
| 506 | const { executable: executablePath } = getBaseDirectories() |
| 507 | |
| 508 | logForDebugging(`Checking for native installer update to version ${version}`) |
| 509 | |
| 510 | // Check if max version is set (server-side kill switch for auto-updates) |
| 511 | if (!forceReinstall) { |
| 512 | const maxVersion = await getMaxVersion() |
| 513 | if (maxVersion && gt(version, maxVersion)) { |
| 514 | logForDebugging( |
| 515 | `Native installer: maxVersion ${maxVersion} is set, capping update from ${version} to ${maxVersion}`, |
| 516 | ) |
| 517 | // If we're already at or above maxVersion, skip the update entirely |
| 518 | if (gte(MACRO.VERSION, maxVersion)) { |
| 519 | logForDebugging( |
| 520 | `Native installer: current version ${MACRO.VERSION} is already at or above maxVersion ${maxVersion}, skipping update`, |
| 521 | ) |
| 522 | logEvent('tengu_native_update_skipped_max_version', { |
| 523 | latency_ms: Date.now() - startTime, |
| 524 | max_version: |
| 525 | maxVersion as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, |
| 526 | available_version: |
| 527 | version as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, |
| 528 | }) |
| 529 | return { success: true, latestVersion: version } |
| 530 | } |
| 531 | version = maxVersion |
| 532 | } |
| 533 | } |
| 534 | |
| 535 | // Early exit: if we're already running this exact version AND both the version binary |
| 536 | // and executable exist and are valid. We need to proceed if the executable doesn't exist, |
| 537 | // is invalid (e.g., empty/corrupted from a failed install), or we're running via npx. |
| 538 | if ( |
| 539 | !forceReinstall && |
| 540 | version === MACRO.VERSION && |
| 541 | (await versionIsAvailable(version)) && |
| 542 | (await isPossibleClaudeBinary(executablePath)) |
| 543 | ) { |
| 544 | logForDebugging(`Found ${version} at ${executablePath}, skipping install`) |
| 545 | logEvent('tengu_native_update_complete', { |
| 546 | latency_ms: Date.now() - startTime, |
| 547 | was_new_install: false, |
| 548 | was_force_reinstall: false, |
| 549 | was_already_running: true, |
| 550 | }) |
| 551 | return { success: true, latestVersion: version } |
| 552 | } |
no test coverage detected