(Alleged) Leaked source of Claude Code
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 119 lines 3.5 kB view raw
1import { getHistory } from '../../history.js' 2import { logForDebugging } from '../debug.js' 3 4/** 5 * Result of shell history completion lookup 6 */ 7export type ShellHistoryMatch = { 8 /** The full command from history */ 9 fullCommand: string 10 /** The suffix to display as ghost text (the part after user's input) */ 11 suffix: string 12} 13 14// Cache for shell history commands to avoid repeated async reads 15// History only changes when user submits a command, so a long TTL is fine 16let shellHistoryCache: string[] | null = null 17let shellHistoryCacheTimestamp = 0 18const CACHE_TTL_MS = 60000 // 60 seconds - history won't change while typing 19 20/** 21 * Get shell commands from history, with caching 22 */ 23async function getShellHistoryCommands(): Promise<string[]> { 24 const now = Date.now() 25 26 // Return cached result if still fresh 27 if (shellHistoryCache && now - shellHistoryCacheTimestamp < CACHE_TTL_MS) { 28 return shellHistoryCache 29 } 30 31 const commands: string[] = [] 32 const seen = new Set<string>() 33 34 try { 35 // Read history entries and filter for bash commands 36 for await (const entry of getHistory()) { 37 if (entry.display && entry.display.startsWith('!')) { 38 // Remove the '!' prefix to get the actual command 39 const command = entry.display.slice(1).trim() 40 if (command && !seen.has(command)) { 41 seen.add(command) 42 commands.push(command) 43 } 44 } 45 // Limit to 50 most recent unique commands 46 if (commands.length >= 50) { 47 break 48 } 49 } 50 } catch (error) { 51 logForDebugging(`Failed to read shell history: ${error}`) 52 } 53 54 shellHistoryCache = commands 55 shellHistoryCacheTimestamp = now 56 return commands 57} 58 59/** 60 * Clear the shell history cache (useful when history is updated) 61 */ 62export function clearShellHistoryCache(): void { 63 shellHistoryCache = null 64 shellHistoryCacheTimestamp = 0 65} 66 67/** 68 * Add a command to the front of the shell history cache without 69 * flushing the entire cache. If the command already exists in the 70 * cache it is moved to the front (deduped). When the cache hasn't 71 * been populated yet this is a no-op – the next lookup will read 72 * the full history which already includes the new command. 73 */ 74export function prependToShellHistoryCache(command: string): void { 75 if (!shellHistoryCache) { 76 return 77 } 78 const idx = shellHistoryCache.indexOf(command) 79 if (idx !== -1) { 80 shellHistoryCache.splice(idx, 1) 81 } 82 shellHistoryCache.unshift(command) 83} 84 85/** 86 * Find the best matching shell command from history for the given input 87 * 88 * @param input The current user input (without '!' prefix) 89 * @returns The best match, or null if no match found 90 */ 91export async function getShellHistoryCompletion( 92 input: string, 93): Promise<ShellHistoryMatch | null> { 94 // Don't suggest for empty or very short input 95 if (!input || input.length < 2) { 96 return null 97 } 98 99 // Check the trimmed input to make sure there's actual content 100 const trimmedInput = input.trim() 101 if (!trimmedInput) { 102 return null 103 } 104 105 const commands = await getShellHistoryCommands() 106 107 // Find the first command that starts with the EXACT input (including spaces) 108 // This ensures "ls " matches "ls -lah" but "ls " (2 spaces) does not 109 for (const command of commands) { 110 if (command.startsWith(input) && command !== input) { 111 return { 112 fullCommand: command, 113 suffix: command.slice(input.length), 114 } 115 } 116 } 117 118 return null 119}