/**
 * Workflow runtime executor.
 *
 * Architecture:
 * 1. `executeWorkflow()` is called by the CLI command (e.g. atomic) or by
 *    the SDK's `runWorkflow()` primitive
 * 2. It creates a tmux session with an orchestrator pane that runs the
 *    SDK-owned `orchestrator-entry.ts` with three positional args:
 *    `<workflowSource> <agent> <inputsB64>`
 * 3. The CLI then attaches to the tmux session (user sees it live)
 * 4. The orchestrator pane imports the workflow module by `source`,
 *    calls `runOrchestrator(definition, inputs)`, which then calls
 *    `definition.run(workflowCtx)` — the user's callback uses
 *    `ctx.stage()` to spawn agent sessions
 *
 * The dev's CLI is never re-imported. The SDK orchestrator entry script
 * is the only re-exec target, so there is no orchestrator-mode env var
 * re-entry signal and no boilerplate in user code.
 */
import type { WorkflowDefinition, WorkflowInput, AgentType, SavedMessage, StageClientOptions } from "../types.ts";
import { type ProviderOverrides } from "../../services/config/definitions.ts";
/** Maximum time (ms) for the SDK probe to succeed after port is discovered. */
export declare const SERVER_PROBE_TIMEOUT_MS = 60000;
export { errorMessage } from "../errors.ts";
export interface WorkflowRunOptions {
    /** The compiled workflow definition */
    definition: WorkflowDefinition;
    /** Agent type */
    agent: AgentType;
    /**
     * Structured inputs for this run. Free-form workflows model their
     * single positional prompt as `{ prompt: "..." }` so workflow
     * authors can read `ctx.inputs.prompt` uniformly regardless of
     * whether the workflow declares a schema. Empty record is valid.
     */
    inputs?: Record<string, string>;
    /** Project root (defaults to cwd) */
    projectRoot?: string;
    /**
     * When true, create the tmux session and return immediately instead
     * of attaching. The orchestrator keeps running in the background on
     * the atomic tmux socket; users can attach later with
     * `atomic workflow session connect <name>`.
     */
    detach?: boolean;
}
/**
 * Resolve a non-JS Copilot CLI binary on PATH.
 *
 * Under Bun, `@github/copilot-sdk` spawns its bundled JS entry via `node`
 * (see `getNodeExecPath` in the SDK). If `node` isn't installed — common in
 * minimal containers — the spawn fails silently with ENOENT and the SDK's
 * write to the child's stdin surfaces as "Cannot call write after a stream
 * was destroyed" from vscode-jsonrpc. Pointing the SDK at a standalone
 * `copilot` binary (the npm-installed ELF executable) sidesteps the
 * node-vs-bun problem because the SDK execs it directly when the path does
 * not end in `.js`.
 *
 * Returns undefined if no suitable binary is found.
 */
export declare function discoverCopilotBinary(): string | undefined;
/**
 * True when we need to override the SDK's default CLI path — i.e. running
 * under Bun, the user hasn't set COPILOT_CLI_PATH, and `node` is not
 * available to execute the SDK's bundled JS entry.
 *
 * Pure predicate on the current env; safe to call repeatedly.
 */
export declare function shouldOverrideCopilotCliPath(): boolean;
/**
 * Set safe env defaults for the orchestrator process before any SDK is
 * loaded. Idempotent — subsequent calls no-op once `COPILOT_CLI_PATH`
 * is set. Call as early as possible so headless Copilot subprocesses
 * inherit the resolved env.
 */
export declare function applyContainerEnvDefaults(): void;
export declare function buildPaneCommand(agent: AgentType, overrides?: ProviderOverrides, extraChatFlags?: string[]): {
    command: string;
    envVars: Record<string, string>;
};
export declare function waitForServer(agent: AgentType, paneId: string): Promise<string>;
/**
 * Escape a string for safe interpolation inside a bash double-quoted string.
 *
 * In bash `"..."` strings only `$`, `` ` ``, `\`, `"`, and `!` are special.
 * Single quotes are literal inside double quotes and need no escaping.
 * Null bytes are stripped because bash strings cannot contain them.
 */
