Adds DiffCache<T> module, extends BranchManager with getHeadCommitHash, and wires phase-level caching into getPhaseReviewDiff and getFileDiff. Cache is invalidated in ExecutionOrchestrator after each task merges into the phase branch, ensuring stale diffs are never served after new commits. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
68 lines
1.9 KiB
TypeScript
68 lines
1.9 KiB
TypeScript
/**
|
|
* DiffCache — in-memory cache with TTL and prefix-based invalidation.
|
|
* Used to avoid re-running expensive git diff subprocesses on repeated requests.
|
|
*/
|
|
|
|
import type { FileStatEntry } from '../git/types.js';
|
|
|
|
interface CacheEntry<T> {
|
|
value: T;
|
|
expiresAt: number;
|
|
}
|
|
|
|
export class DiffCache<T> {
|
|
private store = new Map<string, CacheEntry<T>>();
|
|
private ttlMs: number;
|
|
|
|
constructor(ttlMs: number) {
|
|
this.ttlMs = ttlMs;
|
|
}
|
|
|
|
get(key: string): T | undefined {
|
|
const entry = this.store.get(key);
|
|
if (!entry) return undefined;
|
|
if (Date.now() > entry.expiresAt) {
|
|
this.store.delete(key);
|
|
return undefined;
|
|
}
|
|
return entry.value;
|
|
}
|
|
|
|
set(key: string, value: T): void {
|
|
this.store.set(key, { value, expiresAt: Date.now() + this.ttlMs });
|
|
}
|
|
|
|
invalidateByPrefix(prefix: string): void {
|
|
for (const key of this.store.keys()) {
|
|
if (key.startsWith(prefix)) this.store.delete(key);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Response shapes (mirror the return types of getPhaseReviewDiff / getFileDiff)
|
|
// ---------------------------------------------------------------------------
|
|
|
|
export interface PhaseMetaResponse {
|
|
phaseName: string;
|
|
sourceBranch: string;
|
|
targetBranch: string;
|
|
files: FileStatEntry[];
|
|
totalAdditions: number;
|
|
totalDeletions: number;
|
|
}
|
|
|
|
export interface FileDiffResponse {
|
|
binary: boolean;
|
|
rawDiff: string;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Singleton instances — TTL is read once at module load time
|
|
// ---------------------------------------------------------------------------
|
|
|
|
const TTL = parseInt(process.env.REVIEW_DIFF_CACHE_TTL_MS ?? '300000', 10);
|
|
|
|
export const phaseMetaCache = new DiffCache<PhaseMetaResponse>(TTL);
|
|
export const fileDiffCache = new DiffCache<FileDiffResponse>(TTL);
|