Something went wrong. Try again.
source dump of claude code forked from oppi.li/claude-code
Something went wrong. Try again.
15 kB · 439 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440/** * Auto-install logic for the official Anthropic marketplace. * * This module handles automatically installing the official marketplace * on startup for new users, with appropriate checks for: * - Enterprise policy restrictions * - Git availability * - Previous installation attempts */
import { join } from 'path'import { getFeatureValue_CACHED_MAY_BE_STALE } from '../../services/analytics/growthbook.js'import { logEvent } from '../../services/analytics/index.js'import { getGlobalConfig, saveGlobalConfig } from '../config.js'import { logForDebugging } from '../debug.js'import { isEnvTruthy } from '../envUtils.js'import { toError } from '../errors.js'import { logError } from '../log.js'import { checkGitAvailable, markGitUnavailable } from './gitAvailability.js'import { isSourceAllowedByPolicy } from './marketplaceHelpers.js'import { addMarketplaceSource, getMarketplacesCacheDir, loadKnownMarketplacesConfig, saveKnownMarketplacesConfig,} from './marketplaceManager.js'import { OFFICIAL_MARKETPLACE_NAME, OFFICIAL_MARKETPLACE_SOURCE,} from './officialMarketplace.js'import { fetchOfficialMarketplaceFromGcs } from './officialMarketplaceGcs.js'
/** * Reason why the official marketplace was not installed */export type OfficialMarketplaceSkipReason = | 'already_attempted' | 'already_installed' | 'policy_blocked' | 'git_unavailable' | 'gcs_unavailable' | 'unknown'
/** * Check if official marketplace auto-install is disabled via environment variable. */export function isOfficialMarketplaceAutoInstallDisabled(): boolean { return isEnvTruthy( process.env.CLAUDE_CODE_DISABLE_OFFICIAL_MARKETPLACE_AUTOINSTALL, )}
/** * Configuration for retry logic */export const RETRY_CONFIG = { MAX_ATTEMPTS: 10, INITIAL_DELAY_MS: 60 * 60 * 1000, // 1 hour BACKOFF_MULTIPLIER: 2, MAX_DELAY_MS: 7 * 24 * 60 * 60 * 1000, // 1 week}
/** * Calculate next retry delay using exponential backoff */function calculateNextRetryDelay(retryCount: number): number { const delay = RETRY_CONFIG.INITIAL_DELAY_MS * Math.pow(RETRY_CONFIG.BACKOFF_MULTIPLIER, retryCount) return Math.min(delay, RETRY_CONFIG.MAX_DELAY_MS)}
/** * Determine if installation should be retried based on failure reason and retry state */function shouldRetryInstallation( config: ReturnType<typeof getGlobalConfig>,): boolean { // If never attempted, should try if (!config.officialMarketplaceAutoInstallAttempted) { return true }
// If already installed successfully, don't retry if (config.officialMarketplaceAutoInstalled) { return false }
const failReason = config.officialMarketplaceAutoInstallFailReason const retryCount = config.officialMarketplaceAutoInstallRetryCount || 0 const nextRetryTime = config.officialMarketplaceAutoInstallNextRetryTime const now = Date.now()
// Check if we've exceeded max attempts if (retryCount >= RETRY_CONFIG.MAX_ATTEMPTS) { return false }
// Permanent failures - don't retry if (failReason === 'policy_blocked') { return false }
// Check if enough time has passed for next retry if (nextRetryTime && now < nextRetryTime) { return false }
// Retry for temporary failures (unknown), semi-permanent (git_unavailable), // and legacy state (undefined failReason from before retry logic existed) return ( failReason === 'unknown' || failReason === 'git_unavailable' || failReason === 'gcs_unavailable' || failReason === undefined )}
/** * Result of the auto-install check */export type OfficialMarketplaceCheckResult = { /** Whether the marketplace was successfully installed */ installed: boolean /** Whether the installation was skipped (and why) */ skipped: boolean /** Reason for skipping, if applicable */ reason?: OfficialMarketplaceSkipReason /** Whether saving retry metadata to config failed */ configSaveFailed?: boolean}
/** * Check and install the official marketplace on startup. * * This function is designed to be called as a fire-and-forget operation * during startup. It will: * 1. Check if installation was already attempted * 2. Check if marketplace is already installed * 3. Check enterprise policy restrictions * 4. Check git availability * 5. Attempt installation * 6. Record the result in GlobalConfig * * @returns Result indicating whether installation succeeded or was skipped */export async function checkAndInstallOfficialMarketplace(): Promise<OfficialMarketplaceCheckResult> { const config = getGlobalConfig()
// Check if we should retry installation if (!shouldRetryInstallation(config)) { const reason: OfficialMarketplaceSkipReason = config.officialMarketplaceAutoInstallFailReason ?? 'already_attempted' logForDebugging(`Official marketplace auto-install skipped: ${reason}`) return { installed: false, skipped: true, reason, } }
try { // Check if auto-install is disabled via env var if (isOfficialMarketplaceAutoInstallDisabled()) { logForDebugging( 'Official marketplace auto-install disabled via env var, skipping', ) saveGlobalConfig(current => ({ ...current, officialMarketplaceAutoInstallAttempted: true, officialMarketplaceAutoInstalled: false, officialMarketplaceAutoInstallFailReason: 'policy_blocked', })) logEvent('tengu_official_marketplace_auto_install', { installed: false, skipped: true, policy_blocked: true, }) return { installed: false, skipped: true, reason: 'policy_blocked' } }
// Check if marketplace is already installed const knownMarketplaces = await loadKnownMarketplacesConfig() if (knownMarketplaces[OFFICIAL_MARKETPLACE_NAME]) { logForDebugging( `Official marketplace '${OFFICIAL_MARKETPLACE_NAME}' already installed, skipping`, ) // Mark as attempted so we don't check again saveGlobalConfig(current => ({ ...current, officialMarketplaceAutoInstallAttempted: true, officialMarketplaceAutoInstalled: true, })) return { installed: false, skipped: true, reason: 'already_installed' } }
// Check enterprise policy restrictions if (!isSourceAllowedByPolicy(OFFICIAL_MARKETPLACE_SOURCE)) { logForDebugging( 'Official marketplace blocked by enterprise policy, skipping', ) saveGlobalConfig(current => ({ ...current, officialMarketplaceAutoInstallAttempted: true, officialMarketplaceAutoInstalled: false, officialMarketplaceAutoInstallFailReason: 'policy_blocked', })) logEvent('tengu_official_marketplace_auto_install', { installed: false, skipped: true, policy_blocked: true, }) return { installed: false, skipped: true, reason: 'policy_blocked' } }
// inc-5046: try GCS mirror first — doesn't need git, doesn't hit GitHub. // Backend (anthropic#317037) publishes a marketplace zip to the same // bucket as the native binary. If GCS succeeds, register the marketplace // with source:'github' (still true — GCS is a mirror) and skip git // entirely. const cacheDir = getMarketplacesCacheDir() const installLocation = join(cacheDir, OFFICIAL_MARKETPLACE_NAME) const gcsSha = await fetchOfficialMarketplaceFromGcs( installLocation, cacheDir, ) if (gcsSha !== null) { const known = await loadKnownMarketplacesConfig() known[OFFICIAL_MARKETPLACE_NAME] = { source: OFFICIAL_MARKETPLACE_SOURCE, installLocation, lastUpdated: new Date().toISOString(), } await saveKnownMarketplacesConfig(known)
saveGlobalConfig(current => ({ ...current, officialMarketplaceAutoInstallAttempted: true, officialMarketplaceAutoInstalled: true, officialMarketplaceAutoInstallFailReason: undefined, officialMarketplaceAutoInstallRetryCount: undefined, officialMarketplaceAutoInstallLastAttemptTime: undefined, officialMarketplaceAutoInstallNextRetryTime: undefined, })) logEvent('tengu_official_marketplace_auto_install', { installed: true, skipped: false, via_gcs: true, }) return { installed: true, skipped: false } } // GCS failed (404 until backend writes, or network). Fall through to git // ONLY if the kill-switch allows — same gate as refreshMarketplace(). if ( !getFeatureValue_CACHED_MAY_BE_STALE( 'tengu_plugin_official_mkt_git_fallback', true, ) ) { logForDebugging( 'Official marketplace GCS failed; git fallback disabled by flag — skipping install', ) // Same retry-with-backoff metadata as git_unavailable below — transient // GCS failures should retry with exponential backoff, not give up. const retryCount = (config.officialMarketplaceAutoInstallRetryCount || 0) + 1 const now = Date.now() const nextRetryTime = now + calculateNextRetryDelay(retryCount) saveGlobalConfig(current => ({ ...current, officialMarketplaceAutoInstallAttempted: true, officialMarketplaceAutoInstalled: false, officialMarketplaceAutoInstallFailReason: 'gcs_unavailable', officialMarketplaceAutoInstallRetryCount: retryCount, officialMarketplaceAutoInstallLastAttemptTime: now, officialMarketplaceAutoInstallNextRetryTime: nextRetryTime, })) logEvent('tengu_official_marketplace_auto_install', { installed: false, skipped: true, gcs_unavailable: true, retry_count: retryCount, }) return { installed: false, skipped: true, reason: 'gcs_unavailable' } }
// Check git availability const gitAvailable = await checkGitAvailable() if (!gitAvailable) { logForDebugging( 'Git not available, skipping official marketplace auto-install', ) const retryCount = (config.officialMarketplaceAutoInstallRetryCount || 0) + 1 const now = Date.now() const nextRetryDelay = calculateNextRetryDelay(retryCount) const nextRetryTime = now + nextRetryDelay
let configSaveFailed = false try { saveGlobalConfig(current => ({ ...current, officialMarketplaceAutoInstallAttempted: true, officialMarketplaceAutoInstalled: false, officialMarketplaceAutoInstallFailReason: 'git_unavailable', officialMarketplaceAutoInstallRetryCount: retryCount, officialMarketplaceAutoInstallLastAttemptTime: now, officialMarketplaceAutoInstallNextRetryTime: nextRetryTime, })) } catch (saveError) { configSaveFailed = true // Log the error properly so it gets tracked const configError = toError(saveError) logError(configError)
logForDebugging( `Failed to save marketplace auto-install git_unavailable state: ${saveError}`, { level: 'error' }, ) } logEvent('tengu_official_marketplace_auto_install', { installed: false, skipped: true, git_unavailable: true, retry_count: retryCount, }) return { installed: false, skipped: true, reason: 'git_unavailable', configSaveFailed, } }
// Attempt installation logForDebugging('Attempting to auto-install official marketplace') await addMarketplaceSource(OFFICIAL_MARKETPLACE_SOURCE)
// Success logForDebugging('Successfully auto-installed official marketplace') const previousRetryCount = config.officialMarketplaceAutoInstallRetryCount || 0 saveGlobalConfig(current => ({ ...current, officialMarketplaceAutoInstallAttempted: true, officialMarketplaceAutoInstalled: true, // Clear retry metadata on success officialMarketplaceAutoInstallFailReason: undefined, officialMarketplaceAutoInstallRetryCount: undefined, officialMarketplaceAutoInstallLastAttemptTime: undefined, officialMarketplaceAutoInstallNextRetryTime: undefined, })) logEvent('tengu_official_marketplace_auto_install', { installed: true, skipped: false, retry_count: previousRetryCount, }) return { installed: true, skipped: false } } catch (error) { // Handle installation failure const errorMessage = error instanceof Error ? error.message : String(error)
// On macOS, /usr/bin/git is an xcrun shim that always exists on PATH, so // checkGitAvailable() (which only does `which git`) passes even without // Xcode CLT installed. The shim then fails at clone time with // "xcrun: error: invalid active developer path (...)". Poison the memoized // availability check so other git callers in this session skip cleanly, // then return silently without recording any attempt state — next startup // tries fresh (no backoff machinery for what is effectively "git absent"). if (errorMessage.includes('xcrun: error:')) { markGitUnavailable() logForDebugging( 'Official marketplace auto-install: git is a non-functional macOS xcrun shim, treating as git_unavailable', ) logEvent('tengu_official_marketplace_auto_install', { installed: false, skipped: true, git_unavailable: true, macos_xcrun_shim: true, }) return { installed: false, skipped: true, reason: 'git_unavailable', } }
logForDebugging( `Failed to auto-install official marketplace: ${errorMessage}`, { level: 'error' }, ) logError(toError(error))
const retryCount = (config.officialMarketplaceAutoInstallRetryCount || 0) + 1 const now = Date.now() const nextRetryDelay = calculateNextRetryDelay(retryCount) const nextRetryTime = now + nextRetryDelay
let configSaveFailed = false try { saveGlobalConfig(current => ({ ...current, officialMarketplaceAutoInstallAttempted: true, officialMarketplaceAutoInstalled: false, officialMarketplaceAutoInstallFailReason: 'unknown', officialMarketplaceAutoInstallRetryCount: retryCount, officialMarketplaceAutoInstallLastAttemptTime: now, officialMarketplaceAutoInstallNextRetryTime: nextRetryTime, })) } catch (saveError) { configSaveFailed = true // Log the error properly so it gets tracked const configError = toError(saveError) logError(configError)
logForDebugging( `Failed to save marketplace auto-install failure state: ${saveError}`, { level: 'error' }, )
// Still return the failure result even if config save failed // This ensures we report the installation failure correctly } logEvent('tengu_official_marketplace_auto_install', { installed: false, skipped: true, failed: true, retry_count: retryCount, })
return { installed: false, skipped: true, reason: 'unknown', configSaveFailed, } }}