/** * File Access Tracker * * Tracks file accesses during agent sessions to provide context restoration * hints after compaction. Inspired by Claude Code's post-compaction file * reference display. * * Features: * - Track read, referenced, and modified files * - Deduplication (read supersedes reference) * - Max entries with LRU eviction * - Verbosity-aware formatting * * @see /workspace/project-docs/00-requirements/compilr-dev-agents/context-restoration-hints.md */ import type { VerbosityLevel } from './types.js'; /** * Type of file access */ export type FileAccessType = 'read' | 'referenced' | 'modified'; /** * Record of a file access */ export interface FileAccess { /** Absolute file path */ path: string; /** Type of access */ type: FileAccessType; /** When accessed (timestamp) */ timestamp: number; /** Number of lines (for 'read' type) */ lineCount?: number; /** Optional summary of what was found/changed */ summary?: string; /** Stored file content (only for small reads, used for post-compaction restoration) */ content?: string; /** Token count of stored content */ tokenCount?: number; } /** * Options for FileAccessTracker constructor */ export interface FileAccessTrackerOptions { /** * Maximum number of entries to track * @default 100 */ maxEntries?: number; /** * Deduplicate references (don't track same file twice as 'referenced') * @default true */ deduplicateReferences?: boolean; /** * Maximum line count for a file to have its content stored inline. * Files with more lines than this threshold will only store path/lineCount. * @default 200 */ inlineThreshold?: number; /** * Maximum number of files that can have stored content at once. * When exceeded, oldest content entries are evicted (path still tracked). * @default 10 */ maxContentEntries?: number; } /** * Options for formatting restoration hints */ export interface FormatHintsOptions { /** Include line counts for read files @default true */ includeLineCount?: boolean; /** Include summaries @default false */ includeSummary?: boolean; /** Include timestamps @default false */ includeTimestamp?: boolean; /** Group by access type @default true */ groupByType?: boolean; /** Maximum files to include @default 20 */ maxFiles?: number; /** Verbosity level (adjusts format automatically) */ verbosityLevel?: VerbosityLevel; } /** * A single restoration hint message for post-compaction context injection */ export interface RestorationHintMessage { /** File path */ path: string; /** Whether content is inlined or just referenced */ type: 'inline' | 'reference'; /** The formatted hint text */ text: string; /** Estimated token count of this hint */ tokens: number; } /** * Statistics about file accesses */ export interface FileAccessStats { read: number; referenced: number; modified: number; total: number; } /** * Tracks file accesses during agent sessions for context restoration hints. * * @example * ```typescript * const tracker = new FileAccessTracker(); * * // Track file accesses * tracker.trackRead('/path/to/file.ts', 597); * tracker.trackReference('/path/to/other.ts'); * tracker.trackModification('/path/to/file.ts', 'Added function'); * * // Get restoration hints after compaction * const hints = tracker.formatRestorationHints(); * console.log(hints); * ``` */ export declare class FileAccessTracker { private readonly accesses; private readonly maxEntries; private readonly deduplicateReferences; private readonly inlineThreshold; private readonly maxContentEntries; constructor(options?: FileAccessTrackerOptions); /** * Track a file that was fully read */ trackRead(filePath: string, lineCount: number, summary?: string, content?: string): void; /** * Track a file that was referenced (e.g., appeared in grep/glob results) */ trackReference(filePath: string): void; /** * Track a file that was modified (written or edited) */ trackModification(filePath: string, summary?: string): void; /** * Get all file accesses, optionally filtered */ getAccesses(options?: { type?: FileAccessType; since?: number; }): FileAccess[]; /** * Get most recent file accesses */ getRecentAccesses(limit?: number): FileAccess[]; /** * Check if a file has been accessed */ hasAccessed(filePath: string): boolean; /** * Get access record for a specific file */ getAccess(filePath: string): FileAccess | undefined; /** * Get statistics about file accesses */ getStats(): FileAccessStats; /** * Format restoration hints for injection after compaction */ formatRestorationHints(options?: FormatHintsOptions): string; /** * Format restoration hints with inline file content (Claude Code style). * * Small files with stored content are inlined up to a token budget. * Large files or files exceeding the budget get reference-only hints. * Each file produces a separate hint message for individual injection. * * Priority order for inlining: * 1. Modified files (most critical context) * 2. Read files, most recent first * 3. Once budget exhausted → remaining become reference-only * 4. Referenced-only files → always reference-only */ formatRestorationHintsWithContent(options?: { /** Total token budget for all inline content (default: 4000) */ maxInlineTokens?: number; }): RestorationHintMessage[]; /** * Clear all tracked accesses */ clear(): void; /** * Get the number of tracked files */ get size(): number; /** * Rough token estimate (4 chars ≈ 1 token). Avoids heavy tiktoken dependency * in the tracker — exact counts aren't critical for budget enforcement. */ private estimateTokens; /** * Evict oldest stored content when maxContentEntries is exceeded. * Only drops the `content`/`tokenCount` fields — the access entry itself is preserved. */ private enforceMaxContentEntries; private normalizePath; private enforceMaxEntries; private getEffectiveMaxFiles; private formatCompact; private formatGrouped; private formatFlat; private formatAccessLine; private groupByType; private getDisplayName; private getDisplayPath; }