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/tools/helpers.ts4 * Description: Shared test fixtures — real LocalWorkspace-backed ToolContext in a temp directory.5 *6 * Author: Simon-Pierre Boucher7 * Contact: contact@spboucher.ai8 */910import { mkdirSync, mkdtempSync, writeFileSync } from "node:fs";11import { tmpdir } from "node:os";12import * as path from "node:path";13import type { ToolContext, ToolEmittedEvent } from "../../src/tools/index.js";14import {15 InMemoryFileTimeRegistry,16 LocalProcessManager,17 LocalWorkspace,18} from "../../src/workspace/index.js";1920export interface TestHarness {21 dir: string;22 workspace: LocalWorkspace;23 fileTimes: InMemoryFileTimeRegistry;24 processes: LocalProcessManager;25 events: ToolEmittedEvent[];26 spills: string[];27 ctx: ToolContext;28 abort: AbortController;29}3031let spillCounter = 0;3233/** Build a real ToolContext rooted in a fresh temp directory. */34export function makeHarness(): TestHarness {35 const dir = mkdtempSync(path.join(tmpdir(), "khaelor-tools-"));36 const workspace = new LocalWorkspace(dir);37 const fileTimes = new InMemoryFileTimeRegistry();38 const logDir = path.join(dir, ".khaelor-test-logs");39 const processes = new LocalProcessManager({ logDir, shell: "/bin/sh" });40 const events: ToolEmittedEvent[] = [];41 const spills: string[] = [];42 const abort = new AbortController();43 const spillDir = path.join(dir, ".khaelor-test-spill");44 mkdirSync(spillDir, { recursive: true });4546 const ctx: ToolContext = {47 sessionId: "s_test",48 callId: "toolu_test",49 workspace,50 signal: abort.signal,51 fileTimes,52 processes,53 emit: (event) => {54 events.push(event);55 },56 progress: () => undefined,57 spill: (label, content) => {58 spillCounter += 1;59 const file = path.join(spillDir, `${label}-${spillCounter}.txt`);60 writeFileSync(file, content, "utf8");61 spills.push(file);62 return Promise.resolve(file);63 },64 };6566 return { dir, workspace, fileTimes, processes, events, spills, ctx, abort };67}6869/** Write a fixture file under the harness dir; returns the absolute path. */70export function fixture(harness: TestHarness, rel: string, content: string): string {71 const abs = path.join(harness.dir, rel);72 mkdirSync(path.dirname(abs), { recursive: true });73 writeFileSync(abs, content, "utf8");74 return abs;75}7677/** Read a file through the harness and stamp it (simulates a prior read tool call). */78export async function markRead(harness: TestHarness, abs: string): Promise<void> {79 const content = await harness.workspace.readFile(abs);80 harness.fileTimes.stamp(abs, content);81}82