export declare function escBash(s: string): string;
/**
 * Escape a string for safe interpolation inside a PowerShell double-quoted string.
 *
 * In PowerShell `"..."` strings, backtick is the escape character and `$` triggers
 * variable expansion.  Null bytes are stripped for safety.
 */
export declare function escPwsh(s: string): string;
/**
 * Coerce raw string inputs to their declared runtime types. Integer inputs
 * become `number`; every other declared type passes through as `string`.
 * Unknown keys (not in the schema) are preserved as strings.
 *
 * Invalid integer strings fall back to the key being dropped — validation
 * already runs upstream (in `validateInputsAgainstSchema`), so reaching
 * this path with garbage means the executor was invoked out-of-band.
 */
export declare function coerceInputsBySchema(inputs: Record<string, string>, schema: readonly WorkflowInput[]): Record<string, string | number>;
/**
 * Called by `atomic workflow -n <name> -a <agent> <prompt>`.
 *
 * Always creates a tmux session in the atomic socket with the
 * orchestrator as the initial pane, then attaches so the user sees
 * everything live — even when invoked from inside another tmux session.
 */
export declare function executeWorkflow(options: WorkflowRunOptions): Promise<{
    id: string;
    tmuxSessionName: string;
}>;
/** Type guard for objects with a string `content` property (Copilot assistant.message data). */
export declare function hasContent(value: unknown): value is {
    content: string;
};
export declare function renderMessagesToText(messages: SavedMessage[]): string;
/**
 * Minimal Copilot session surface required by `wrapCopilotSend()`.
 * Uses a generic `on` signature to remain compatible with both the real
 * CopilotSession and lightweight test mocks.
 */
export interface CopilotSendSessionSurface {
    on(eventType: string, handler: (event: {
        data?: unknown;
    }) => void): () => void;
}
/**
 * Wraps a Copilot session's `send()` to block until `session.idle` fires.
 *
 * Copilot's `send()` is fire-and-forget — it returns immediately after
 * queuing the message.  This wrapper blocks the returned promise until the
 * session emits `session.idle` (turn complete) or `session.error`.
 *
 * HIL detection for Copilot is handled separately by
 * `watchCopilotSessionForHIL()`, which subscribes to the session's
 * `tool.execution_start` / `tool.execution_complete` events for the
 * `ask_user` built-in tool.  Those events fire regardless of whether
 * an `onUserInputRequest` handler is registered, so we can detect HIL
 * via native SDK events while the CLI continues to handle user input
 * locally in the tmux pane.
 *
 * Exported for unit testing.
 */
export declare function wrapCopilotSend<O, R>(session: CopilotSendSessionSurface, nativeSend: (options: O) => Promise<R>): (options: O) => Promise<R>;
/**
 * Minimal shape of an event as produced by the OpenCode v2 SDK event stream.
 * Using a structural interface rather than the SDK's generated union type keeps
 * this helper independently unit-testable with plain objects.
 *
 * `sessionID` is optional because many OpenCode event types (e.g.
 * `file.edited`, `session.compacted`) carry properties without that field.
 * The `watchOpencodeStreamForHIL` implementation guards with a runtime check.
 */
export interface OpenCodeHILEvent {
    type: string;
    properties: {
        sessionID?: string;
        [key: string]: unknown;
    };
}
/**
 * Consume an OpenCode SSE event stream and call `onHIL` whenever the session
 * with `sessionId` enters or exits a human-in-the-loop (HIL) state:
 *
 *   - `question.asked`    → `onHIL(true)`   (agent awaiting user input)
 *   - `question.replied`  → `onHIL(false)`  (user answered, agent resumes)
 *   - `question.rejected` → `onHIL(false)`  (user dismissed, agent resumes)
 *
 * Events for other sessions are silently ignored.  The function returns when
 * the stream is exhausted (i.e. the server closes the connection).
 *
 * NOTE: OpenCode does not emit any bus event for MCP-server-initiated
 * elicitation requests — its MCP client never registers an
 * `ElicitRequestSchema` handler, so such requests are auto-rejected by the
 * MCP SDK at the protocol layer before reaching any OpenCode-level code.
 * As a result, the workflow UI **cannot** mark an OpenCode session as
 * "awaiting input" for MCP elicitation; this is an upstream limitation that
 * Atomic cannot work around.  If a future OpenCode release surfaces MCP
 * elicitation as a bus event, extend the switch below (or add a sibling
 * watcher) to map it onto `onHIL`.
 *
 * Exported for unit testing.
 */
