import type { CompletionDetector } from "../completion/detector.js"; import type { PtyManager } from "../../features/background-command/pty/pty-manager.js"; import type { OpenCodeClient } from "../../shared/session-api.js"; import type { CommandDelegationParams, RuntimePolicy } from "../../shared/types.js"; import type { DelegateParams } from "../spawner/spawn-request-builder.js"; import type { DelegationCoordinator, DispatchParams } from "./coordinator.js"; import { DelegationManager as RuntimeDelegationManager } from "./manager-runtime.js"; import type { DelegationMonitor } from "./monitor.js"; import type { NotificationRouter } from "./notification-router.js"; import type { DelegationStateMachine } from "./state-machine.js"; import type { Delegation, DelegationResult } from "./types.js"; import type { DelegationPool } from "./pool-types.js"; import type { PersistedSession } from "../../features/tmux/persistence.js"; import type { ToolDelegation } from "../../features/session-tracker/tool-delegation.js"; type NativeTask = (params: { agent: string; prompt: string; disabledTools: string[]; }) => Promise; type FacadeLifecycle = { getChildSessionId: (delegationId: string) => string | undefined; getStatus: (delegationId: string) => Delegation | undefined; list: () => Delegation[]; markAborted: (delegationId: string) => DelegationResult; markCancelled: (delegationId: string) => DelegationResult; register?: (record: Delegation) => void; }; export type DelegationManagerOptions = { coordinator?: Pick & Partial>; lifecycle?: FacadeLifecycle; monitor?: Pick; notificationRouter?: Pick; ptyManager?: PtyManager | null; runtimePolicy?: RuntimePolicy; sendPromptAsync?: (sessionId: string, prompt: string) => Promise; stateMachine?: DelegationStateMachine; /** * P58 (G3, REQ-58-03, D-58-06/07/08): Optional sub-type exposing the * persistence + pane-rehydration surface needed by abort+resume. Narrow * type (only the methods we call) — keep the dependency surface small. * Existing callers that don't inject `sessionManager` see the G3 wiring * as a no-op (the `?.` short-circuits). */ sessionManager?: { persist: (record: PersistedSession) => Promise; respawnIfKnown: (sessionId: string) => Promise<{ paneId: string; } | null>; /** * P58.8 S1 (REQ-58-07): start the capture-pane polling loop. Optional * because not every consumer of DelegationManager has a tmux integration * wired in (e.g. headless test fixtures). When undefined, dispatch * skips the polling-start call (the `?.` short-circuits). */ startPolling?: (intervalMs?: number) => void; }; /** * P58 (G6, REQ-58-06, D-58-14): Optional ToolDelegation reference for * emitting `delegation-terminal` events. Narrow Pick<>-typed — only the * `recordDelegationTerminal` method is needed. Existing callers that * don't inject `toolDelegation` see the G6 wiring as a no-op. */ toolDelegation?: Pick; }; export type DelegationControlRequest = { action: "abort" | "cancel" | "restart" | "resume" | "chain" | "adjust-prompt" | "change-agent"; chainParentSessionId?: string; delegationId: string; nativeTask?: NativeTask; restartPrompt?: string; agent?: string; }; /** * Thin public facade for delegation operations. * * The facade keeps the historical `DelegationManager` import stable while the * heavy runtime implementation lives in `manager-runtime.ts`. Tests and newer * callers can inject the coordinator/lifecycle modules directly; legacy plugin * wiring still falls back to the runtime adapter until the remaining command and * SDK paths are migrated behind the v2 coordinator. */ export declare class DelegationManager { private readonly options; private readonly runtime?; /** * P58 PLAN-07 (Gap 2 fix): Optional test-only override map. When set by * `createForTest()`, the `__getDelegationsForTesting` getter returns this * map instead of falling back to a new empty Map. The same map is also * the source of truth for the injected noop `lifecycle.list()` so that * `getPoolSnapshot()` observes entries added via the test seam. */ private readonly __testPoolMap?; constructor(client?: OpenCodeClient, options?: DelegationManagerOptions, testPoolMap?: Map); /** * P58 PLAN-07 (Gap 2 fix): Static factory that constructs a no-arg * `DelegationManager` suitable for BATS / unit tests. Returns a manager * whose `runtime` is undefined (no SDK client) and whose `options` carry * a noop `coordinator` and a noop `lifecycle` that share a single * in-memory map (the `__testPoolMap`). * * The resulting instance supports: * - `getPoolSnapshot()` — returns a frozen pool reflecting the entries * added to the test map via `__getDelegationsForTesting` * - `__getDelegationsForTesting` — returns the writable test map so * BATS tests can populate it via `Map.set()` * - `__getDelegationsForTesting` mutations are observed by * `getPoolSnapshot()` because both read from the same `__testPoolMap` * * BATS tests should: * 1. Call `const instance = DelegationManager.createForTest()` * 2. Populate `instance.__getDelegationsForTesting` via `Map.set()` * 3. Call `instance.getPoolSnapshot()` to assert the frozen contract * * NOT for production code — only for BATS slots 62 and similar in-memory * tests. Real wiring still requires `new DelegationManager(client)`. */ static createForTest(): DelegationManager; /** Wires the lifecycle-owned completion detector into the legacy runtime adapter. */ setCompletionDetector(detector: CompletionDetector): void; /** Preserve the historical SDK dispatch API. */ dispatch(params: DelegateParams): Promise; /** Attach the real native Task child session ID to a prepared v2 delegation. */ attachChildSession(delegationId: string, childSessionId: string): void; /** Roll back a prepared v2 delegation after native Task dispatch fails. */ failDispatch(delegationId: string, caughtError: unknown): void; /** Compatibility alias for callers that use the Plan 04 facade name. */ dispatchDelegation(_client: OpenCodeClient | undefined, params: DispatchParams): Promise; /** Preserve command delegation until it is migrated to the coordinator lane. */ dispatchCommand(params: CommandDelegationParams): Promise; /** Forward session-idle events to the runtime adapter. */ handleSessionIdle(sessionId: string): void; /** Forward session-error events to the runtime adapter and v2 coordinator. */ handleSessionError(sessionId: string, error?: unknown): void; /** Forward session-deleted events to the runtime adapter. */ handleSessionDeleted(sessionId: string): void; /** Forward child message observations to the v2 coordinator execution collector. */ recordChildMessageSignal(sessionId: string, finalMessageExcerpt?: string): void; /** Forward child tool observations to the v2 coordinator execution collector. */ recordChildToolSignal(sessionId: string): void; /** Recover pending delegations through the runtime adapter. */ recoverPending(): Promise; /** Read a single delegation from the injected lifecycle or runtime adapter. */ getStatus(delegationId: string): Delegation | undefined; /** List delegations, optionally filtered by parent session. */ listDelegations(sessionId?: string): Delegation[]; /** * P58 (G2, REQ-58-02, D-58-04): Returns a frozen, JSON-serializable snapshot * of every delegation known to the in-memory map. The snapshot is a pure * read of runtime state — no mutation, no async I/O. Used by tmux-copilot, * SC-01 SSE pool, and SC-04/05 dashboards. * * @returns A deep-frozen DelegationPool with `schemaVersion: 1` (numeric * literal per D-53-13) and `promptPreview` sanitized to <= 200 chars * single-line per the frozen contract documented in pool-types.ts. */ getPoolSnapshot(): DelegationPool; /** Historical name retained for existing status tool callers. */ getAllDelegations(): Delegation[]; /** Mark a delegation aborted via the lifecycle module. */ abortDelegation(delegationId: string): DelegationResult; /** Mark a delegation cancelled via the lifecycle module. */ cancelDelegation(delegationId: string): DelegationResult; /** * Applies control semantics with two dispatch paths: * * 1. **sendPromptAsync path** (resume, chain, adjust-prompt, change-agent): * Reuses the existing childSessionId to continue a session without creating a * new child session. Requires `options.sendPromptAsync` to be configured. * * 2. **abort+dispatch path** (restart, legacy resume/chain fallback): * Aborts the current delegation and dispatches a new one via coordinator.dispatch. * This creates a new childSessionId. * * Direct terminal actions (abort, cancel) are handled immediately without dispatch. */ controlDelegation(request: DelegationControlRequest): Promise; /** Return the child session id for a delegation when known. */ getChildSessionId(delegationId: string): string | undefined; canSessionAccessDelegation(callerSessionId: string | undefined, delegation: Delegation | undefined): boolean; getVisibleDelegationsForSession(callerSessionId: string): Delegation[]; getDelegationForPtySession(ptySessionId: string): Delegation | undefined; markCommandCancellationForPtySession(ptySessionId: string): DelegationResult | undefined; pruneCompletedDelegations(maxAgeMs?: number): number; applyBehavioralGuardrail(level: Parameters[0]): number | undefined; get stabilityTimers(): Map; get delegations(): Map; /** * P58 (G2, REQ-58-02, D-58-03): Read-only test seam exposing the in-memory * delegation map. **TEST-ONLY:** do not call from production code; for * BATS test fixtures only. Returns a `ReadonlyMap` view — consumers MUST * NOT cast away the readonly modifier to mutate state. */ get __getDelegationsForTesting(): ReadonlyMap; get delegationsBySession(): Map; get safetyTimers(): Map; get semaphore(): { acquire: (...args: unknown[]) => Promise<() => void>; }; private toDispatchParams; private terminalFallback; private extractNativeTaskSessionId; private requireRuntime; } export {}; //# sourceMappingURL=manager.d.ts.map