Something went wrong. Try again.
source dump of claude code forked from oppi.li/claude-code
Something went wrong. Try again.
5.7 kB · 194 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195import { execa } from 'execa'import memoize from 'lodash-es/memoize.js'import { getSessionId } from '../bootstrap/state.js'import { getOauthAccountInfo, getRateLimitTier, getSubscriptionType,} from './auth.js'import { getGlobalConfig, getOrCreateUserID } from './config.js'import { getCwd } from './cwd.js'import { type env, getHostPlatformForAnalytics } from './env.js'import { isEnvTruthy } from './envUtils.js'
// Cache for email fetched asynchronously at startuplet cachedEmail: string | undefined | null = null // null means not fetched yetlet emailFetchPromise: Promise<string | undefined> | null = null
/** * GitHub Actions metadata when running in CI */export type GitHubActionsMetadata = { actor?: string actorId?: string repository?: string repositoryId?: string repositoryOwner?: string repositoryOwnerId?: string}
/** * Core user data used as base for all analytics providers. * This is also the format used by GrowthBook. */export type CoreUserData = { deviceId: string sessionId: string email?: string appVersion: string platform: typeof env.platform organizationUuid?: string accountUuid?: string userType?: string subscriptionType?: string rateLimitTier?: string firstTokenTime?: number githubActionsMetadata?: GitHubActionsMetadata}
/** * Initialize user data asynchronously. Should be called early in startup. * This pre-fetches the email so getUser() can remain synchronous. */export async function initUser(): Promise<void> { if (cachedEmail === null && !emailFetchPromise) { emailFetchPromise = getEmailAsync() cachedEmail = await emailFetchPromise emailFetchPromise = null // Clear memoization cache so next call picks up the email getCoreUserData.cache.clear?.() }}
/** * Reset all user data caches. Call on auth changes (login/logout/account switch) * so the next getCoreUserData() call picks up fresh credentials and email. */export function resetUserCache(): void { cachedEmail = null emailFetchPromise = null getCoreUserData.cache.clear?.() getGitEmail.cache.clear?.()}
/** * Get core user data. * This is the base representation that gets transformed for different analytics providers. */export const getCoreUserData = memoize( (includeAnalyticsMetadata?: boolean): CoreUserData => { const deviceId = getOrCreateUserID() const config = getGlobalConfig()
let subscriptionType: string | undefined let rateLimitTier: string | undefined let firstTokenTime: number | undefined if (includeAnalyticsMetadata) { subscriptionType = getSubscriptionType() ?? undefined rateLimitTier = getRateLimitTier() ?? undefined if (subscriptionType && config.claudeCodeFirstTokenDate) { const configFirstTokenTime = new Date( config.claudeCodeFirstTokenDate, ).getTime() if (!isNaN(configFirstTokenTime)) { firstTokenTime = configFirstTokenTime } } }
// Only include OAuth account data when actively using OAuth authentication const oauthAccount = getOauthAccountInfo() const organizationUuid = oauthAccount?.organizationUuid const accountUuid = oauthAccount?.accountUuid
return { deviceId, sessionId: getSessionId(), email: getEmail(), appVersion: MACRO.VERSION, platform: getHostPlatformForAnalytics(), organizationUuid, accountUuid, userType: process.env.USER_TYPE, subscriptionType, rateLimitTier, firstTokenTime, ...(isEnvTruthy(process.env.GITHUB_ACTIONS) && { githubActionsMetadata: { actor: process.env.GITHUB_ACTOR, actorId: process.env.GITHUB_ACTOR_ID, repository: process.env.GITHUB_REPOSITORY, repositoryId: process.env.GITHUB_REPOSITORY_ID, repositoryOwner: process.env.GITHUB_REPOSITORY_OWNER, repositoryOwnerId: process.env.GITHUB_REPOSITORY_OWNER_ID, }, }), } },)
/** * Get user data for GrowthBook (same as core data with analytics metadata). */export function getUserForGrowthBook(): CoreUserData { return getCoreUserData(true)}
function getEmail(): string | undefined { // Return cached email if available (from async initialization) if (cachedEmail !== null) { return cachedEmail }
// Only include OAuth email when actively using OAuth authentication const oauthAccount = getOauthAccountInfo() if (oauthAccount?.emailAddress) { return oauthAccount.emailAddress }
// Ant-only fallbacks below (no execSync) if (process.env.USER_TYPE !== 'ant') { return undefined }
if (process.env.COO_CREATOR) { return `${process.env.COO_CREATOR}@anthropic.com` }
// If initUser() wasn't called, we return undefined instead of blocking return undefined}
async function getEmailAsync(): Promise<string | undefined> { // Only include OAuth email when actively using OAuth authentication const oauthAccount = getOauthAccountInfo() if (oauthAccount?.emailAddress) { return oauthAccount.emailAddress }
// Ant-only fallbacks below if (process.env.USER_TYPE !== 'ant') { return undefined }
if (process.env.COO_CREATOR) { return `${process.env.COO_CREATOR}@anthropic.com` }
return getGitEmail()}
/** * Get the user's git email from `git config user.email`. * Memoized so the subprocess only spawns once per process. */export const getGitEmail = memoize(async (): Promise<string | undefined> => { const result = await execa('git config --get user.email', { shell: true, reject: false, cwd: getCwd(), }) return result.exitCode === 0 && result.stdout ? result.stdout.trim() : undefined})