export declare function watchOpencodeStreamForHIL(stream: AsyncIterable<OpenCodeHILEvent>, sessionId: string, onHIL: (waiting: boolean) => void): Promise<void>;
/**
 * Minimal Copilot session surface required by `watchCopilotSessionForHIL()`.
 * A structural `on()` signature keeps this helper independently unit-testable
 * with plain objects and compatible with both the real CopilotSession and
 * test mocks.
 */
export interface CopilotHILSessionSurface {
    on(eventType: string, handler: (event: {
        data?: unknown;
    }) => void): () => void;
}
/**
 * Subscribe to a Copilot session's tool-execution events to track HIL state
 * for the `ask_user` built-in tool:
 *
 *   - `tool.execution_start`    with `toolName === "ask_user"` → `onHIL(true)`
 *   - `tool.execution_complete` with matching `toolCallId`     → `onHIL(false)`
 *
 * These events fire regardless of whether an `onUserInputRequest` handler is
 * registered, so we can detect HIL without providing one — letting the CLI
 * keep its native tmux-pane dialog.
 *
 * Overlapping `ask_user` invocations are tracked by `toolCallId` so
 * `onHIL(false)` only fires after the last active request resolves.
 *
 * Returns an unsubscribe function that removes both listeners.
 *
 * Exported for unit testing.
 */
export declare function watchCopilotSessionForHIL(session: CopilotHILSessionSurface, onHIL: (waiting: boolean) => void): () => void;
/**
 * Subscribe to a Copilot session's elicitation events to track HIL state for
 * `session.ui.elicitation()`, `session.ui.select()`, `session.ui.input()`, and
 * MCP-server-initiated elicitation requests:
 *
 *   - `elicitation.requested`  → `onHIL(true)`  (set transitions empty→non-empty)
 *   - `elicitation.completed`  → `onHIL(false)` (set transitions non-empty→empty)
 *
 * Overlapping elicitation requests are tracked by `requestId` so
 * `onHIL(false)` only fires after the last in-flight request completes.
 *
 * Returns an unsubscribe function that removes both listeners.
 *
 * Exported for unit testing.
 */
export declare function watchCopilotSessionForElicitation(session: CopilotHILSessionSurface, onHIL: (waiting: boolean) => void): () => void;
/**
 * Append tool names to a Copilot `excludedTools` list without duplicating
 * entries the caller already supplied. Exported for unit testing.
 */
export declare function mergeExcludedTools(existing: string[] | undefined, extras: string[]): string[];
type ExternalCopilotClientOptions = Omit<StageClientOptions<"copilot">, "gitHubToken" | "useLoggedInUser">;
interface ExternalCopilotOptions {
    clientOptions: ExternalCopilotClientOptions;
    sessionGitHubToken?: string;
}
/**
 * Copilot SDK 0.3.0 rejects client-level auth options when connecting to an
 * existing `cliUrl`. Visible stages use an already-running TUI server, so move
 * token auth to the session-level option that 0.3.0 introduced for this case.
 */
export declare function normalizeExternalCopilotOptions(clientOptions: StageClientOptions<"copilot">, sessionGitHubToken?: string): ExternalCopilotOptions;
export { validateOrchestratorEnv } from "./executor-env.ts";
/**
 * Run the orchestrator for a compiled workflow definition.
 *
 * Called by the SDK's `orchestrator-entry.ts` after it imports the
 * workflow module by `source` and decodes the inputs payload from argv.
 * The runtime environment (`ATOMIC_WF_ID`, `ATOMIC_WF_TMUX`,
 * `ATOMIC_WF_AGENT`, `ATOMIC_WF_CWD`) is set by the launcher script that
 * `executeWorkflow()` writes — those vars describe *where* this
 * orchestrator is running, not what to do.
 */
export declare function runOrchestrator(definition: WorkflowDefinition, inputs?: Record<string, string>): Promise<void>;
//# sourceMappingURL=executor.d.ts.map