import { type AgentInfoResult, type ConnectionAuthorizationOutcome, type InputRequest, Client, ClientSession } from "#client/index.js"; import { type SubagentView } from "./subagent-pump.js"; export type { SubagentRun, SubagentStepUpdate, SubagentToolUpdate, SubagentView, } from "./subagent-pump.js"; import { type DevBootProgressReporter } from "#internal/dev-boot-progress.js"; import { type PromptCommand, type PromptCommandSpec } from "./prompt-commands.js"; import { type RemoteConnectionController, type RemoteConnectionControllerOptions, type RemoteConnectionSnapshot } from "./remote-connection.js"; import type { DevelopmentCredentialGate } from "#services/dev-client/credential-gate.js"; import { type BootDetection } from "./setup-issues.js"; import type { SetupFlowRenderer } from "./setup-flow.js"; import type { TraceViewerRenderer } from "./traces/trace-viewer-session.js"; import type { RemoteDevelopmentTarget } from "./target.js"; import type { AssistantResponseStatsMode, LogDisplayMode, TerminalPartDisplayMode, TuiDisplayOptions } from "./types.js"; import { type TerminalInput, type TerminalOutput } from "./terminal-renderer.js"; import { type VercelStatusEffect, type VercelStatusSnapshot } from "./vercel-status.js"; import { type McpConnectionProbe } from "./mcp-connection-status.js"; import type { detectProjectIdentity } from "#setup/project-resolution.js"; import { getVercelAuthStatus } from "#setup/vercel-project.js"; import type { DevDiagnostics } from "../diagnostics.js"; import type { CommandLifecycle } from "../../shutdown.js"; export { parsePromptCommand, type PromptCommand } from "./prompt-commands.js"; export type AgentTUIStreamResult = { events: AsyncIterable | ReadableStream; abort?: () => void; /** * Requests cooperative server-side cancellation of the streaming turn * (`/cancel`, Esc, or Ctrl+C; the keys steer when a message is queued). Unlike * {@link abort} — which drops the client stream and forces a fresh session — * the server settles the turn as `turn.cancelled` → `session.waiting`, so * the stream reaches its boundary normally and the session keeps its context. * Best-effort and idempotent; scoped to the turn the user observed when its id is known. */ cancel?: () => void; turnState?: AgentTUITurnState; }; export type AgentTUIStreamUsage = { inputTokens?: number; outputTokens?: number; }; export type AgentTUIStreamEvent = { type: "step-start"; } | { type: "step-finish"; usage?: AgentTUIStreamUsage; } | { type: "assistant-delta"; id: string; delta: string; } | { type: "assistant-complete"; id: string; text?: string | null; } | { type: "reasoning-delta"; id: string; delta: string; } | { type: "reasoning-complete"; id: string; } | { type: "tool-call-preparing"; toolCallId: string; toolName: string; } | { type: "tool-call"; toolCallId: string; toolName: string; input: unknown; } | { type: "tool-approval-request"; approvalId: string; toolCallId: string; } | { type: "tool-result"; toolCallId: string; output: unknown; } | { type: "tool-error"; toolCallId: string; errorText: string; } | { type: "tool-rejected"; toolCallId: string; reason: string; } | { type: "error"; errorText: string; hint?: string; detail?: string; } | { type: "turn-cancelled"; } | { type: "finish"; usage?: AgentTUIStreamUsage; }; export type AgentTUITurnState = { aborted?: boolean; boundaryEvent?: "session.completed" | "session.failed" | "session.waiting"; pendingApprovals: AgentTUIToolApprovalRequest[]; pendingQuestions: InputRequest[]; sawSessionFailure: boolean; /** Id of the streaming turn, once `turn.started` names it. Scopes cancels. */ turnId?: string; /** True while a cooperative-cancel request loop is running for this turn. */ cancelInFlight?: boolean; }; export type AgentTUISessionOptions = { title?: string; /** * Text to seed the editable prompt buffer with before the user types. * Set by the runner for the first prompt when `eve dev --input` is used. */ initialDraft?: string; submittedPrompt?: string; continueSession?: boolean; tools?: TerminalPartDisplayMode; reasoning?: TerminalPartDisplayMode; subagents?: TerminalPartDisplayMode; connectionAuth?: TerminalPartDisplayMode; assistantResponseStats?: AssistantResponseStatsMode; contextSize?: number; }; export type AgentTUIToolApprovalRequest = { approvalId: string; toolCallId: string; toolName: string; title?: string; input: unknown; }; export type AgentTUIToolApprovalResponse = { approved: boolean; reason?: string; }; export type AgentTUIInputOption = { id: string; label: string; description?: string; style?: "primary" | "danger" | "default"; }; export type AgentTUIInputQuestion = { requestId: string; prompt: string; display: "select" | "text"; options?: ReadonlyArray; allowFreeform?: boolean; }; export type AgentTUIInputQuestionResponse = { optionId?: string; text?: string; }; export type AgentTUIAgentHeader = { name: string; serverUrl: string; info?: AgentInfoResult; /** Message-of-the-day line shown under the brand line (local sessions only). */ tip?: string; }; export type AgentTUIRenderer = { /** * Commits a startup header describing the connected agent (brand mark, * model, instructions, tools, skills, subagents) to the transcript before * the first prompt, and refreshes it after local dev artifact changes. * Optional — renderers without a header simply skip it. */ renderAgentHeader?(header: AgentTUIAgentHeader): void; /** * Commits a single informational line to the transcript. Used for session * recovery and slash-command results. Optional. */ renderNotice?(text: string): void; /** * Commits the session boundary (`┌── Session restarted, clear context.`) * when a dead session is replaced mid-conversation. Optional; renderers * without it get the plain notice. */ renderSessionBoundary?(): void; /** * Commits one development sandbox lifecycle line to the transcript. * Optional so non-terminal renderers can ignore local prewarm progress. */ renderSandboxLog?(text: string): void; renderSetupWarning?(text: string): void; /** Clears the setup attention line once its issue is resolved. */ clearSetupWarning?(): void; /** Commits the startup `/vc:login` invocation to the transcript. */ renderCommandInvocation?(text: string, status?: "failed"): void; renderCommandResult?(text: string, tone?: "success" | "error"): void; readonly setupFlow?: SetupFlowRenderer; /** * The renderer's full-screen local trace viewer, opened by `/traces`. * The returned promise resolves when the user closes the viewer. */ readonly traceViewer?: TraceViewerRenderer; readPrompt?(options?: AgentTUISessionOptions): Promise; /** * Consumes the next prompt produced by mid-turn input: the Esc-popped * steering message when one is staged, otherwise every message queued * during the turn coalesced into one. The runner calls this at a clean * turn boundary and submits the result as the next turn without reading * the prompt. Optional — renderers without mid-turn input never queue. */ takeQueuedPrompt?(): string | undefined; /** * Reports the server session id backing the conversation — pushed by the * runner once a send is accepted, and overwritten when a later session's * turn is accepted. Deliberately sticky across `/reset` and interrupt * recovery: the terminal renderer echoes the LAST session this TUI talked * to in the parting line on exit, so an interrupted conversation (whose * replacement session never ran a turn) can still be found again * (`eve logs`, the session store). Optional. */ setSessionId?(sessionId: string): void; readToolApproval?(request: AgentTUIToolApprovalRequest, options?: AgentTUISessionOptions): Promise; readInputQuestion?(question: AgentTUIInputQuestion, options?: AgentTUISessionOptions): Promise; renderStream(result: AgentTUIStreamResult, options?: AgentTUISessionOptions): Promise; /** * The renderer's whole subagent surface — sections, nested steps and * tools, ghost sweeps, completion. One optional capability with required * members: a renderer either has a subagent view or it doesn't, and a * type-legal partial implementation (which would ghost placeholders or * duplicate parent tool rows) cannot exist. */ readonly subagents?: SubagentView; /** * Out-of-band update for one MCP connection authorization lifecycle. * Called by the runner as `authorization.*` events arrive. * The renderer renders this as a persistent body section per * connection that transitions through `required` → `pending` → * one of the terminal `ConnectionAuthorizationOutcome` states. */ upsertConnectionAuth?(update: ConnectionAuthUpdate): void; /** * Sets the number of connections currently awaiting an OAuth * callback. The renderer overrides its bottom status bar with a * "waiting for connection authorization" hint while this is > 0, * so the user understands the agent is parked, not hung. */ setConnectionAuthPendingCount?(count: number): void; /** * The log display mode currently in effect. Paired with * {@link setLogDisplayMode}; both are absent on renderers that do not * capture process output. */ logDisplayMode?(): LogDisplayMode; /** * Switches which captured log sources (stdout/stderr) the transcript * shows. Captured output is buffered regardless of mode, so a change * applies retroactively: hiding removes already-rendered log lines from * the transcript and showing restores buffered ones at their original * positions. Used by the `/loglevel` command. */ setLogDisplayMode?(mode: LogDisplayMode): void; /** * Commits any delayed local dev build errors immediately before dispatching * a user prompt. Renderers without process-log capture ignore it. */ flushDelayedDevBuildErrors?(): void; /** * Sets the workspace-scoped Vercel segment of the persistent bottom * status line. Pushed by the runner at startup and after Vercel-related * setup outcomes. Renderers without a status line ignore it. */ setVercelStatus?(status: VercelStatusSnapshot): void; /** Sets the remote deployment badge and its current connection/authentication state. */ setRemoteConnectionStatus?(status: RemoteConnectionSnapshot): void; /** * Clears the rendered transcript and resets per-conversation display * state, leaving the UI interactive on a fresh screen. Used by the * `/reset` command to start a new session with a clean slate. */ reset?(): void; /** * Tears down interactive mode and restores the terminal when the runner's * lifecycle ends. */ shutdown?(): void; requestInterrupt?(): void; exitRequested?(): boolean; }; export interface PromptCommandHandlerContext { readonly renderer: AgentTUIRenderer; readonly title: string; /** Provider entry authorized by confirmed boot-time model-access evidence. */ readonly initialModelStep?: "provider"; /** * Leaves the current setup panel mounted for the next automatic onboarding * command. The runner closes it if no next command can proceed. */ readonly keepSetupFlowOpen?: true; readonly remoteConnection?: RemoteConnectionController; readonly withExclusiveTerminal?: (task: () => Promise) => Promise; readonly disabledConnectionReasons?: Readonly>; } /** What one handled slash command leaves behind for the runner to apply. */ export interface PromptCommandOutcome { /** Outcome line rendered under the echoed command; absent renders nothing. */ message?: string; /** Promotes an outcome to a top-level status. */ tone?: "success" | "error"; /** Post-command work after setup settles. */ effect?: VercelStatusEffect | { kind: "model-access-changed"; }; } export interface PromptCommandHandler { handle(command: Extract, context: PromptCommandHandlerContext): Promise; } export type EveTUIRunnerOptions = TuiDisplayOptions & { session?: ClientSession; /** Production TUI probe injected by the launcher; omitted in hermetic runners. */ probeMcpConnection?: McpConnectionProbe; /** * Optional client used to attach to child sessions for live subagent * stream observation. When omitted, the TUI still shows the subagent * section but cannot surface the subagent's reasoning / response / * intermediate events — only the parent-stream `called` and * `completed` transitions. */ client?: Client; renderer?: AgentTUIRenderer; screen?: TerminalOutput; userInput?: TerminalInput; /** * Formats an error thrown while dispatching a turn (the initial * `session.send()` POST — e.g. a transport failure or a Vercel * Deployment Protection challenge) into the text rendered in the * inline error region. Defaults to the error's message. Callers that * know about transport-specific challenges (the `eve dev` glue) inject * a richer formatter here. */ formatTransportError?: (error: unknown) => string; /** * Local `eve dev` server URL. When present, normal prompts refresh the * runtime artifacts after HMR so the next prompt uses the latest authored * artifacts while retaining its logical session. */ serverUrl?: string; /** Absolute local application root; omitted for remote `--url` sessions. */ appRoot?: string; /** * Seeds the editable prompt buffer for the first prompt. A bare local * `/model` starts initial model onboarding. */ initialInput?: string; /** Handles non-core slash commands without adding feature branches to the runner. */ promptCommandHandler?: PromptCommandHandler; /** Commands shown in discovery for this local or remote session. */ availablePromptCommands?: readonly PromptCommandSpec[]; /** Gives setup subprocesses exclusive terminal and development-host ownership. */ withExclusiveTerminal?: (task: () => Promise) => Promise; /** Remote target and mutable OIDC token source, when connected through `--url`. */ remote?: { readonly target: RemoteDevelopmentTarget; readonly credentials: DevelopmentCredentialGate; readonly resolveOidcToken: NonNullable; readonly resolveDeployment: NonNullable; }; /** Boot-time installation-state checks; defaults to the built-ins. */ bootDetections?: readonly BootDetection[]; /** Test seam for the status line's Vercel link probe; defaults to the real one. */ detectProjectIdentity?: typeof detectProjectIdentity; /** Test seam for the off-critical-path boot login probe; defaults to the real one. */ getVercelAuthStatus?: typeof getVercelAuthStatus; /** Reports phases from this runner's initial local-dev connection. */ onBootProgress?: DevBootProgressReporter; /** Parent-owned diagnostics recorder; omitted for remote and test renderers. */ diagnostics?: DevDiagnostics; lifecycle?: CommandLifecycle; }; export declare class EveTUIRunner { #private; constructor(options: EveTUIRunnerOptions); run(): Promise; } export type ConnectionAuthChallenge = { url?: string; userCode?: string; expiresAt?: string; instructions?: string; }; export type ConnectionAuthState = "required" | "pending" | ConnectionAuthorizationOutcome; export type ConnectionAuthUpdate = { name: string; description: string; state: ConnectionAuthState; challenge?: ConnectionAuthChallenge; reason?: string; };