import { EventStream } from '../event-stream.js';
import type { FrameworkEvent } from '../events.js';
import { type AgentMeta } from '../store/index.js';
import type { StartAgentKind, StartAgentOptions, StartAgentResult } from './types.js';
/**
 * The server-side half of "run on a connected device" (#1067). The local daemon holds the saved
 * device's token, so it - not the browser - drives the remote daemon: it POSTs the agent to the
 * remote's `/_relay/start` and then fetch-streams the remote's `/_relay/events` back into a local
 * {@link EventStream}, which the dashboard reads over its normal same-origin `onEvents` channel. So
 * the browser never talks cross-origin and the token never leaves the two daemons (issue #1067 (b)).
 *
 * Authentication is the shared-token cookie (#1051), sent daemon-to-daemon: `Cookie: fw_daemon=<token>` with no
 * `Origin` header. The remote's guard admits a matching cookie without the browser-only `?token=`
 * 302, and its `/_rpc` CSRF check (absent Origin passes) is not even on these raw routes.
 */
/** Where a relayed agent executes: the remote daemon's origin and its #1051 token. Memory-only. */
export interface RemoteTarget {
    url: string;
    token: string;
}
/** The body a relay start forwards to the remote's `/_relay/start`. */
export interface RelayStartBody {
    prompt: string;
    kind: StartAgentKind;
    options: StartAgentOptions;
}
/**
 * Health-check a saved device (#1072): a cookie'd `GET /_relay/ping`, true on any 2xx, false on a
 * non-2xx, an unreachable host, or the timeout. The token stays in memory for the check only, never
 * persisted, same as {@link startRemoteAgent}. This is how the browser's status dots learn reachable
 * from not: it has the tokens, the daemon does the cross-origin request.
 */
export declare function pingRemote(target: RemoteTarget): Promise<boolean>;
/**
 * Start an agent on the remote daemon and return its {@link StartAgentResult} (with the remote's own run
 * id). A non-2xx or a transport failure surfaces as an `ok: false` result the dashboard shows, the
 * same shape a local refusal has, so the caller does not special-case remote errors.
 */
export declare function startRemoteAgent(target: RemoteTarget, body: RelayStartBody): Promise<StartAgentResult>;
/**
 * Relay one run-scoped RPC to the device that owns a remote agent (#1067 slice 2). The local daemon
 * holds the device token, so a read/diff/handoff/push/PR for a relayed agent runs ON the device: POST
 * {fn, args} to the remote's /_relay/rpc over the shared-token cookie (#1051) (no Origin), returning the device's
 * result. Throws on an unreachable device or a non-2xx so the caller falls back to its own empty/error
 * shape, the same way a failed local read does.
 */
export declare function relayRpc(target: RemoteTarget, fn: string, args: unknown[]): Promise<unknown>;
/**
 * Fetch-stream a remote agent's newline-delimited events into `onEvent` until the remote closes the
 * body, the agent ends, or `cancel()` is called. A 401 (the token was rotated) ends the stream
 * cleanly rather than as an error, so the dashboard sees a normal `done`, not a lost connection.
 * Returns a cancel function; calling it aborts the fetch and releases the reader.
 */
export declare function streamRemoteEvents(target: RemoteTarget, agentId: string, onEvent: (event: FrameworkEvent) => void, onEnd?: () => void): () => void;
/**
 * The local daemon's live relayed runs (#1067), keyed by the remote agent id. Registering an agent opens
 * an {@link EventStream} the dashboard reads through `onEvents`, fed by {@link streamRemoteEvents}
 * from the remote. This map is where a saved device's token lives daemon-side: in memory, for the
 * run's lifetime.
 *
 * The `targets` map outlives the event pump (#1067 slice 2): a finished remote agent's post-run reads,
 * push and open-PR still have to reach the device after its event stream has ended, so the device
 * target is kept until {@link dispose} clears it, not dropped when the stream closes.
 *
 * The `metas` map (#1077) holds a local {@link AgentMeta} stub per relayed agent so `onAgents` can show a
 * remote run in the session list and re-open it after a dashboard reload; {@link list} projects it
 * per project. Same lifetime as `targets`: it outlives the event stream and is cleared on dispose.
 */
export declare class RelayedAgents {
    private readonly agents;
    private readonly targets;
    private readonly metas;
    /** Open a local stream for a remote agent and start pumping the remote's events into it. */
    register(agentId: string, target: RemoteTarget, meta: AgentMeta, projectId: string): void;
    /** The live event stream for a relayed agent, or undefined when this daemon is not relaying it. */
    get(agentId: string | undefined): EventStream<FrameworkEvent> | undefined;
    /** The device a relayed agent runs on, kept past the event stream so post-run push/PR still reach it. */
    target(agentId: string | undefined): RemoteTarget | undefined;
    /** A project's relayed run stubs (#1077), newest-first, so `onAgents` can surface them in the list. */
    list(projectId: string): AgentMeta[];
    /** Fold each relayed event into the agent's list row via the store's own reducer (#1077), so the
     *  local stub mirrors the device: the terminal status on `end`, the waiting flag while it is parked
     *  (#785), the driver once its session starts. Events carry no write time, so this stamps its own. */
    private apply;
    /** Close a relayed agent's event stream (not its target). Idempotent. */
    private endStream;
    /** Stop every pump, close every stream, and forget every device target + list stub, on daemon shutdown. */
    dispose(): void;
}
//# sourceMappingURL=remote-run.d.ts.map