import type { TaskGenerationExpectation } from '../../core/task-parser.js'; export interface MachineEntry { cortexPath: string; gpuCount: number; ssh?: string; win?: boolean; /** * Command the server runs (over SSH) to launch cortex-client on this machine. * Defaults to `cortex-client`. Override for machines where a bare `cortex-client` * isn't on the non-login SSH PATH — e.g. nvm installs need `bash -lc cortex-client` * so the login profile puts node + cortex-client on PATH. The token-injection and * nohup/echo-$! (Linux) / cmd.exe-wrap WMI (Windows) machinery wraps this command. */ clientCommand?: string; /** * Command the server runs (over SSH) to install the client tgz on this machine * during a dev-mode hot-reload. Defaults to `npm install -g `. Override for * machines where a bare `npm` is not on the non-interactive SSH PATH (e.g. nvm * installs, where npm is only sourced in a login/interactive profile). * The template may contain the `{tgz}` placeholder for the remote tgz path; if the * placeholder is absent, the path is appended. Examples: * "bash -lc 'source ~/.nvm/nvm.sh && npm install -g {tgz}'" * "/home/u/.nvm/versions/node/v20.19.5/bin/npm install -g" */ installCommand?: string; } 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; 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; } interface SplitOutcomeArgs { threadId: string; taskId: string | null; project: string; ownership?: TaskGenerationExpectation; } interface SplitDetection { split: boolean; subtasks: any[] | null; error: string | null; } interface SplitOutcomeDeps { detect: (threadId: string) => SplitDetection; decompose: (project: string, text: string | null, subtasks: any[], taskId: string | null, options: { keepParent?: boolean; ownership?: TaskGenerationExpectation; }) => { success: boolean; message: string; } | Promise<{ success: boolean; message: string; }>; unclaim: (taskId: string) => Promise; } /** Process a worker thread's [SPLIT] proposal and preserve dispatch ownership. */ declare function processSplitOutcome(args: SplitOutcomeArgs, deps: SplitOutcomeDeps): 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, };