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/cli/subtasks.ts4 * Description: Subtask wiring — SubtaskManager factory whose child runner assembles a full headless engine per worktree (v2 design §6).5 *6 * Author: Simon-Pierre Boucher7 * Contact: contact@spboucher.ai8 */910import type { ResolvedConfig } from "../config/index.js";11import type { DurableEventInput } from "../session/index.js";12import { SubtaskManager } from "../tasks/index.js";13import type { ExecFn } from "../tasks/index.js";14import type { Workspace } from "../workspace/index.js";15import { runHeadlessTurn } from "./headless.js";16import type { FileLogger } from "./logger.js";1718const CHILD_PROMPT_SUFFIX =19 "\n\nYou are running as an isolated KHAELOR subtask inside a dedicated git worktree. " +20 "Work only inside this worktree. Do not push, merge, or touch branches — the orchestrator " +21 "supervises the merge. Design first, verify before finishing.";2223/** Adapt Workspace.exec to the tasks module's minimal exec seam. */24export function workspaceExec(workspace: Workspace): ExecFn {25 return async (cmd, cwd) => {26 const result = await workspace.exec({ cmd, timeoutMs: 120_000, ...(cwd !== undefined ? { cwd } : {}) });27 return { exitCode: result.exitCode, stdout: result.stdout, stderr: result.stderr };28 };29}3031export interface CreateSubtaskManagerOptions {32 config: ResolvedConfig;33 workspace: Workspace;34 projectRoot: string;35 logger: FileLogger;36 publish: (event: DurableEventInput) => void;37 /** Orchestrator session id — recorded as the child's meta.parent. */38 parentSessionId: string;39}4041/**42 * Build the SubtaskManager with a child runner that assembles a complete43 * headless engine over the worktree: own JSONL (meta.parent → orchestrator),44 * non-interactive permissions (capability attenuation: asks resolve deny),45 * phase gates in the configured mode, native verify active (v2 §6).46 */47export function createSubtaskManager(options: CreateSubtaskManagerOptions): SubtaskManager {48 return new SubtaskManager({49 publish: options.publish,50 exec: workspaceExec(options.workspace),51 projectRoot: options.projectRoot,52 runChild: async (args) => {53 const result = await runHeadlessTurn({54 config: options.config,55 cwd: args.worktreePath,56 prompt: args.description + CHILD_PROMPT_SUFFIX,57 logger: options.logger,58 meta: { parent: options.parentSessionId },59 });60 return {61 status:62 result.outcome === "done" ? "done" : result.outcome === "interrupted" ? "interrupted" : "failed",63 verifyOk: result.verifyOk,64 detail:65 result.outcome === "done"66 ? result.finalText.slice(0, 2000)67 : result.detail || result.finalText.slice(0, 2000),68 };69 },70 });71}72