/** * The workflow daemon's HTTP face: a plain node:http server on loopback exposing the single * MCP endpoint required by the Streamable HTTP spec (2025-11-25), plus a non-MCP /healthz * identity probe. One StreamableHTTPServerTransport + WorkflowServer per session (the SDK * transport is single-session by design), all sessions of a project sharing that project's * WorkflowManager and BackgroundRunRegistry. * * The SDK transport owns the spec mechanics — session id issuance, 400-on-missing-session, * protocol-version validation, DELETE termination, SSE priming/resume via the injected * EventStore. This module owns what the SDK deliberately leaves outside: routing by * Mcp-Session-Id (including the spec's 404 for unknown sessions, which tells clients to * re-initialize), Origin/Host validation, and project binding. */ import type { AgentRunner } from "@automatalabs/shared-types"; import { WorkflowProjectRegistry } from "../project-registry.js"; import { WorkflowPermissionBroker } from "../workflow-permissions.js"; import { SessionRegistry } from "./session-registry.js"; export interface CreateDaemonOptions { runner: AgentRunner; /** Live ACP permission broker installed on runner.onPermissionRequest by the composition root. */ permissionBroker?: WorkflowPermissionBroker; /** 0 binds an ephemeral port (tests); the actually bound port is on the handle. */ port: number; host?: string; env?: Record; log?: (line: string) => void; /** * This daemon's identity for discovery/succession accounting. Defaults to `process.pid`; * injected in tests. It is the pid reported by /healthz and compared against `daemon.json` * to decide lame-duck (superseded) status. */ ownPid?: number; /** Opaque daemon-generation identity used by run leases and control routing. */ ownInstanceId?: string; /** * The version string reported by /healthz. Defaults to `SERVER_VERSION`; injected in tests * to simulate a divergent (older/newer) daemon that a current-version shim must supersede. */ version?: string; /** * Whether this daemon has been superseded (a newer daemon owns discovery). A lame-duck * daemon admits no new MCP sessions. Defaults to the family-pointer check * (`isSupersededBy(ownPid)`). The daemon LATCHES the first true: once superseded, always * superseded, whatever the check says later. Injected in tests. */ isSuperseded?: () => boolean; } export interface DaemonHandle { port: number; url: string; startedAt: string; instanceId: string; controlUrl: string; sessions: SessionRegistry; projects: WorkflowProjectRegistry; activeRunCount(): number; /** Requests (POSTs) being processed right now, across every session. */ inflightRequestCount(): number; /** True when a newer daemon owns this family's discovery pointer (this one is a lame duck). */ isSuperseded(): boolean; /** * The lame-duck migration: close every session with no request in flight, so its client transparently re-initializes on the successor. Returns * the closed session ids. */ evictDrainableSessions(): string[]; /** Scan durable whole-stop intents; calls coalesce while one scan is in flight. */ processPendingControlIntents?(): Promise; close(): Promise; } export declare class DaemonPortInUseError extends Error { readonly port: number; constructor(port: number); } export declare function createDaemon(options: CreateDaemonOptions): Promise; //# sourceMappingURL=http-daemon.d.ts.map