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 · 82 lines typescript
Raw Blame History
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