Something went wrong. Try again.
source dump of claude code forked from oppi.li/claude-code
Something went wrong. Try again.
5.1 kB · 166 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167import { mkdir, readdir, readFile, writeFile } from 'fs/promises'import { join } from 'path'import { getSessionId } from '../bootstrap/state.js'import { logForDebugging } from './debug.js'import { getClaudeConfigHomeDir } from './envUtils.js'import { errorMessage, getErrnoCode } from './errors.js'import { getPlatform } from './platform.js'
// Cache states:// undefined = not yet loaded (need to check disk)// null = checked disk, no files exist (don't check again)// string = loaded and cached (use cached value)let sessionEnvScript: string | null | undefined = undefined
export async function getSessionEnvDirPath(): Promise<string> { const sessionEnvDir = join( getClaudeConfigHomeDir(), 'session-env', getSessionId(), ) await mkdir(sessionEnvDir, { recursive: true }) return sessionEnvDir}
export async function getHookEnvFilePath( hookEvent: 'Setup' | 'SessionStart' | 'CwdChanged' | 'FileChanged', hookIndex: number,): Promise<string> { const prefix = hookEvent.toLowerCase() return join(await getSessionEnvDirPath(), `${prefix}-hook-${hookIndex}.sh`)}
export async function clearCwdEnvFiles(): Promise<void> { try { const dir = await getSessionEnvDirPath() const files = await readdir(dir) await Promise.all( files .filter( f => (f.startsWith('filechanged-hook-') || f.startsWith('cwdchanged-hook-')) && HOOK_ENV_REGEX.test(f), ) .map(f => writeFile(join(dir, f), '')), ) } catch (e: unknown) { const code = getErrnoCode(e) if (code !== 'ENOENT') { logForDebugging(`Failed to clear cwd env files: ${errorMessage(e)}`) } }}
export function invalidateSessionEnvCache(): void { logForDebugging('Invalidating session environment cache') sessionEnvScript = undefined}
export async function getSessionEnvironmentScript(): Promise<string | null> { if (getPlatform() === 'windows') { logForDebugging('Session environment not yet supported on Windows') return null }
if (sessionEnvScript !== undefined) { return sessionEnvScript }
const scripts: string[] = []
// Check for CLAUDE_ENV_FILE passed from parent process (e.g., HFI trajectory runner) // This allows venv/conda activation to persist across shell commands const envFile = process.env.CLAUDE_ENV_FILE if (envFile) { try { const envScript = (await readFile(envFile, 'utf8')).trim() if (envScript) { scripts.push(envScript) logForDebugging( `Session environment loaded from CLAUDE_ENV_FILE: ${envFile} (${envScript.length} chars)`, ) } } catch (e: unknown) { const code = getErrnoCode(e) if (code !== 'ENOENT') { logForDebugging(`Failed to read CLAUDE_ENV_FILE: ${errorMessage(e)}`) } } }
// Load hook environment files from session directory const sessionEnvDir = await getSessionEnvDirPath() try { const files = await readdir(sessionEnvDir) // We are sorting the hook env files by the order in which they are listed // in the settings.json file so that the resulting env is deterministic const hookFiles = files .filter(f => HOOK_ENV_REGEX.test(f)) .sort(sortHookEnvFiles)
for (const file of hookFiles) { const filePath = join(sessionEnvDir, file) try { const content = (await readFile(filePath, 'utf8')).trim() if (content) { scripts.push(content) } } catch (e: unknown) { const code = getErrnoCode(e) if (code !== 'ENOENT') { logForDebugging( `Failed to read hook file ${filePath}: ${errorMessage(e)}`, ) } } }
if (hookFiles.length > 0) { logForDebugging( `Session environment loaded from ${hookFiles.length} hook file(s)`, ) } } catch (e: unknown) { const code = getErrnoCode(e) if (code !== 'ENOENT') { logForDebugging( `Failed to load session environment from hooks: ${errorMessage(e)}`, ) } }
if (scripts.length === 0) { logForDebugging('No session environment scripts found') sessionEnvScript = null return sessionEnvScript }
sessionEnvScript = scripts.join('\n') logForDebugging( `Session environment script ready (${sessionEnvScript.length} chars total)`, ) return sessionEnvScript}
const HOOK_ENV_PRIORITY: Record<string, number> = { setup: 0, sessionstart: 1, cwdchanged: 2, filechanged: 3,}const HOOK_ENV_REGEX = /^(setup|sessionstart|cwdchanged|filechanged)-hook-(\d+)\.sh$/
function sortHookEnvFiles(a: string, b: string): number { const aMatch = a.match(HOOK_ENV_REGEX) const bMatch = b.match(HOOK_ENV_REGEX) const aType = aMatch?.[1] || '' const bType = bMatch?.[1] || '' if (aType !== bType) { return (HOOK_ENV_PRIORITY[aType] ?? 99) - (HOOK_ENV_PRIORITY[bType] ?? 99) } const aIndex = parseInt(aMatch?.[2] || '0', 10) const bIndex = parseInt(bMatch?.[2] || '0', 10) return aIndex - bIndex}