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: src/workspace/workspace.ts4 * Description: Workspace interface — the single world seam for files and process execution (ADR-13).5 *6 * Author: Simon-Pierre Boucher7 * Contact: contact@spboucher.ai8 */910/**11 * The world seam (ARCHITECTURE.md §workspace, ADR-13). Exactly four methods.12 * Tools act on the world only through this interface; `src/workspace/` is the13 * sole module allowed to import `node:fs` / `node:child_process`.14 */15export interface Workspace {16 cwd(): string;17 readFile(path: string): Promise<string>;18 /** Atomic: temp file + rename, preserving mode bits. */19 writeFile(path: string, content: string): Promise<void>;20 exec(command: Command): Promise<ProcessResult>;21}2223/** A foreground command for `Workspace.exec` (used by the `bash` tool). */24export interface Command {25 /** Run via the user shell for the `bash` tool. */26 cmd: string;27 cwd?: string;28 /** Hard ceiling; ADR-8: long commands redirect to `process`. */29 timeoutMs: number;30 env?: Record<string, string>;31 signal?: AbortSignal;32}3334/** Result of a foreground command. */35export interface ProcessResult {36 /** null = killed by timeout/signal. */37 exitCode: number | null;38 stdout: string;39 stderr: string;40 durationMs: number;41 truncated: boolean;42}4344/** Stable machine-readable error codes for workspace failures. */45export type WorkspaceErrorCode =46 | "file-not-found"47 | "file-is-directory"48 | "file-too-large"49 | "file-binary"50 | "write-failed"51 | "exec-failed"52 | "process-unknown"53 | "process-not-running";5455/**56 * Typed workspace failure. Kept module-local (the shared `KhaelorErrorCode`57 * union stays closed); messages must never contain secrets.58 */59export class WorkspaceError extends Error {60 readonly code: WorkspaceErrorCode;61 readonly details: Readonly<Record<string, unknown>>;6263 constructor(code: WorkspaceErrorCode, message: string, details: Record<string, unknown> = {}) {64 super(message);65 this.name = "WorkspaceError";66 this.code = code;67 this.details = details;68 }69}7071/** Narrowing helper. */72export function isWorkspaceError(value: unknown): value is WorkspaceError {73 return value instanceof WorkspaceError;74}75