spb/khaelor Public
KHAELOR — a terminal-native autonomous engineering agent powered by Anthropic.
TypeScript 82.9%
HTML 14.9%
CSS 1.1%
JavaScript 0.7%
1/**2 * KHAELOR3 * File: tests/repository/recent.test.ts4 * Description: RecentFilesTracker tests — LRU bounds, frecency decay, repeated-access boosts.5 *6 * Author: Simon-Pierre Boucher7 * Contact: contact@spboucher.ai8 */910import { describe, expect, it } from "vitest";11import { RecentFilesTracker } from "../../src/repository/index.js";1213const T0 = 1_700_000_000_000;14const MINUTE = 60_000;15const HOUR = 60 * MINUTE;16const DAY = 24 * HOUR;1718function tracker(maxEntries = 256, maxTimestampsPerFile = 16): RecentFilesTracker {19 return new RecentFilesTracker({ maxEntries, maxTimestampsPerFile, now: () => T0 });20}2122describe("RecentFilesTracker LRU bound", () => {23 it("evicts the least recently accessed path at capacity", () => {24 const t = tracker(3);25 t.noteAccess("a", T0 - 4 * MINUTE);26 t.noteAccess("b", T0 - 3 * MINUTE);27 t.noteAccess("c", T0 - 2 * MINUTE);28 t.noteAccess("d", T0 - MINUTE);29 expect(t.size()).toBe(3);30 expect(t.has("a")).toBe(false);31 expect(t.has("d")).toBe(true);32 });3334 it("re-accessing a path refreshes its LRU position", () => {35 const t = tracker(3);36 t.noteAccess("a", T0 - 4 * MINUTE);37 t.noteAccess("b", T0 - 3 * MINUTE);38 t.noteAccess("c", T0 - 2 * MINUTE);39 t.noteAccess("a", T0 - MINUTE); // refresh a40 t.noteAccess("d", T0); // should evict b, not a41 expect(t.has("a")).toBe(true);42 expect(t.has("b")).toBe(false);43 });44});4546describe("RecentFilesTracker frecency", () => {47 it("scores recent accesses far higher than old ones", () => {48 const t = tracker();49 t.noteAccess("old.ts", T0 - 30 * DAY);50 t.noteAccess("recent.ts", T0 - 10 * MINUTE);51 expect(t.frecency("recent.ts")).toBeGreaterThan(t.frecency("old.ts"));52 expect(t.recent().map((r) => r.path)).toEqual(["recent.ts", "old.ts"]);53 });5455 it("accumulates over repeated accesses", () => {56 const t = tracker();57 t.noteAccess("hot.ts", T0 - 3 * MINUTE);58 t.noteAccess("hot.ts", T0 - 2 * MINUTE);59 t.noteAccess("hot.ts", T0 - MINUTE);60 t.noteAccess("cold.ts", T0 - MINUTE);61 expect(t.frecency("hot.ts")).toBe(3 * t.frecency("cold.ts"));62 const hot = t.recent()[0];63 expect(hot).toMatchObject({ path: "hot.ts", count: 3 });64 });6566 it("bounds the per-file timestamp window", () => {67 const t = tracker(256, 2);68 for (let i = 5; i >= 1; i -= 1) t.noteAccess("f.ts", T0 - i * MINUTE);69 expect(t.frecency("f.ts")).toBe(16); // only 2 retained accesses × weight 870 });7172 it("returns 0 for unknown paths", () => {73 expect(tracker().frecency("nope.ts")).toBe(0);74 });75});76