import type { DelegationDispatcher, PreflightParams, PreflightResult } from "./dispatcher.js"; import type { DelegationLifecycle } from "./lifecycle.js"; import type { DelegationMonitor } from "./monitor.js"; import type { NotificationRouter } from "./notification-router.js"; import type { PeriodicNotifier } from "./periodic-notifier.js"; import type { DelegationResult, DelegationSignalSource, DelegationStatus } from "./types.js"; import { z } from "zod"; import { type OpenCodeClient } from "../../shared/session-api.js"; /** * Zod-validated SDK message shape covering both `info.*` wrapper and * top-level field positions. Used by the typed extraction functions below * to avoid inline type assertions (`as SdkMessage`, `as Record`). */ export declare const sdkMessageSchema: z.ZodObject<{ role: z.ZodOptional; info: z.ZodOptional; error: z.ZodOptional; }, z.core.$strip>>; error: z.ZodOptional; }, z.core.$strip>; /** Inferred body type from the Zod schema. */ export type SdkMessageShape = z.infer; /** * Extract the role field from an SDK message, preferring `info.role` over * the top-level `role` (the nested wrapper is the newer SDK format). * * @param msg - A parsed SDK message body (Zod-validated). * @returns The role string, or `undefined` if neither field is present. */ export declare function extractSdkMessageRole(msg: SdkMessageShape): string | undefined; /** * Extract a concise error string from an SDK message. Searches `info.error` * first, then falls back to top-level `error`. For object errors, extracts * the `.message` property if available; otherwise returns `String(errorField)`. * * This function deliberately does NOT use `JSON.stringify()` on the error * field — JSON.stringify produces unreadable long strings for complex objects. * * @param msg - A parsed SDK message body (Zod-validated). * @returns A concise error string, or `undefined` if no error field is present. */ export declare function extractSdkMessageError(msg: SdkMessageShape): string | undefined; export type DispatchParams = PreflightParams; export interface ChainStep { agent: string; prompt: string; usePreviousResult?: boolean; } export interface DelegationCoordinatorDeps { childSessionStarter?: { start: (params: ChildSessionStartParams) => Promise; }; dispatcher: Pick; monitor: Pick; notificationRouter: Pick; lifecycle: Pick & Partial>; detector: { signalCompletionEvent: (delegationId: string, result?: DelegationResult) => void; signalTerminalStatus: (delegationId: string, status: DelegationStatus) => void; unwatch: (delegationId: string) => void; watchDualSignal: (delegationId: string, childSessionId: string, callback: (result: DelegationResult) => void) => void; }; periodicNotifier?: Pick; onChildSessionCreated?: (childSessionId: string, parentSessionId: string) => void; client?: OpenCodeClient; /** * P58.8 S1 (REQ-58-07): optional session manager reference used to start * the capture-pane polling loop after a child session is created. When * undefined, no polling is started (tmux may be unavailable or the * integration is not wired in the current environment). */ sessionManager?: { startPolling(intervalMs?: number): void; }; /** * S5b fix: optional tmux integration surface used to synthesize a * `EnrichedSessionEvent` and invoke the panel-spawn adapter when the * OpenCode SDK does not fire `session.created` for an SDK-created * child session. Mirrors the `onChildSessionCreated` fallback for * session-tracker; closes the gap documented in * `.planning/debug/s5-panel-spawn-root-cause-2026-06-04.md`. * * The shape is intentionally narrow — only the surface the * coordinator needs (synthesize event → call `onSessionCreated`). The * full `TmuxIntegration` type is broader and would create a * `src/coordination` → `src/features/tmux` import cycle (the tmux * feature layer is a leaf for the coordination layer's purposes). */ tmuxIntegration?: { adapter: import("../../features/tmux/types.js").SessionManagerAdapter; }; } export interface ChildSessionStartParams { agent: string; delegationId: string; parentSessionId: string; prompt: string; validatedAgent: PreflightResult["validatedAgent"]; workingDirectory: string; onChildSessionId?: (childSessionId: string) => void; model?: { providerID: string; modelID: string; }; } export interface ChildSessionStartResult { childSessionId: string; /** * Title generated for the child session by the starter (see * `generateSessionTitle` in `sdk-child-session-starter.ts`). Surfaced * back to the coordinator so it can populate * `EnrichedSessionEvent.properties.info.title` when synthesizing a * fallback event for the tmux panel-spawn path. Without this, the * synthesized event would have to fall back to a generic placeholder. */ title: string; /** * Resolved working directory for the child session. Mirrors the * `workingDirectory` field of the corresponding * `ChildSessionStartParams` and is surfaced for tmux-fallback event * synthesis so the pane can be opened in the right project root. */ workingDirectory: string; } export interface ExecutionSignalInput { source: DelegationSignalSource; observedAt?: number; actionDelta?: number; messageDelta?: number; toolDelta?: number; } /** SDK-free delegate-task v2 wire coordinator; the tool layer still owns native Task dispatch. */ export declare class DelegationCoordinator { private readonly deps; private readonly active; private readonly delegationByChildSession; constructor(deps: DelegationCoordinatorDeps); /** Runs pre-flight, records metadata, starts monitoring, and registers dual-signal completion. */ dispatch(params: DispatchParams): Promise; /** Record the first observable child action/message/tool signal; promptAsync acceptance never calls this. */ recordExecutionSignal(delegationId: string, signal: ExecutionSignalInput): void; /** Record a runtime message observation for a tracked child session. */ recordChildMessageSignal(childSessionId: string, observedAt?: number, finalMessageExcerpt?: string): void; /** Record a runtime tool observation for a tracked child session. */ recordChildToolSignal(childSessionId: string, observedAt?: number): void; /** Mark a delegation as unconfirmed when the 60s first-action window expires without signals. */ markExecutionUnconfirmed(delegationId: string, elapsedSeconds: number): Promise; /** Handles terminal completion and performs monitor, notification, slot, and persistence cleanup. */ handleCompletion(delegationId: string, result: DelegationResult): void; /** Marks a delegation timed out and performs the same cleanup path as terminal completion. */ handleTimeout(delegationId: string): void; /** Updates the child session mapping once the native Task seam returns a real session ID. */ attachChildSession(delegationId: string, childSessionId: string): void; private getDelegationIdForChildSession; /** Converts a native Task dispatch failure into terminal cleanup without leaking active resources. */ failDispatch(delegationId: string, caughtError: unknown): void; /** Aborts an active delegation and releases all coordinator-owned resources. */ abortDelegation(delegationId: string, reason?: string): DelegationResult; /** Cancels tracking for an active delegation without asserting child termination. */ cancelDelegation(delegationId: string, reason?: string): DelegationResult; /** Routes child session idle hook observations into the v2 completion path. */ handleSessionIdle(childSessionId: string): void; /** Routes child session error hook observations into the v2 completion path. */ handleSessionError(childSessionId: string, caughtError?: unknown): void; /** Routes child session deleted hook observations into the v2 completion path. */ handleSessionDeleted(childSessionId: string): void; /** Dispatches a bounded sequential chain, passing prior results into later prompts when requested. * When sendPromptAsync is provided, steps after the first append to the previous child session * instead of creating a new one. */ chain(delegations: ChainStep[], sendPromptAsync?: (sessionId: string, prompt: string) => Promise): Promise; private buildChainResult; /** * P58.8 S4 (REQ-58-10): detach the child event bus subscription * for the given delegation. Resolves the child session id from the * active map so we do not have to pass it through every terminal * path. Idempotent — the bus is a no-op if no subscription was * ever registered. Errors are caught and logged via the client's * app.log envelope (best-effort cleanup, do not block the * terminal transition). */ private unsubscribeChildEventBus; private cleanup; private findRecord; private mergeCompletionResult; private handleChildSessionTerminal; private buildChildCompletionResult; private routeTerminal; private notificationTypeFor; private createDelegationId; private createRecord; private errorResult; /** * S5b fix: synthesize an `EnrichedSessionEvent` and invoke the tmux * adapter's `onSessionCreated` directly. This mirrors the * `onChildSessionCreated` fallback for session-tracker at * `coordinator.ts:220` and closes the panel-spawn gap documented in * `.planning/debug/s5-panel-spawn-root-cause-2026-06-04.md`. * * Idempotency: the underlying `SessionManager.onSessionCreated` has * `sessions` and `spawningSessions` guards (see session-manager.ts:223-231) * that return early on duplicate calls. If the SDK also fires * `session.created` and the tmuxObserver path runs, this fallback * becomes a no-op. * * Errors are logged via the client.app log sink and swallowed * (D-04 silent-fallback). The session keeps running even if pane * spawn fails — visibility is degraded but not lost. */ private spawnTmuxPanelForChild; } //# sourceMappingURL=coordinator.d.ts.map