export interface MachineEntry { cortexPath: string; gpuCount: number; ssh?: string; win?: boolean; } export type MachineRegistry = Record; export declare function setAdminNotifier(fn: (text: string) => void): void; /** * Load machines.json from disk into memory. * On first call (startup), throws if file is missing or malformed. * On subsequent calls (hot-reload), logs errors and keeps old config. */ declare function loadMachinesFromFile(failOnError?: boolean): void; /** * Return the current in-memory machine registry. */ declare function getMachineRegistry(): MachineRegistry; /** * Return the first machine key in the registry as the local/default machine. * Falls back to 'local' if no machines are registered. */ declare function getLocalMachine(): string; /** * Start watching machines.json for changes. Reloads on file edit. * Handles atomic file replacement (rename event) by re-creating the watcher. */ declare function startMachineRegistryWatcher(): void; /** * Stop watching machines.json (for tests / graceful shutdown). */ declare function stopMachineRegistryWatcher(): void; declare function generateTaskId(): string; declare function buildDispatchSessionName(taskId: any): string; /** Test-only: directly set the in-memory machine registry. */ declare function _testSetRegistry(registry: MachineRegistry): void; export interface SplitOutcome { handled: boolean; note?: string; error?: string; } /** Process a worker thread's [SPLIT] decomposition proposal after dispatch: * decompose keep-parent (the task becomes a join/acceptance node over its new children) * and unclaim it so the children flow through the normal queue. Parse errors are surfaced * (and the task still unclaimed) instead of silently dropped. Deps are injected by the * caller (task-dispatch wires the real detect/decompose/unclaim) — keeps this testable * and this module free of thread-system imports. */ declare function processSplitOutcome(args: { threadId: string; taskId: string | null; project: string; }, deps: { detect: (threadId: string) => { split: boolean; subtasks: any[] | null; error: string | null; }; decompose: (project: string, text: string | null, subtasks: any[], taskId: string | null, options: { keepParent?: boolean; }) => { success: boolean; message: string; } | Promise<{ success: boolean; message: string; }>; unclaim: (taskId: string) => Promise; }): Promise; export interface AbortOutcome { handled: boolean; note?: string; error?: string; } /** Canonical block reason for a worker-aborted task. Single source so the runner's * pre-onEnd block (DR-0015 problem 2) and processAbortOutcome produce byte-identical * reasons — a second block with the same reason is a no-op commit (git porcelain sees no * change), so blocking in both places is safe. */ export declare function formatWorkerAbortReason(raw: string | null): string; /** Process an aborted dispatch thread: the worker said "I can't" ([ABORT: ]) — * block the task with the abort reason. taskMutator.block publishes task.blocked, which * wakes a manager thread waiting on this task (its parent re-plans); with no manager the * block surfaces to humans/stage-gate as usual. Also fixes the pre-existing bug where * aborted dispatch threads were finalized as successes (publishing a bogus task.completed). * Not counted as a dispatch failure — abort is a judgment, not a fault. */ declare function processAbortOutcome(args: { threadId: string; taskId: string | null; project: string; }, deps: { getThread: (threadId: string) => { status: string; abortReason: string | null; } | null; block: (taskId: string, reason: string) => Promise<{ success: boolean; message: string; }>; }): Promise; export { getMachineRegistry, getLocalMachine, loadMachinesFromFile, startMachineRegistryWatcher, stopMachineRegistryWatcher, generateTaskId, buildDispatchSessionName, processSplitOutcome, processAbortOutcome, _testSetRegistry, };