/** * Host channel: the runner running inside the Melaya desktop app. * * The desktop app (desktop/src/main/runnerHost.ts) starts this runner in an * Electron utilityProcess. There, `process.parentPort` is a message port to the * app's main process; under plain Node (`npx @melaya/runner`) it is undefined * and every function here is a no-op, so the CLI behaves exactly as before. * * The runner token arrives as the first host message ({ type: "start", token }) * and never through argv or env, so it does not show up in process listings. * * The message types below MIRROR packages/desktop-contract/src/index.ts * (RunnerToHostMessage / HostToRunnerMessage) and src/computer.ts. The runner * build (tsc, rootDir src) cannot import that package, so keep both in step. */ export type HostedRunnerState = "starting" | "online" | "reconnecting" | "blocked" | "error"; /** Why a terminal "error" happened, so the app can react without parsing text. */ export type HostedStatusCode = "token_rejected" | "server_disconnect"; /** Mirror of the contract's RunnerToHostMessage (computer messages kept loose). */ export type RunnerToHostMessage = { type: "status"; state: HostedRunnerState; lastError?: string; code?: HostedStatusCode; } | { type: "log"; level: "info" | "warn" | "error"; line: string; } | { type: "version"; runnerVersion: string; } /** Additive (runner side first; the contract mirror is the coordinator's): startup stage offsets in ms from process start. */ | { type: "timings"; stages: Partial>; } /** Additive: background setup progress. `waiting` = a request is waiting for this task to finish. */ | { type: "progress"; task: "runtime_setup"; state: "running" | "done" | "failed"; step?: string; waiting?: boolean; } | { type: "computer.command"; id: string; action: unknown; deadlineMs: number; allowedAppIds: string[]; allowedApps?: Array<{ appId: string; tier: "view" | "click" | "full"; expiresAt?: string; }>; pauseBudgetMs?: number; } | { type: "computer.stop"; reason: string; } | { type: "computer.capabilities.request"; } | { type: "computer.file"; path: string; name: string; origin: "download" | "output"; handleHint?: string; } | { type: "computer.approval.request"; approvalId: string; summary: string; effect: string; appName?: string; expiresAt: string; } | { type: "computer.approval.closed"; approvalId: string; } /** Additive: something the user must fix on this computer; the app shows it natively. */ | { type: "notice"; code: "browser_not_installed"; }; /** Mirror of the contract's HostToRunnerMessage (computer messages kept loose). */ export type HostToRunnerMessage = { type: "stop"; } /** `appVersion`: the desktop app's own version (additive; reported in runner:hello's `host` block). */ | { type: "start"; token: string; appVersion?: string; } /** Additive: rescan model providers now and publish the list through runner:models. */ | { type: "rescan_models"; } | { type: "computer.result"; id: string; result: unknown; } | { type: "computer.capabilities"; capabilities: unknown; } | { type: "computer.approval.answer"; approvalId: string; decision: "approve" | "decline"; }; /** True when this runner was started by the Melaya desktop app. */ export declare function isHosted(): boolean; /** Send one message to the desktop app. No-op outside the app; never throws. */ export declare function sendToHost(msg: RunnerToHostMessage): void; /** Subscribe to messages from the desktop app. Returns an unsubscribe function. */ export declare function onHostMessage(cb: (msg: HostToRunnerMessage) => void): () => void; /** Strip anything token-shaped from a reason before it leaves the process. */ export declare function redactReason(s: string): string; /** Report a state change to the desktop app. No-op outside the app. */ export declare function hostStatus(state: HostedRunnerState, lastError?: string, code?: HostedStatusCode): void; /** Background setup progress for the desktop app. No-op outside the app. */ export declare function hostProgress(state: "running" | "done" | "failed", step?: string, waiting?: boolean): void; /** The desktop app's own version, as its start message said; null outside the * app and with an app older than the field. */ export declare function hostAppVersion(): string | null; /** * Wait for the token from the desktop app. Resolves with the token, or rejects * when nothing valid arrives within `timeoutMs`. */ export declare function waitForHostToken(timeoutMs?: number): Promise; /** * Exit after giving the last host message time to leave the process. The * parentPort queue is asynchronous; exiting in the same tick can drop it. */ export declare function exitHostedSoon(code: number, delayMs?: number): void;