diff --git a/extensions/cloudflare-ai-gateway/api.ts b/extensions/cloudflare-ai-gateway/api.ts index efa260997320..cbd2d412b7f1 100644 --- a/extensions/cloudflare-ai-gateway/api.ts +++ b/extensions/cloudflare-ai-gateway/api.ts @@ -1,3 +1,7 @@ +/** + * Public Cloudflare AI Gateway provider helpers shared by onboarding, catalog, + * and tests. + */ export { buildCloudflareAiGatewayModelDefinition, CLOUDFLARE_AI_GATEWAY_DEFAULT_MODEL_ID, diff --git a/extensions/cloudflare-ai-gateway/catalog-provider.ts b/extensions/cloudflare-ai-gateway/catalog-provider.ts index bbb3f3ec7f84..5f05774b02c0 100644 --- a/extensions/cloudflare-ai-gateway/catalog-provider.ts +++ b/extensions/cloudflare-ai-gateway/catalog-provider.ts @@ -1,3 +1,7 @@ +/** + * Builds runtime model catalog entries from stored Cloudflare AI Gateway auth + * profiles. + */ import { coerceSecretRef, resolveNonEnvSecretRefApiKeyMarker, @@ -46,6 +50,10 @@ function resolveCloudflareAiGatewayMetadata(cred: CloudflareAiGatewayCredential) }; } +/** + * Returns a provider catalog entry when credentials and Gateway metadata are + * complete enough to construct an Anthropic-compatible base URL. + */ export function buildCloudflareAiGatewayCatalogProvider(params: { credential: CloudflareAiGatewayCredential; envApiKey?: string; diff --git a/extensions/cloudflare-ai-gateway/index.ts b/extensions/cloudflare-ai-gateway/index.ts index 8849745579d1..1ffa444a8c2d 100644 --- a/extensions/cloudflare-ai-gateway/index.ts +++ b/extensions/cloudflare-ai-gateway/index.ts @@ -1,3 +1,7 @@ +/** + * Bundled provider plugin entry for Cloudflare AI Gateway setup, catalog + * discovery, failover classification, and stream wrapping. + */ import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry"; import { applyAuthProfileConfig, @@ -96,6 +100,8 @@ export default definePluginEntry({ let capturedSecretInput: Parameters[1] = ""; let capturedCredential = false; let capturedMode: "plaintext" | "ref" | undefined; + // Capture through the shared provider auth helper so plaintext, + // env refs, and secret refs keep the same validation path. await ensureApiKeyFromOptionEnvOrPrompt({ token: normalizeOptionalSecretInput(ctx.opts?.cloudflareAiGatewayApiKey), tokenProvider: "cloudflare-ai-gateway", @@ -178,6 +184,8 @@ export default definePluginEntry({ return null; } if (resolved.source !== "profile") { + // Persist newly supplied credentials with Gateway metadata; a + // profile-sourced key already owns its existing auth-store record. const credential = ctx.toApiKeyCredential({ provider: PROVIDER_ID, resolved, diff --git a/extensions/cloudflare-ai-gateway/models.ts b/extensions/cloudflare-ai-gateway/models.ts index f49b57ff3ff7..e2bde3793b15 100644 --- a/extensions/cloudflare-ai-gateway/models.ts +++ b/extensions/cloudflare-ai-gateway/models.ts @@ -1,7 +1,14 @@ +/** + * Model ids, default model metadata, and URL construction for the Cloudflare AI + * Gateway provider. + */ import type { ModelDefinitionConfig } from "openclaw/plugin-sdk/provider-model-shared"; +/** Provider id used in model refs and auth profiles. */ export const CLOUDFLARE_AI_GATEWAY_PROVIDER_ID = "cloudflare-ai-gateway"; +/** Default Cloudflare AI Gateway model id exposed by the bundled provider. */ export const CLOUDFLARE_AI_GATEWAY_DEFAULT_MODEL_ID = "claude-sonnet-4-6"; +/** Fully-qualified default model ref used by onboarding. */ export const CLOUDFLARE_AI_GATEWAY_DEFAULT_MODEL_REF = `${CLOUDFLARE_AI_GATEWAY_PROVIDER_ID}/${CLOUDFLARE_AI_GATEWAY_DEFAULT_MODEL_ID}`; const CLOUDFLARE_AI_GATEWAY_DEFAULT_CONTEXT_WINDOW = 200_000; @@ -13,6 +20,10 @@ const CLOUDFLARE_AI_GATEWAY_DEFAULT_COST = { cacheWrite: 3.75, }; +/** + * Builds a provider model definition, allowing tests/catalog code to override + * the model id while preserving Cloudflare defaults. + */ export function buildCloudflareAiGatewayModelDefinition(params?: { id?: string; name?: string; @@ -31,6 +42,10 @@ export function buildCloudflareAiGatewayModelDefinition(params?: { }; } +/** + * Constructs the Anthropic Messages base URL for a Cloudflare account/gateway + * pair, returning an empty string for incomplete metadata. + */ export function resolveCloudflareAiGatewayBaseUrl(params: { accountId: string; gatewayId: string; diff --git a/extensions/cloudflare-ai-gateway/onboard.ts b/extensions/cloudflare-ai-gateway/onboard.ts index 1cdee4325120..cbaf4618af43 100644 --- a/extensions/cloudflare-ai-gateway/onboard.ts +++ b/extensions/cloudflare-ai-gateway/onboard.ts @@ -1,3 +1,7 @@ +/** + * Config patch helpers used by Cloudflare AI Gateway interactive and + * non-interactive onboarding flows. + */ import { applyAgentDefaultModelPrimary, applyProviderConfigWithDefaultModel, @@ -9,6 +13,9 @@ import { resolveCloudflareAiGatewayBaseUrl, } from "./models.js"; +/** + * Builds the minimal config patch for provider setup and default model aliasing. + */ export function buildCloudflareAiGatewayConfigPatch(params: { accountId: string; gatewayId: string; @@ -36,6 +43,9 @@ export function buildCloudflareAiGatewayConfigPatch(params: { }; } +/** + * Applies provider model config while preserving existing agent model aliases. + */ export function applyCloudflareAiGatewayProviderConfig( cfg: OpenClawConfig, params?: { accountId?: string; gatewayId?: string }, @@ -80,6 +90,9 @@ export function applyCloudflareAiGatewayProviderConfig( }); } +/** + * Applies Cloudflare AI Gateway config and makes its default model primary. + */ export function applyCloudflareAiGatewayConfig( cfg: OpenClawConfig, params?: { accountId?: string; gatewayId?: string }, diff --git a/extensions/cloudflare-ai-gateway/stream-wrappers.ts b/extensions/cloudflare-ai-gateway/stream-wrappers.ts index 8025adc4a04d..040d3537c13a 100644 --- a/extensions/cloudflare-ai-gateway/stream-wrappers.ts +++ b/extensions/cloudflare-ai-gateway/stream-wrappers.ts @@ -1,3 +1,7 @@ +/** + * Stream wrapper for Cloudflare AI Gateway's Anthropic Messages compatibility + * quirks. + */ import type { StreamFn } from "openclaw/plugin-sdk/agent-core"; import type { ProviderWrapStreamFnContext } from "openclaw/plugin-sdk/plugin-entry"; import { createAnthropicThinkingPrefillPayloadWrapper } from "openclaw/plugin-sdk/provider-stream-shared"; @@ -9,6 +13,10 @@ function shouldPatchAnthropicMessagesPayload(model: ProviderWrapStreamFnContext[ return model?.api === undefined || model.api === "anthropic-messages"; } +/** + * Creates a wrapper that removes trailing assistant prefill messages before + * extended-thinking Anthropic requests are sent through Cloudflare. + */ export function createCloudflareAiGatewayAnthropicThinkingPrefillWrapper( baseStreamFn: StreamFn | undefined, ): StreamFn { @@ -19,6 +27,9 @@ export function createCloudflareAiGatewayAnthropicThinkingPrefillWrapper( }); } +/** + * Applies the Anthropic payload wrapper only for Anthropic-compatible models. + */ export function wrapCloudflareAiGatewayProviderStream( ctx: ProviderWrapStreamFnContext, ): StreamFn | undefined { @@ -28,5 +39,6 @@ export function wrapCloudflareAiGatewayProviderStream( return createCloudflareAiGatewayAnthropicThinkingPrefillWrapper(ctx.streamFn); } +/** Test-only access to wrapper decisions and logger injection points. */ export const testing = { log, shouldPatchAnthropicMessagesPayload }; export { testing as __testing }; diff --git a/extensions/codex-supervisor/index.ts b/extensions/codex-supervisor/index.ts index 88e86d6e4dc3..b08669d44ab0 100644 --- a/extensions/codex-supervisor/index.ts +++ b/extensions/codex-supervisor/index.ts @@ -1,3 +1,7 @@ +/** + * Bundled plugin entry that exposes Codex app-server supervisor tools to + * OpenClaw agents. + */ import { buildJsonPluginConfigSchema, definePluginEntry } from "openclaw/plugin-sdk/plugin-entry"; import { CodexSupervisorPluginConfigSchema, diff --git a/extensions/codex-supervisor/src/api.ts b/extensions/codex-supervisor/src/api.ts index a7425b4f025f..99794d36a728 100644 --- a/extensions/codex-supervisor/src/api.ts +++ b/extensions/codex-supervisor/src/api.ts @@ -1,3 +1,7 @@ +/** + * Public Codex Supervisor API barrel for plugin tools, MCP serving, config, and + * session types. + */ export { CodexSupervisorPluginConfigSchema, loadCodexSupervisorEndpoints, diff --git a/extensions/codex-supervisor/src/config.ts b/extensions/codex-supervisor/src/config.ts index 51b9c82919c9..06fc0ec13176 100644 --- a/extensions/codex-supervisor/src/config.ts +++ b/extensions/codex-supervisor/src/config.ts @@ -1,3 +1,6 @@ +/** + * Config parsing for Codex Supervisor endpoints and safety gates. + */ import { Type, type Static } from "typebox"; import type { CodexSupervisorEndpoint } from "./types.js"; @@ -26,6 +29,9 @@ const WebSocketEndpointSchema = Type.Object( { additionalProperties: false }, ); +/** + * Plugin config schema accepted by the bundled plugin manifest. + */ export const CodexSupervisorPluginConfigSchema = Type.Object( { endpoints: Type.Optional( @@ -37,8 +43,10 @@ export const CodexSupervisorPluginConfigSchema = Type.Object( { additionalProperties: false }, ); +/** Raw plugin config shape accepted from OpenClaw config. */ export type CodexSupervisorPluginConfig = Static; +/** Normalized config consumed by plugin registration and MCP serving. */ export type ResolvedCodexSupervisorPluginConfig = { endpoints: CodexSupervisorEndpoint[]; allowRawTranscripts: boolean; @@ -140,6 +148,10 @@ function endpointFromToken(token: string, index: number): CodexSupervisorEndpoin return undefined; } +/** + * Loads endpoint definitions from environment, defaulting to the local Codex + * app-server unix socket. + */ export function loadCodexSupervisorEndpoints( env: Pick = process.env, ): CodexSupervisorEndpoint[] { @@ -185,6 +197,9 @@ function normalizeConfiguredEndpoints( return normalized.length > 0 ? requireUniqueEndpointIds(normalized) : undefined; } +/** + * Resolves raw plugin config and env endpoints into validated runtime config. + */ export function resolveCodexSupervisorPluginConfig( rawConfig: unknown, env: Pick = process.env, diff --git a/extensions/codex-supervisor/src/json-rpc-client.ts b/extensions/codex-supervisor/src/json-rpc-client.ts index 2b1fc3398e7e..1b3ef284a0ca 100644 --- a/extensions/codex-supervisor/src/json-rpc-client.ts +++ b/extensions/codex-supervisor/src/json-rpc-client.ts @@ -1,3 +1,7 @@ +/** + * JSON-RPC transports for Codex app-server connections over stdio proxies or + * websocket/unix-socket endpoints. + */ import { spawn, type ChildProcessWithoutNullStreams } from "node:child_process"; import { randomUUID } from "node:crypto"; import * as net from "node:net"; @@ -28,6 +32,10 @@ function formatMalformedMessageError(error: unknown): Error { return new Error(`Malformed Codex app-server message: ${detail}`); } +/** + * Produces denial responses for app-server approval requests the supervisor + * deliberately cannot grant. + */ export function resolveSafeApprovalResult(method: string): Record | undefined { if (method === "item/tool/call") { return { @@ -121,6 +129,8 @@ abstract class BaseCodexJsonRpcConnection implements CodexJsonRpcConnection { const method = typeof message.method === "string" ? message.method : undefined; if (id !== undefined && method) { const result = resolveSafeApprovalResult(method); + // The supervisor is read/steer tooling, not a native approval delegate; + // unknown app-server requests fail closed with either a denial or -32601. this.sendRaw( JSON.stringify( result === undefined @@ -339,6 +349,10 @@ class WebSocketCodexJsonRpcConnection extends BaseCodexJsonRpcConnection { } } +/** + * Opens, initializes, and returns a JSON-RPC connection for one supervisor + * endpoint. + */ export async function connectCodexAppServerEndpoint( endpoint: CodexSupervisorEndpoint, ): Promise { diff --git a/extensions/codex-supervisor/src/mcp-server.ts b/extensions/codex-supervisor/src/mcp-server.ts index f2689907f5ec..2c570889fd59 100644 --- a/extensions/codex-supervisor/src/mcp-server.ts +++ b/extensions/codex-supervisor/src/mcp-server.ts @@ -1,3 +1,7 @@ +/** + * Standalone MCP stdio server for exposing Codex Supervisor tools to trusted + * MCP clients. + */ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { loadCodexSupervisorEndpoints } from "./config.js"; @@ -18,11 +22,15 @@ function routeLogsToStderr(): void { } } +/** Options for creating or serving a Codex Supervisor MCP server. */ export type CodexSupervisorMcpServeOptions = { supervisor?: CodexSupervisor; toolOptions?: CodexSupervisorMcpToolOptions; }; +/** + * Creates an MCP server and owns the supervisor instance unless one is supplied. + */ export function createCodexSupervisorMcpServer(opts: CodexSupervisorMcpServeOptions = {}): { server: McpServer; supervisor: CodexSupervisor; @@ -41,6 +49,10 @@ export function createCodexSupervisorMcpServer(opts: CodexSupervisorMcpServeOpti }; } +/** + * Serves Codex Supervisor tools over MCP stdio until transport or process + * shutdown. + */ export async function serveCodexSupervisorMcp( opts: CodexSupervisorMcpServeOptions = {}, ): Promise { @@ -63,6 +75,8 @@ export async function serveCodexSupervisorMcp( process.stdin.off("close", shutdown); process.off("SIGINT", shutdown); process.off("SIGTERM", shutdown); + // The SDK exposes this callback slot but not a stable setter; clear it so + // close() cannot recursively re-enter shutdown. transport["onclose"] = undefined; close().then(resolveClosed, resolveClosed); }; diff --git a/extensions/codex-supervisor/src/mcp-tools.ts b/extensions/codex-supervisor/src/mcp-tools.ts index 5613cf4236b2..7e1ec4130f39 100644 --- a/extensions/codex-supervisor/src/mcp-tools.ts +++ b/extensions/codex-supervisor/src/mcp-tools.ts @@ -1,3 +1,7 @@ +/** + * MCP tool registration plus redaction helpers for Codex Supervisor sessions + * and endpoint metadata. + */ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { z } from "zod"; import type { CodexSupervisor } from "./supervisor.js"; @@ -7,9 +11,12 @@ import type { CodexSupervisorSessionListResult, } from "./types.js"; +/** Env gate for exposing transcript-derived fields through standalone MCP. */ export const RAW_TRANSCRIPTS_ENV = "OPENCLAW_CODEX_SUPERVISOR_ALLOW_RAW_TRANSCRIPTS"; +/** Env gate for mutating/steering Codex sessions through standalone MCP. */ export const WRITE_CONTROLS_ENV = "OPENCLAW_CODEX_SUPERVISOR_ALLOW_WRITE_CONTROLS"; +/** Optional policy callbacks for standalone MCP tool exposure. */ export type CodexSupervisorMcpToolOptions = { rawTranscriptReadsAllowed?: () => boolean; writeControlsAllowed?: () => boolean; @@ -36,6 +43,10 @@ function redactString(value: string): string { .replace(/\bBearer\s+[-._~+/a-zA-Z0-9]+=*/g, "Bearer [redacted]"); } +/** + * Redacts common secret-bearing fields and token-like substrings before tool + * results leave the supervisor. + */ export function redactCodexSupervisorValue(value: unknown, key = ""): unknown { if (typeof value === "string") { if (/authorization|password|secret|token|api[-_]?key/i.test(key)) { @@ -74,6 +85,7 @@ function redactEndpointUrl(value: string): string { } } +/** Returns endpoint metadata safe for tool results. */ export function redactCodexSupervisorEndpoint( endpoint: CodexSupervisorEndpoint, ): Record { @@ -115,6 +127,10 @@ function sanitizeSessionForMcp( return sanitized; } +/** + * Sanitizes session-list output, optionally including transcript-derived + * preview/name fields only when the caller has opted in. + */ export function sanitizeCodexSupervisorSessionListResult( result: CodexSupervisorSessionListResult, includeTranscriptDerivedFields = rawTranscriptReadsAllowed(), @@ -129,6 +145,10 @@ export function sanitizeCodexSupervisorSessionListResult( }; } +/** + * Registers MCP tools for endpoint probing, session listing, reads, sends, and + * interrupts. + */ export function registerCodexSupervisorMcpTools( server: McpServer, supervisor: CodexSupervisor, diff --git a/extensions/codex-supervisor/src/plugin-tools.ts b/extensions/codex-supervisor/src/plugin-tools.ts index 059bb76a3d71..83ea18fc011b 100644 --- a/extensions/codex-supervisor/src/plugin-tools.ts +++ b/extensions/codex-supervisor/src/plugin-tools.ts @@ -1,3 +1,7 @@ +/** + * OpenClaw agent-tool definitions for Codex Supervisor endpoint and session + * controls. + */ import { jsonResult, readStringParam, type AnyAgentTool } from "openclaw/plugin-sdk/core"; import { Type } from "typebox"; import { @@ -48,11 +52,13 @@ const SessionInterruptParamsSchema = Type.Object( { additionalProperties: false }, ); +/** Policy flags controlling transcript reads and write operations. */ export type CodexSupervisorToolPolicy = { allowRawTranscripts: boolean; allowWriteControls: boolean; }; +/** Dependencies needed to build OpenClaw agent tools. */ export type CodexSupervisorToolOptions = { supervisor: CodexSupervisor; policy: CodexSupervisorToolPolicy; @@ -105,6 +111,10 @@ function requireWriteAccess(policy: CodexSupervisorToolPolicy): void { } } +/** + * Creates the OpenClaw tools that expose Codex endpoint health and session + * controls. + */ export function createCodexSupervisorTools({ supervisor, policy, @@ -151,6 +161,8 @@ export function createCodexSupervisorTools({ description: "Read one Codex session transcript from app-server.", parameters: SessionReadParamsSchema, execute: async (_toolCallId, rawParams) => { + // Raw transcript access is opt-in because app-server sessions can hold + // secrets, private files, and user-authenticated browser context. requireRawTranscriptAccess(policy); const params = asRecord(rawParams); const threadId = readStringParam(params, "thread_id", { required: true }); @@ -172,6 +184,8 @@ export function createCodexSupervisorTools({ "Send text to a Codex session. Idle sessions start a turn; active sessions are steered.", parameters: SessionSendParamsSchema, execute: async (_toolCallId, rawParams) => { + // Session write controls can steer or interrupt a human-visible Codex + // turn, so they remain behind an explicit plugin policy gate. requireWriteAccess(policy); const params = asRecord(rawParams); const result = await supervisor.sendToSession({ diff --git a/extensions/codex-supervisor/src/supervisor.ts b/extensions/codex-supervisor/src/supervisor.ts index cfca44cf7829..8b26bbc1d568 100644 --- a/extensions/codex-supervisor/src/supervisor.ts +++ b/extensions/codex-supervisor/src/supervisor.ts @@ -1,3 +1,7 @@ +/** + * Codex app-server supervisor that lists sessions, reads transcripts, and + * starts/steers/interrupts turns across configured endpoints. + */ import { connectCodexAppServerEndpoint } from "./json-rpc-client.js"; import type { CodexJsonRpcConnection, @@ -109,6 +113,7 @@ function isLoadedThreadReadMiss(error: unknown): boolean { return message.includes("thread not found") || message.includes("thread not loaded"); } +/** High-level supervisor facade used by OpenClaw tools and MCP tools. */ export class CodexSupervisor { private readonly connections = new Map>(); @@ -117,10 +122,12 @@ export class CodexSupervisor { private readonly connector: EndpointConnector = connectCodexAppServerEndpoint, ) {} + /** Returns configured endpoint definitions without opening connections. */ listEndpoints(): CodexSupervisorEndpoint[] { return this.endpoints; } + /** Closes all open app-server connections owned by this supervisor. */ async close(): Promise { const settled = await Promise.allSettled(this.connections.values()); this.connections.clear(); @@ -133,6 +140,7 @@ export class CodexSupervisor { ); } + /** Checks whether each endpoint can service a lightweight thread list call. */ async probeEndpoints(): Promise { return await Promise.all( this.endpoints.map(async (endpoint) => { @@ -152,12 +160,14 @@ export class CodexSupervisor { ); } + /** Lists sessions, returning only the session array for agent-tool callers. */ async listSessions( params: { includeStored?: boolean; maxStoredSessions?: number } = {}, ): Promise { return (await this.listSessionSnapshot(params)).sessions; } + /** Lists sessions plus endpoint errors for structured tool output. */ async listSessionSnapshot( params: { includeStored?: boolean; maxStoredSessions?: number } = {}, ): Promise { @@ -178,6 +188,7 @@ export class CodexSupervisor { return { sessions, errors }; } + /** Reads a single Codex session transcript from the resolved endpoint. */ async readSession(params: { endpointId?: string; threadId: string; @@ -201,6 +212,7 @@ export class CodexSupervisor { } } + /** Starts a new turn or steers an active turn depending on requested mode. */ async sendToSession(params: { endpointId?: string; threadId: string; @@ -224,6 +236,8 @@ export class CodexSupervisor { if (mode === "steer" || status === "active") { const detailed = await this.readThread(connection, params.threadId, true); const detailedThread = extractThread(detailed); + // Active-turn ids may appear in full thread turns or the summary API; + // try both before failing so steering handles materialized and lazy turns. const turnId = (detailedThread ? findInProgressTurnId(detailedThread) : undefined) ?? findInProgressTurnId(thread) ?? @@ -247,6 +261,7 @@ export class CodexSupervisor { } } + /** Interrupts an active Codex turn, resolving the turn id when omitted. */ async interruptSession(params: { endpointId?: string; threadId: string; @@ -285,6 +300,8 @@ export class CodexSupervisor { endpoint, params.maxStoredSessions, )) { + // Loaded sessions are authoritative for attachment/status; append stored + // history only for threads that are not already live. if (!sessions.some((session) => session.threadId === stored.threadId)) { sessions.push(stored); } diff --git a/extensions/codex-supervisor/src/types.ts b/extensions/codex-supervisor/src/types.ts index 9594920b49cc..35d1c364a3ae 100644 --- a/extensions/codex-supervisor/src/types.ts +++ b/extensions/codex-supervisor/src/types.ts @@ -1,3 +1,7 @@ +/** + * Public Codex Supervisor endpoint, session, and JSON-RPC connection types. + */ +/** Configured transport target for a Codex app-server endpoint. */ export type CodexSupervisorEndpoint = | { id: string; @@ -15,10 +19,13 @@ export type CodexSupervisorEndpoint = authTokenEnv?: string; }; +/** Send behavior requested by supervisor write tools. */ export type CodexSupervisorTurnMode = "auto" | "start" | "steer"; +/** App-server thread status string, preserved for forward compatibility. */ export type CodexSupervisorThreadStatus = string; +/** Normalized session summary returned by supervisor list operations. */ export type CodexSupervisorSession = { endpointId: string; threadId: string; @@ -32,6 +39,7 @@ export type CodexSupervisorSession = { humanAttached?: boolean; }; +/** Result returned after starting or steering a Codex turn. */ export type CodexSupervisorSendResult = { endpointId: string; threadId: string; @@ -40,18 +48,21 @@ export type CodexSupervisorSendResult = { status?: string; }; +/** Minimal JSON-RPC connection contract used by the supervisor. */ export type CodexJsonRpcConnection = { request(method: string, params?: Record): Promise; notify(method: string, params?: Record): void; close(): Promise; }; +/** Health result for one configured supervisor endpoint. */ export type CodexSupervisorEndpointHealth = { endpointId: string; ok: boolean; detail?: string; }; +/** Session list plus endpoint errors for tool-friendly structured output. */ export type CodexSupervisorSessionListResult = { sessions: CodexSupervisorSession[]; errors: CodexSupervisorEndpointHealth[];