SPB Git

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%
2.5 KB · 76 lines typescript
Raw Blame History
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