Resolves add/add conflict in diff-cache.ts (kept typed PhaseMetaResponse/ FileDiffResponse interfaces from HEAD over unknown-typed singletons from test branch) and content conflict in phase.ts (kept both phaseMetaCache and fileDiffCache imports; removed auto-merged duplicate firstClone/headHash/ cacheKey/cached declarations and unreachable empty-projects guard). Also cleans auto-merged duplicate getHeadCommitHash in orchestrator.test.ts and simple-git-branch-manager.ts. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
71 lines
2.0 KiB
TypeScript
71 lines
2.0 KiB
TypeScript
/**
|
|
* DiffCache — in-memory TTL cache for git diff results.
|
|
*
|
|
* Keyed by `phaseId:headHash` (or `phaseId:headHash:filePath` for per-file diffs).
|
|
* TTL defaults to 5 minutes, configurable via REVIEW_DIFF_CACHE_TTL_MS env var.
|
|
* Prefix-based invalidation clears all entries for a phase when a new commit lands.
|
|
*/
|
|
|
|
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);
|