Download src/utils/filePersistence/outputsScanner.ts from chenbhao/codev: direct link, hf CLI and curl.
- Browser
- Download file 3.68 kB
-
https://huggingface.co/chenbhao/codev/resolve/afbc7edaae4e6bb0102ba024b49ce8be89d2264c/src/utils/filePersistence/outputsScanner.ts
- Command line
-
hf download hf://chenbhao/codev@afbc7edaae4e6bb0102ba024b49ce8be89d2264c/src/utils/filePersistence/outputsScanner.ts
-
curl -L -o outputsScanner.ts https://huggingface.co/chenbhao/codev/resolve/afbc7edaae4e6bb0102ba024b49ce8be89d2264c/src/utils/filePersistence/outputsScanner.ts
3.68 kB
| /** | |
| * Outputs directory scanner for file persistence | |
| * | |
| * This module provides utilities to: | |
| * - Detect the session type from environment variables | |
| * - Capture turn start timestamp | |
| * - Find modified files by comparing file mtimes against turn start time | |
| */ | |
| import * as fs from 'fs/promises' | |
| import * as path from 'path' | |
| import { logForDebugging } from '../debug.js' | |
| import type { EnvironmentKind } from '../teleport/environments.js' | |
| import type { TurnStartTime } from './types.js' | |
| /** Shared debug logger for file persistence modules */ | |
| export function logDebug(message: string): void { | |
| logForDebugging(`[file-persistence] ${message}`) | |
| } | |
| /** | |
| * Get the environment kind from CLAUDE_CODE_ENVIRONMENT_KIND. | |
| * Returns null if not set or not a recognized value. | |
| */ | |
| export function getEnvironmentKind(): EnvironmentKind | null { | |
| const kind = process.env.CLAUDE_CODE_ENVIRONMENT_KIND | |
| if (kind === 'byoc' || kind === 'anthropic_cloud') { | |
| return kind | |
| } | |
| return null | |
| } | |
| function hasParentPath( | |
| entry: object, | |
| ): entry is { parentPath: string; name: string } { | |
| return 'parentPath' in entry && typeof entry.parentPath === 'string' | |
| } | |
| function hasPath(entry: object): entry is { path: string; name: string } { | |
| return 'path' in entry && typeof entry.path === 'string' | |
| } | |
| function getEntryParentPath(entry: object, fallback: string): string { | |
| if (hasParentPath(entry)) { | |
| return entry.parentPath | |
| } | |
| if (hasPath(entry)) { | |
| return entry.path | |
| } | |
| return fallback | |
| } | |
| /** | |
| * Find files that have been modified since the turn started. | |
| * Returns paths of files with mtime >= turnStartTime. | |
| * | |
| * Uses recursive directory listing and parallelized stat calls for efficiency. | |
| * | |
| * @param turnStartTime - The timestamp when the turn started | |
| * @param outputsDir - The directory to scan for modified files | |
| */ | |
| export async function findModifiedFiles( | |
| turnStartTime: TurnStartTime, | |
| outputsDir: string, | |
| ): Promise<string[]> { | |
| // Use recursive flag to get all entries in one call | |
| let entries: Awaited<ReturnType<typeof fs.readdir>> | |
| try { | |
| entries = await fs.readdir(outputsDir, { | |
| withFileTypes: true, | |
| recursive: true, | |
| }) | |
| } catch { | |
| // Directory doesn't exist or is not accessible | |
| return [] | |
| } | |
| // Filter to regular files only (skip symlinks for security) and build full paths | |
| const filePaths: string[] = [] | |
| for (const entry of entries) { | |
| if (entry.isSymbolicLink()) { | |
| continue | |
| } | |
| if (entry.isFile()) { | |
| // entry.parentPath is available in Node 20+, fallback to entry.path for older versions | |
| const parentPath = getEntryParentPath(entry, outputsDir) | |
| filePaths.push(path.join(parentPath, entry.name)) | |
| } | |
| } | |
| if (filePaths.length === 0) { | |
| logDebug('No files found in outputs directory') | |
| return [] | |
| } | |
| // Parallelize stat calls for all files | |
| const statResults = await Promise.all( | |
| filePaths.map(async filePath => { | |
| try { | |
| const stat = await fs.lstat(filePath) | |
| // Skip if it became a symlink between readdir and stat (race condition) | |
| if (stat.isSymbolicLink()) { | |
| return null | |
| } | |
| return { filePath, mtimeMs: stat.mtimeMs } | |
| } catch { | |
| // File may have been deleted between readdir and stat | |
| return null | |
| } | |
| }), | |
| ) | |
| // Filter to files modified since turn start | |
| const modifiedFiles: string[] = [] | |
| for (const result of statResults) { | |
| if (result && result.mtimeMs >= turnStartTime) { | |
| modifiedFiles.push(result.filePath) | |
| } | |
| } | |
| logDebug( | |
| `Found ${modifiedFiles.length} modified files since turn start (scanned ${filePaths.length} total)`, | |
| ) | |
| return modifiedFiles | |
| } | |