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/search.test.ts4 * Description: FileSearch tests — fuzzy ranking tiers (exact > prefix > subsequence) and frecency boosts.5 *6 * Author: Simon-Pierre Boucher7 * Contact: contact@spboucher.ai8 */910import { rmSync } from "node:fs";11import { afterEach, beforeEach, describe, expect, it } from "vitest";12import {13 FileSearch,14 RecentFilesTracker,15 RepositoryMap,16 subsequenceQuality,17} from "../../src/repository/index.js";18import { LocalWorkspace } from "../../src/workspace/index.js";19import { makeTempDir, writeFixtureFile } from "./fixtures.js";2021let dir: string;22let map: RepositoryMap;23let recent: RecentFilesTracker;24let search: FileSearch;2526beforeEach(() => {27 dir = makeTempDir("khaelor-search-");28 for (const rel of [29 "abc.ts",30 "abcdef.ts",31 "axbxcx.ts",32 "src/alpha/agent.ts",33 "src/betaa/agent.ts",34 "notes.md",35 ]) {36 writeFixtureFile(dir, rel, "content\n");37 }38 map = new RepositoryMap(new LocalWorkspace(dir));39 recent = new RecentFilesTracker();40 search = new FileSearch(map, recent);41});4243afterEach(() => {44 rmSync(dir, { recursive: true, force: true });45});4647describe("FileSearch ranking tiers", () => {48 it("ranks exact matches above prefix matches above subsequence matches", async () => {49 const exact = await search.findFiles("abc.ts");50 expect(exact[0]?.path).toBe("abc.ts");5152 const prefix = await search.findFiles("abc");53 expect(prefix.map((r) => r.path)).toEqual(["abc.ts", "abcdef.ts", "axbxcx.ts"]);54 expect(prefix[0]?.score).toBeGreaterThan(prefix[2]?.score ?? 0);55 });5657 it("excludes files that are not even a subsequence match", async () => {58 expect(await search.findFiles("zzz")).toEqual([]);59 expect(subsequenceQuality("notes.md", "zzz")).toBeUndefined();60 expect(subsequenceQuality("axbxcx.ts", "abc")).toBeGreaterThan(0);61 });6263 it("respects the result limit", async () => {64 const results = await search.findFiles("a", 2);65 expect(results).toHaveLength(2);66 });67});6869describe("FileSearch frecency boost", () => {70 it("breaks ties deterministically without access history", async () => {71 const results = await search.findFiles("agent");72 expect(results.map((r) => r.path)).toEqual(["src/alpha/agent.ts", "src/betaa/agent.ts"]);73 });7475 it("boosts recently accessed files within the same match tier", async () => {76 recent.noteAccess("src/betaa/agent.ts");77 const results = await search.findFiles("agent");78 expect(results.map((r) => r.path)).toEqual(["src/betaa/agent.ts", "src/alpha/agent.ts"]);79 });8081 it("never lets frecency promote a weaker match class above a stronger one", async () => {82 // axbxcx.ts is only a subsequence match for "abc" — heavy access must not83 // rank it above the prefix matches.84 for (let i = 0; i < 10; i += 1) recent.noteAccess("axbxcx.ts");85 const results = await search.findFiles("abc");86 expect(results.map((r) => r.path)).toEqual(["abc.ts", "abcdef.ts", "axbxcx.ts"]);87 });88});8990describe("FileSearch empty query", () => {91 it("returns recently accessed files first, then alphabetical fill", async () => {92 recent.noteAccess("notes.md");93 const results = await search.findFiles("", 4);94 expect(results[0]?.path).toBe("notes.md");95 expect(results).toHaveLength(4);96 const rest = results.slice(1).map((r) => r.path);97 expect(rest).toEqual([...rest].sort((a, b) => a.localeCompare(b)));98 });99});100