Something went wrong. Try again.
source dump of claude code forked from oppi.li/claude-code
Something went wrong. Try again.
claude-code context.ts
6.4 kB · 189 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190import { feature } from 'bun:bundle'import memoize from 'lodash-es/memoize.js'import { getAdditionalDirectoriesForClaudeMd, setCachedClaudeMdContent,} from './bootstrap/state.js'import { getLocalISODate } from './constants/common.js'import { filterInjectedMemoryFiles, getClaudeMds, getMemoryFiles,} from './utils/claudemd.js'import { logForDiagnosticsNoPII } from './utils/diagLogs.js'import { isBareMode, isEnvTruthy } from './utils/envUtils.js'import { execFileNoThrow } from './utils/execFileNoThrow.js'import { getBranch, getDefaultBranch, getIsGit, gitExe } from './utils/git.js'import { shouldIncludeGitInstructions } from './utils/gitSettings.js'import { logError } from './utils/log.js'
const MAX_STATUS_CHARS = 2000
// System prompt injection for cache breaking (ant-only, ephemeral debugging state)let systemPromptInjection: string | null = null
export function getSystemPromptInjection(): string | null { return systemPromptInjection}
export function setSystemPromptInjection(value: string | null): void { systemPromptInjection = value // Clear context caches immediately when injection changes getUserContext.cache.clear?.() getSystemContext.cache.clear?.()}
export const getGitStatus = memoize(async (): Promise<string | null> => { if (process.env.NODE_ENV === 'test') { // Avoid cycles in tests return null }
const startTime = Date.now() logForDiagnosticsNoPII('info', 'git_status_started')
const isGitStart = Date.now() const isGit = await getIsGit() logForDiagnosticsNoPII('info', 'git_is_git_check_completed', { duration_ms: Date.now() - isGitStart, is_git: isGit, })
if (!isGit) { logForDiagnosticsNoPII('info', 'git_status_skipped_not_git', { duration_ms: Date.now() - startTime, }) return null }
try { const gitCmdsStart = Date.now() const [branch, mainBranch, status, log, userName] = await Promise.all([ getBranch(), getDefaultBranch(), execFileNoThrow(gitExe(), ['--no-optional-locks', 'status', '--short'], { preserveOutputOnError: false, }).then(({ stdout }) => stdout.trim()), execFileNoThrow( gitExe(), ['--no-optional-locks', 'log', '--oneline', '-n', '5'], { preserveOutputOnError: false, }, ).then(({ stdout }) => stdout.trim()), execFileNoThrow(gitExe(), ['config', 'user.name'], { preserveOutputOnError: false, }).then(({ stdout }) => stdout.trim()), ])
logForDiagnosticsNoPII('info', 'git_commands_completed', { duration_ms: Date.now() - gitCmdsStart, status_length: status.length, })
// Check if status exceeds character limit const truncatedStatus = status.length > MAX_STATUS_CHARS ? status.substring(0, MAX_STATUS_CHARS) + '\n... (truncated because it exceeds 2k characters. If you need more information, run "git status" using BashTool)' : status
logForDiagnosticsNoPII('info', 'git_status_completed', { duration_ms: Date.now() - startTime, truncated: status.length > MAX_STATUS_CHARS, })
return [ `This is the git status at the start of the conversation. Note that this status is a snapshot in time, and will not update during the conversation.`, `Current branch: ${branch}`, `Main branch (you will usually use this for PRs): ${mainBranch}`, ...(userName ? [`Git user: ${userName}`] : []), `Status:\n${truncatedStatus || '(clean)'}`, `Recent commits:\n${log}`, ].join('\n\n') } catch (error) { logForDiagnosticsNoPII('error', 'git_status_failed', { duration_ms: Date.now() - startTime, }) logError(error) return null }})
/** * This context is prepended to each conversation, and cached for the duration of the conversation. */export const getSystemContext = memoize( async (): Promise<{ [k: string]: string }> => { const startTime = Date.now() logForDiagnosticsNoPII('info', 'system_context_started')
// Skip git status in CCR (unnecessary overhead on resume) or when git instructions are disabled const gitStatus = isEnvTruthy(process.env.CLAUDE_CODE_REMOTE) || !shouldIncludeGitInstructions() ? null : await getGitStatus()
// Include system prompt injection if set (for cache breaking, ant-only) const injection = feature('BREAK_CACHE_COMMAND') ? getSystemPromptInjection() : null
logForDiagnosticsNoPII('info', 'system_context_completed', { duration_ms: Date.now() - startTime, has_git_status: gitStatus !== null, has_injection: injection !== null, })
return { ...(gitStatus && { gitStatus }), ...(feature('BREAK_CACHE_COMMAND') && injection ? { cacheBreaker: `[CACHE_BREAKER: ${injection}]`, } : {}), } },)
/** * This context is prepended to each conversation, and cached for the duration of the conversation. */export const getUserContext = memoize( async (): Promise<{ [k: string]: string }> => { const startTime = Date.now() logForDiagnosticsNoPII('info', 'user_context_started')
// CLAUDE_CODE_DISABLE_CLAUDE_MDS: hard off, always. // --bare: skip auto-discovery (cwd walk), BUT honor explicit --add-dir. // --bare means "skip what I didn't ask for", not "ignore what I asked for". const shouldDisableClaudeMd = isEnvTruthy(process.env.CLAUDE_CODE_DISABLE_CLAUDE_MDS) || (isBareMode() && getAdditionalDirectoriesForClaudeMd().length === 0) // Await the async I/O (readFile/readdir directory walk) so the event // loop yields naturally at the first fs.readFile. const claudeMd = shouldDisableClaudeMd ? null : getClaudeMds(filterInjectedMemoryFiles(await getMemoryFiles())) // Cache for the auto-mode classifier (yoloClassifier.ts reads this // instead of importing claudemd.ts directly, which would create a // cycle through permissions/filesystem → permissions → yoloClassifier). setCachedClaudeMdContent(claudeMd || null)
logForDiagnosticsNoPII('info', 'user_context_completed', { duration_ms: Date.now() - startTime, claudemd_length: claudeMd?.length ?? 0, claudemd_disabled: Boolean(shouldDisableClaudeMd), })
return { ...(claudeMd && { claudeMd }), currentDate: `Today's date is ${getLocalISODate()}.`, } },)