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