MCPcopy
hub / github.com/claude-code-best/claude-code / fileHistoryMakeSnapshot

Function fileHistoryMakeSnapshot

src/utils/fileHistory.ts:200–344  ·  view source on GitHub ↗
(
  updateFileHistoryState: (
    updater: (prev: FileHistoryState) => FileHistoryState,
  ) => void,
  messageId: UUID,
)

Source from the content-addressed store, hash-verified

198 * Adds a snapshot in the file history and backs up any modified tracked files.
199 */
200export async function fileHistoryMakeSnapshot(
201 updateFileHistoryState: (
202 updater: (prev: FileHistoryState) => FileHistoryState,
203 ) => void,
204 messageId: UUID,
205): Promise<void> {
206 if (!fileHistoryEnabled()) {
207 return undefined
208 }
209
210 // Phase 1: capture current state with a no-op updater so we know which
211 // files to back up. Returning the same reference keeps this a true no-op
212 // for any wrapper that honors same-ref returns (src/CLAUDE.md wrapper
213 // rule). Wrappers that unconditionally spread will trigger one extra
214 // re-render; acceptable for a once-per-turn call.
215 let captured: FileHistoryState | undefined
216 updateFileHistoryState(state => {
217 captured = state
218 return state
219 })
220 if (!captured) return // updateFileHistoryState was a no-op stub (e.g. mcp.ts)
221
222 // Phase 2: do all IO async, outside the updater.
223 const trackedFileBackups: Record<string, FileHistoryBackup> = {}
224 const mostRecentSnapshot = captured.snapshots.at(-1)
225 if (mostRecentSnapshot) {
226 logForDebugging(`FileHistory: Making snapshot for message ${messageId}`)
227 await Promise.all(
228 Array.from(captured.trackedFiles, async trackingPath => {
229 try {
230 const filePath = maybeExpandFilePath(trackingPath)
231 const latestBackup =
232 mostRecentSnapshot.trackedFileBackups[trackingPath]
233 const nextVersion = latestBackup ? latestBackup.version + 1 : 1
234
235 // Stat the file once; ENOENT means the tracked file was deleted.
236 let fileStats: Stats | undefined
237 try {
238 fileStats = await stat(filePath)
239 } catch (e: unknown) {
240 if (!isENOENT(e)) throw e
241 }
242
243 if (!fileStats) {
244 trackedFileBackups[trackingPath] = {
245 backupFileName: null, // Use null to denote missing tracked file
246 version: nextVersion,
247 backupTime: new Date(),
248 }
249 logEvent('tengu_file_history_backup_deleted_file', {
250 version: nextVersion,
251 })
252 logForDebugging(
253 `FileHistory: Missing tracked file: ${trackingPath}`,
254 )
255 return
256 }
257

Callers 3

submitMessageMethod · 0.85
executeUserInputFunction · 0.85
processInitialMessageFunction · 0.85

Calls 13

fileHistoryEnabledFunction · 0.85
updateFileHistoryStateFunction · 0.85
maybeExpandFilePathFunction · 0.85
statFunction · 0.85
isENOENTFunction · 0.85
logEventFunction · 0.85
checkOriginFileChangedFunction · 0.85
createBackupFunction · 0.85
maybeDumpStateForDebugFunction · 0.85
logForDebuggingFunction · 0.70

Tested by

no test coverage detected