@wrongstack/mcp 0.295.0 → 0.295.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/authorization.ts", "../src/authorization-manager.ts", "../src/client.ts", "../src/constants.ts", "../src/protocol.ts", "../src/tool-schema.ts", "../src/transport-jsonrpc.ts", "../src/sse-reader.ts", "../src/transport-base.ts", "../src/transport-security.ts", "../src/transport-sse.ts", "../src/transport-streamable.ts", "../src/content-selection.ts", "../src/manage.ts", "../src/manifest-cache.ts", "../src/operations.ts", "../src/registry.ts", "../src/wrap-tool.ts", "../src/server.ts", "../src/token-store.ts"],
4
- "sourcesContent": ["import { createHash, randomBytes, timingSafeEqual } from 'node:crypto';\nimport * as dns from 'node:dns/promises';\nimport * as http from 'node:http';\nimport * as https from 'node:https';\nimport * as net from 'node:net';\nimport { isPrivateIPv4, isPrivateIPv6 } from '@wrongstack/core/utils';\n\nexport interface MCPAccessToken {\n accessToken: string;\n tokenType?: string | undefined;\n /** Exact canonical MCP resource URI this token was minted for. */\n resource: string;\n expiresAt?: number | undefined;\n scopes?: string[] | undefined;\n}\n\nexport interface MCPAuthorizationContext {\n serverName: string;\n resource: string;\n signal?: AbortSignal | undefined;\n}\n\nexport interface MCPAuthorizationChallenge {\n status: 401;\n resource: string;\n resourceMetadataUrl?: string | undefined;\n scopes: string[];\n rawScheme: 'Bearer';\n}\n\nexport interface MCPProtectedResourceMetadata {\n resource: string;\n authorizationServers: string[];\n scopesSupported: string[];\n}\n\nexport interface MCPAuthorizationServerMetadata {\n issuer: string;\n authorizationEndpoint: string;\n tokenEndpoint: string;\n registrationEndpoint?: string | undefined;\n scopesSupported: string[];\n}\n\nexport interface MCPAuthorizationDiscoveryResult {\n resourceMetadataUrl: string;\n authorizationServerMetadataUrl: string;\n protectedResource: MCPProtectedResourceMetadata;\n authorizationServer: MCPAuthorizationServerMetadata;\n}\n\nexport type MCPAuthorizationJsonFetcher = (\n url: string,\n signal?: AbortSignal | undefined,\n) => Promise<unknown | undefined>;\n\nexport interface MCPAuthorizationDiscoveryOptions {\n challengeHeader?: string | null | undefined;\n signal?: AbortSignal | undefined;\n timeoutMs?: number | undefined;\n maxResponseBytes?: number | undefined;\n lookup?: BrowserCompatibleDnsLookup | undefined;\n /** Test/host override. Production callers should use the pinned default. */\n fetchJson?: MCPAuthorizationJsonFetcher | undefined;\n}\n\nexport interface MCPAuthorizationSession {\n authorizationUrl: string;\n state: string;\n codeVerifier: string;\n redirectUri: string;\n clientId: string;\n resource: string;\n}\n\nexport interface MCPTokenSet extends MCPAccessToken {\n refreshToken?: string | undefined;\n}\n\nexport interface MCPAuthorizationRequestOptions {\n authorizationServer: MCPAuthorizationServerMetadata;\n clientId: string;\n redirectUri: string;\n resource: string;\n scopes?: readonly string[] | undefined;\n}\n\nexport interface MCPTokenExchangeOptions {\n authorizationServer: MCPAuthorizationServerMetadata;\n clientId: string;\n redirectUri: string;\n resource: string;\n code: string;\n codeVerifier: string;\n signal?: AbortSignal | undefined;\n timeoutMs?: number | undefined;\n maxResponseBytes?: number | undefined;\n lookup?: BrowserCompatibleDnsLookup | undefined;\n}\n\nexport interface MCPTokenRefreshOptions {\n authorizationServer: MCPAuthorizationServerMetadata;\n clientId: string;\n resource: string;\n refreshToken: string;\n signal?: AbortSignal | undefined;\n timeoutMs?: number | undefined;\n maxResponseBytes?: number | undefined;\n lookup?: BrowserCompatibleDnsLookup | undefined;\n}\n\ntype BrowserCompatibleDnsLookup = (\n hostname: string,\n) => Promise<readonly { address: string; family: number }[]>;\n\n/**\n * Host-owned bridge to vault-backed OAuth state. The MCP package never stores\n * access or refresh tokens itself and never exposes them through config.\n */\nexport interface MCPAuthorizationProvider {\n getAccessToken(context: MCPAuthorizationContext): Promise<MCPAccessToken | undefined>;\n /** Refresh/discover/reauthorize. Return true to retry the HTTP request once. */\n handleUnauthorized?(\n challenge: MCPAuthorizationChallenge,\n context: MCPAuthorizationContext,\n ): Promise<boolean>;\n}\n\nexport function canonicalMcpResource(rawUrl: string): string {\n let url: URL;\n try {\n url = new URL(rawUrl);\n } catch {\n throw new Error('MCP authorization resource must be an absolute URL');\n }\n if (url.protocol !== 'https:' && !isLoopbackHttp(url)) {\n throw new Error('MCP authorization resource must use HTTPS (except loopback development)');\n }\n if (url.username || url.password || url.hash) {\n throw new Error('MCP authorization resource must not contain credentials or a fragment');\n }\n if (url.pathname === '/' && !url.search) return url.origin;\n return url.toString();\n}\n\nexport function authorizationHeaderForToken(\n token: MCPAccessToken,\n expectedResource: string,\n now = Date.now(),\n): string {\n if (canonicalMcpResource(token.resource) !== expectedResource) {\n throw new Error('MCP access token resource does not match the target server');\n }\n if (token.expiresAt !== undefined && token.expiresAt <= now) {\n throw new Error('MCP access token is expired');\n }\n const tokenType = token.tokenType ?? 'Bearer';\n if (tokenType.toLowerCase() !== 'bearer') {\n throw new Error(`Unsupported MCP OAuth token type \"${tokenType}\"`);\n }\n if (!token.accessToken || token.accessToken.length > 16_384 || /[\\r\\n]/.test(token.accessToken)) {\n throw new Error('MCP access token is empty, oversized, or contains invalid characters');\n }\n return `Bearer ${token.accessToken}`;\n}\n\nexport function parseMcpBearerChallenge(\n header: string | null,\n resource: string,\n): MCPAuthorizationChallenge {\n const challenge: MCPAuthorizationChallenge = {\n status: 401,\n resource,\n scopes: [],\n rawScheme: 'Bearer',\n };\n if (!header) return challenge;\n const bearer = /(?:^|,)\\s*Bearer(?:\\s+|$)/i.exec(header);\n if (!bearer) return challenge;\n const parameters = header.slice((bearer.index ?? 0) + bearer[0].length);\n const resourceMetadata = challengeParameter(parameters, 'resource_metadata');\n if (resourceMetadata) {\n const metadataUrl = validateMetadataUrl(resourceMetadata);\n if (metadataUrl) challenge.resourceMetadataUrl = metadataUrl;\n }\n const scope = challengeParameter(parameters, 'scope');\n if (scope) {\n challenge.scopes = [...new Set(scope.split(/\\s+/).filter(Boolean))].slice(0, 64);\n }\n return challenge;\n}\n\n/** RFC 9728 fallback order for an MCP endpoint when no challenge URL exists. */\nexport function protectedResourceMetadataUrls(resource: string): string[] {\n const url = new URL(canonicalMcpResource(resource));\n const suffix = url.pathname === '/' ? '' : url.pathname;\n const candidates = [\n new URL(`/.well-known/oauth-protected-resource${suffix}`, url.origin).toString(),\n new URL('/.well-known/oauth-protected-resource', url.origin).toString(),\n ];\n return [...new Set(candidates)];\n}\n\n/** RFC 8414 + OIDC discovery order required by the MCP authorization spec. */\nexport function authorizationServerMetadataUrls(issuer: string): string[] {\n const url = secureOAuthUrl(issuer, 'authorization server issuer');\n const suffix = url.pathname === '/' ? '' : url.pathname;\n const candidates = [\n new URL(`/.well-known/oauth-authorization-server${suffix}`, url.origin).toString(),\n new URL(`/.well-known/openid-configuration${suffix}`, url.origin).toString(),\n ];\n if (suffix) {\n candidates.push(\n new URL(\n `${suffix.replace(/\\/$/, '')}/.well-known/openid-configuration`,\n url.origin,\n ).toString(),\n );\n }\n return candidates;\n}\n\nexport function parseProtectedResourceMetadata(\n value: unknown,\n expectedResource: string,\n): MCPProtectedResourceMetadata {\n const metadata = record(value, 'protected resource metadata');\n const resource = canonicalMcpResource(requiredString(metadata['resource'], 'resource'));\n if (resource !== canonicalMcpResource(expectedResource)) {\n throw new Error('MCP protected resource metadata resource does not match the target server');\n }\n const authorizationServers = boundedStringArray(\n metadata['authorization_servers'],\n 'authorization_servers',\n 8,\n ).map((issuer) => secureOAuthUrl(issuer, 'authorization server issuer').toString());\n if (authorizationServers.length === 0) {\n throw new Error('MCP protected resource metadata must declare an authorization server');\n }\n return {\n resource,\n authorizationServers,\n scopesSupported: optionalStringArray(metadata['scopes_supported'], 'scopes_supported', 128),\n };\n}\n\nexport function parseAuthorizationServerMetadata(\n value: unknown,\n expectedIssuer: string,\n): MCPAuthorizationServerMetadata {\n const metadata = record(value, 'authorization server metadata');\n const issuer = secureOAuthUrl(requiredString(metadata['issuer'], 'issuer'), 'issuer').toString();\n if (issuer !== secureOAuthUrl(expectedIssuer, 'expected issuer').toString()) {\n throw new Error('MCP authorization metadata issuer mismatch');\n }\n const methods = boundedStringArray(\n metadata['code_challenge_methods_supported'],\n 'code_challenge_methods_supported',\n 16,\n );\n if (!methods.includes('S256')) {\n throw new Error('MCP authorization server does not advertise required PKCE S256 support');\n }\n const registration = optionalString(metadata['registration_endpoint'], 'registration_endpoint');\n return {\n issuer,\n authorizationEndpoint: secureOAuthUrl(\n requiredString(metadata['authorization_endpoint'], 'authorization_endpoint'),\n 'authorization endpoint',\n ).toString(),\n tokenEndpoint: secureOAuthUrl(\n requiredString(metadata['token_endpoint'], 'token_endpoint'),\n 'token endpoint',\n ).toString(),\n registrationEndpoint: registration\n ? secureOAuthUrl(registration, 'registration endpoint').toString()\n : undefined,\n scopesSupported: optionalStringArray(metadata['scopes_supported'], 'scopes_supported', 128),\n };\n}\n\n/**\n * Re-validate the normalized authorization-server shape before it is accepted\n * from host-owned persistence. PKCE support is established during discovery;\n * this guard protects the persisted endpoints and bounded fields themselves.\n */\nexport function validateMcpAuthorizationServerMetadata(\n value: unknown,\n): MCPAuthorizationServerMetadata {\n const metadata = record(value, 'stored authorization server metadata');\n const registration = optionalString(metadata['registrationEndpoint'], 'registrationEndpoint');\n return {\n issuer: secureOAuthUrl(requiredString(metadata['issuer'], 'issuer'), 'issuer').toString(),\n authorizationEndpoint: secureOAuthUrl(\n requiredString(metadata['authorizationEndpoint'], 'authorizationEndpoint'),\n 'authorization endpoint',\n ).toString(),\n tokenEndpoint: secureOAuthUrl(\n requiredString(metadata['tokenEndpoint'], 'tokenEndpoint'),\n 'token endpoint',\n ).toString(),\n registrationEndpoint: registration\n ? secureOAuthUrl(registration, 'registration endpoint').toString()\n : undefined,\n scopesSupported: optionalStringArray(metadata['scopesSupported'], 'scopesSupported', 128),\n };\n}\n\n/**\n * Discover and validate MCP OAuth metadata without following redirects. The\n * default fetcher resolves once and opens the socket to that exact IP, making\n * discovery resistant to DNS rebinding.\n */\nexport async function discoverMcpAuthorization(\n resource: string,\n options: MCPAuthorizationDiscoveryOptions = {},\n): Promise<MCPAuthorizationDiscoveryResult> {\n const canonicalResource = canonicalMcpResource(resource);\n const resourceUrl = new URL(canonicalResource);\n const allowedLoopbackHostname = isLoopbackHttp(resourceUrl)\n ? unbracket(resourceUrl.hostname).toLowerCase()\n : undefined;\n const fetchJson =\n options.fetchJson ??\n ((url, signal) =>\n requestPinnedJson(url, {\n signal,\n timeoutMs: options.timeoutMs,\n maxResponseBytes: options.maxResponseBytes,\n lookup: options.lookup,\n allowedLoopbackHostname,\n }));\n\n const challenge = parseMcpBearerChallenge(options.challengeHeader ?? null, canonicalResource);\n const resourceCandidates = challenge.resourceMetadataUrl\n ? [challenge.resourceMetadataUrl]\n : protectedResourceMetadataUrls(canonicalResource);\n const resourceDiscovery = await discoverFirst(\n resourceCandidates,\n fetchJson,\n options.signal,\n (value) => parseProtectedResourceMetadata(value, canonicalResource),\n 'protected resource metadata',\n );\n const issuer = resourceDiscovery.value.authorizationServers[0]!;\n const authorizationDiscovery = await discoverFirst(\n authorizationServerMetadataUrls(issuer),\n fetchJson,\n options.signal,\n (value) => parseAuthorizationServerMetadata(value, issuer),\n 'authorization server metadata',\n );\n return {\n resourceMetadataUrl: resourceDiscovery.url,\n authorizationServerMetadataUrl: authorizationDiscovery.url,\n protectedResource: resourceDiscovery.value,\n authorizationServer: authorizationDiscovery.value,\n };\n}\n\nexport function createMcpAuthorizationRequest(\n options: MCPAuthorizationRequestOptions,\n): MCPAuthorizationSession {\n const resource = canonicalMcpResource(options.resource);\n const clientId = boundedCredential(options.clientId, 'client id');\n const redirectUri = validateRedirectUri(options.redirectUri);\n const scopes = validateScopes(options.scopes ?? []);\n const codeVerifier = base64Url(randomBytes(32));\n const codeChallenge = base64Url(createHash('sha256').update(codeVerifier).digest());\n const state = base64Url(randomBytes(32));\n const authorizationUrl = secureOAuthUrl(\n options.authorizationServer.authorizationEndpoint,\n 'authorization endpoint',\n );\n authorizationUrl.searchParams.set('response_type', 'code');\n authorizationUrl.searchParams.set('client_id', clientId);\n authorizationUrl.searchParams.set('redirect_uri', redirectUri);\n authorizationUrl.searchParams.set('state', state);\n authorizationUrl.searchParams.set('code_challenge', codeChallenge);\n authorizationUrl.searchParams.set('code_challenge_method', 'S256');\n authorizationUrl.searchParams.set('resource', resource);\n if (scopes.length > 0) authorizationUrl.searchParams.set('scope', scopes.join(' '));\n return {\n authorizationUrl: authorizationUrl.toString(),\n state,\n codeVerifier,\n redirectUri,\n clientId,\n resource,\n };\n}\n\nexport function parseMcpAuthorizationCallback(\n callbackUrl: string,\n session: Pick<MCPAuthorizationSession, 'redirectUri' | 'state'>,\n): string {\n let callback: URL;\n try {\n callback = new URL(callbackUrl);\n } catch {\n throw new Error('MCP OAuth callback must be an absolute URL');\n }\n const expected = new URL(validateRedirectUri(session.redirectUri));\n if (\n callback.protocol !== expected.protocol ||\n callback.hostname !== expected.hostname ||\n callback.port !== expected.port ||\n callback.pathname !== expected.pathname\n ) {\n throw new Error('MCP OAuth callback redirect URI does not match the authorization session');\n }\n const returnedState = callback.searchParams.get('state') ?? '';\n if (!constantTimeEqual(returnedState, session.state)) {\n throw new Error('MCP OAuth callback state mismatch');\n }\n const oauthError = callback.searchParams.get('error');\n if (oauthError)\n throw new Error(`MCP OAuth authorization failed: ${boundedErrorCode(oauthError)}`);\n return boundedCredential(callback.searchParams.get('code') ?? '', 'authorization code');\n}\n\nexport async function exchangeMcpAuthorizationCode(\n options: MCPTokenExchangeOptions,\n): Promise<MCPTokenSet> {\n const resource = canonicalMcpResource(options.resource);\n const body = new URLSearchParams({\n grant_type: 'authorization_code',\n code: boundedCredential(options.code, 'authorization code'),\n client_id: boundedCredential(options.clientId, 'client id'),\n redirect_uri: validateRedirectUri(options.redirectUri),\n code_verifier: validateCodeVerifier(options.codeVerifier),\n resource,\n }).toString();\n const response = await requestPinnedJson(options.authorizationServer.tokenEndpoint, {\n method: 'POST',\n body,\n headers: { 'content-type': 'application/x-www-form-urlencoded' },\n signal: options.signal,\n timeoutMs: options.timeoutMs,\n maxResponseBytes: options.maxResponseBytes,\n lookup: options.lookup,\n allowedLoopbackHostname: loopbackHostnameForResource(resource),\n });\n if (response === undefined) throw new Error('MCP OAuth token endpoint returned no response');\n return parseTokenResponse(response, resource);\n}\n\nexport async function refreshMcpAccessToken(options: MCPTokenRefreshOptions): Promise<MCPTokenSet> {\n const resource = canonicalMcpResource(options.resource);\n const previousRefreshToken = boundedCredential(options.refreshToken, 'refresh token');\n const body = new URLSearchParams({\n grant_type: 'refresh_token',\n refresh_token: previousRefreshToken,\n client_id: boundedCredential(options.clientId, 'client id'),\n resource,\n }).toString();\n const response = await requestPinnedJson(options.authorizationServer.tokenEndpoint, {\n method: 'POST',\n body,\n headers: { 'content-type': 'application/x-www-form-urlencoded' },\n signal: options.signal,\n timeoutMs: options.timeoutMs,\n maxResponseBytes: options.maxResponseBytes,\n lookup: options.lookup,\n allowedLoopbackHostname: loopbackHostnameForResource(resource),\n });\n if (response === undefined) throw new Error('MCP OAuth token endpoint returned no response');\n const parsed = parseTokenResponse(response, resource);\n return { ...parsed, refreshToken: parsed.refreshToken ?? previousRefreshToken };\n}\n\nfunction challengeParameter(parameters: string, name: string): string | undefined {\n const pattern = new RegExp(\n `(?:^|,)\\\\s*${name}\\\\s*=\\\\s*(?:\"((?:\\\\\\\\.|[^\"\\\\\\\\])*)\"|([^,\\\\s]+))`,\n 'i',\n );\n const match = pattern.exec(parameters);\n const value = match?.[1] ?? match?.[2];\n return value?.replace(/\\\\([\"\\\\])/g, '$1');\n}\n\nfunction validateMetadataUrl(value: string): string | undefined {\n try {\n const url = new URL(value);\n if (url.username || url.password || url.hash) return undefined;\n if (url.protocol !== 'https:' && !isLoopbackHttp(url)) return undefined;\n return url.toString();\n } catch {\n return undefined;\n }\n}\n\nfunction record(value: unknown, label: string): Record<string, unknown> {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error(`MCP ${label} must be an object`);\n }\n return value as Record<string, unknown>;\n}\n\nfunction requiredString(value: unknown, field: string): string {\n if (typeof value !== 'string' || value.length === 0 || value.length > 4_096) {\n throw new Error(`MCP authorization field \"${field}\" must be a bounded non-empty string`);\n }\n return value;\n}\n\nfunction optionalString(value: unknown, field: string): string | undefined {\n return value === undefined ? undefined : requiredString(value, field);\n}\n\nfunction boundedStringArray(value: unknown, field: string, maxItems: number): string[] {\n if (!Array.isArray(value) || value.length > maxItems) {\n throw new Error(`MCP authorization field \"${field}\" must be an array of at most ${maxItems}`);\n }\n return [...new Set(value.map((entry) => requiredString(entry, field)))];\n}\n\nfunction optionalStringArray(value: unknown, field: string, maxItems: number): string[] {\n return value === undefined ? [] : boundedStringArray(value, field, maxItems);\n}\n\nfunction secureOAuthUrl(value: string, label: string): URL {\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n throw new Error(`MCP ${label} must be an absolute URL`);\n }\n if (url.protocol !== 'https:' && !isLoopbackHttp(url)) {\n throw new Error(`MCP ${label} must use HTTPS (except loopback development)`);\n }\n if (url.username || url.password || url.search || url.hash) {\n throw new Error(`MCP ${label} must not contain credentials, query, or fragment components`);\n }\n if (url.pathname === '/') return new URL(url.origin);\n return url;\n}\n\nasync function discoverFirst<T>(\n candidates: readonly string[],\n fetchJson: MCPAuthorizationJsonFetcher,\n signal: AbortSignal | undefined,\n parse: (value: unknown) => T,\n label: string,\n): Promise<{ url: string; value: T }> {\n const failures: string[] = [];\n for (const candidate of candidates) {\n signal?.throwIfAborted();\n try {\n const value = await fetchJson(candidate, signal);\n if (value === undefined) {\n failures.push(`${candidate}: not found`);\n continue;\n }\n return { url: candidate, value: parse(value) };\n } catch (error) {\n signal?.throwIfAborted();\n failures.push(`${candidate}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n throw new Error(`MCP ${label} discovery failed (${failures.join('; ')})`);\n}\n\nasync function requestPinnedJson(\n rawUrl: string,\n options: {\n method?: 'GET' | 'POST' | undefined;\n body?: string | undefined;\n headers?: Record<string, string> | undefined;\n signal?: AbortSignal | undefined;\n timeoutMs?: number | undefined;\n maxResponseBytes?: number | undefined;\n lookup?: BrowserCompatibleDnsLookup | undefined;\n allowedLoopbackHostname?: string | undefined;\n },\n): Promise<unknown | undefined> {\n const url = secureOAuthUrl(rawUrl, 'discovery URL');\n const target = await resolvePinnedAddress(url, options);\n const timeoutMs = options.timeoutMs ?? 10_000;\n const maxBytes = options.maxResponseBytes ?? 64 * 1024;\n options.signal?.throwIfAborted();\n\n return new Promise<unknown | undefined>((resolve, reject) => {\n let settled = false;\n const finish = (error?: Error, value?: unknown) => {\n if (settled) return;\n settled = true;\n options.signal?.removeEventListener('abort', onAbort);\n if (error) reject(error);\n else resolve(value);\n };\n const onAbort = () => {\n request.destroy(options.signal?.reason instanceof Error ? options.signal.reason : undefined);\n };\n const headers: Record<string, string | number> = {\n accept: 'application/json',\n host: url.host,\n ...options.headers,\n };\n if (options.body !== undefined) {\n headers['content-length'] = Buffer.byteLength(options.body);\n }\n const requestOptions: http.RequestOptions = {\n host: target.address,\n family: target.family,\n port: Number(url.port || (url.protocol === 'https:' ? 443 : 80)),\n method: options.method ?? 'GET',\n path: `${url.pathname}${url.search}`,\n headers,\n ...(url.protocol === 'https:' && net.isIP(unbracket(url.hostname)) === 0\n ? { servername: unbracket(url.hostname) }\n : {}),\n };\n const requestFn = url.protocol === 'https:' ? https.request : http.request;\n const request = requestFn(requestOptions, (response) => {\n const status = response.statusCode ?? 0;\n if (status === 404 || status === 410) {\n response.resume();\n finish(undefined, undefined);\n return;\n }\n if (status >= 300 && status < 400) {\n response.resume();\n finish(new Error('MCP OAuth discovery redirects are not allowed'));\n return;\n }\n if (status < 200 || status >= 300) {\n response.resume();\n finish(new Error(`MCP OAuth discovery HTTP ${status}`));\n return;\n }\n const contentType = response.headers['content-type'] ?? '';\n if (!/^(?:application\\/json|[^;]+\\+json)(?:;|$)/i.test(contentType)) {\n response.resume();\n finish(new Error('MCP OAuth discovery response must be JSON'));\n return;\n }\n const declaredLength = Number(response.headers['content-length'] ?? 0);\n if (Number.isFinite(declaredLength) && declaredLength > maxBytes) {\n response.destroy();\n finish(new Error(`MCP OAuth discovery response exceeds ${maxBytes} bytes`));\n return;\n }\n const chunks: Buffer[] = [];\n let size = 0;\n response.on('data', (chunk: Buffer) => {\n size += chunk.length;\n if (size > maxBytes) {\n response.destroy();\n finish(new Error(`MCP OAuth discovery response exceeds ${maxBytes} bytes`));\n return;\n }\n chunks.push(chunk);\n });\n response.once('end', () => {\n try {\n finish(undefined, JSON.parse(Buffer.concat(chunks).toString('utf8')));\n } catch {\n finish(new Error('MCP OAuth discovery response is not valid JSON'));\n }\n });\n response.once('error', (error) => finish(error));\n });\n request.setTimeout(timeoutMs, () => {\n request.destroy(new Error(`MCP OAuth discovery timed out after ${timeoutMs}ms`));\n });\n request.once('error', (error) => finish(error));\n options.signal?.addEventListener('abort', onAbort, { once: true });\n request.end(options.body);\n });\n}\n\nasync function resolvePinnedAddress(\n url: URL,\n options: {\n lookup?: BrowserCompatibleDnsLookup | undefined;\n allowedLoopbackHostname?: string | undefined;\n },\n): Promise<{ address: string; family: 4 | 6 }> {\n const hostname = unbracket(url.hostname).toLowerCase();\n const literalFamily = net.isIP(hostname);\n if (literalFamily === 4 || literalFamily === 6) {\n assertDiscoveryAddressAllowed(\n hostname,\n literalFamily,\n hostname,\n options.allowedLoopbackHostname,\n );\n return { address: hostname, family: literalFamily };\n }\n const lookup = options.lookup ?? ((host) => dns.lookup(host, { all: true }));\n const records = await lookup(hostname);\n if (records.length === 0)\n throw new Error(`MCP OAuth discovery DNS returned no addresses for ${hostname}`);\n for (const record of records) {\n if (record.family !== 4 && record.family !== 6) {\n throw new Error('MCP OAuth discovery DNS returned an unsupported address family');\n }\n assertDiscoveryAddressAllowed(\n record.address,\n record.family,\n hostname,\n options.allowedLoopbackHostname,\n );\n }\n const selected = records[0]!;\n return { address: selected.address, family: selected.family as 4 | 6 };\n}\n\nfunction assertDiscoveryAddressAllowed(\n address: string,\n family: 4 | 6,\n hostname: string,\n allowedLoopbackHostname: string | undefined,\n): void {\n const isPrivate = family === 4 ? isPrivateIPv4(address) : isPrivateIPv6(address);\n if (!isPrivate) return;\n const loopback = family === 4 ? address.startsWith('127.') : address === '::1';\n if (loopback && hostname === allowedLoopbackHostname) return;\n throw new Error(`MCP OAuth discovery blocked private address ${address}`);\n}\n\nfunction unbracket(hostname: string): string {\n return hostname.startsWith('[') && hostname.endsWith(']') ? hostname.slice(1, -1) : hostname;\n}\n\nfunction validateRedirectUri(value: string): string {\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n throw new Error('MCP OAuth redirect URI must be an absolute URL');\n }\n if (url.protocol !== 'https:' && !isLoopbackHttp(url)) {\n throw new Error('MCP OAuth redirect URI must use HTTPS or loopback HTTP');\n }\n if (url.username || url.password || url.search || url.hash) {\n throw new Error('MCP OAuth redirect URI must not contain credentials, query, or fragment');\n }\n return url.toString();\n}\n\nfunction validateScopes(scopes: readonly string[]): string[] {\n if (scopes.length > 128) throw new Error('MCP OAuth scope list exceeds 128 entries');\n const normalized = scopes.map((scope) => {\n if (!scope || scope.length > 256 || /\\s/.test(scope)) {\n throw new Error('MCP OAuth scopes must be bounded non-empty tokens');\n }\n return scope;\n });\n return [...new Set(normalized)];\n}\n\nfunction validateCodeVerifier(value: string): string {\n if (value.length < 43 || value.length > 128 || !/^[A-Za-z0-9._~-]+$/.test(value)) {\n throw new Error('MCP OAuth PKCE code verifier is invalid');\n }\n return value;\n}\n\nfunction boundedCredential(value: string, label: string): string {\n if (!value || value.length > 16_384 || /[\\r\\n]/.test(value)) {\n throw new Error(`MCP OAuth ${label} is empty, oversized, or invalid`);\n }\n return value;\n}\n\nfunction boundedErrorCode(value: string): string {\n return /^[A-Za-z0-9._-]{1,128}$/.test(value) ? value : 'invalid_error';\n}\n\nfunction base64Url(value: Uint8Array): string {\n return Buffer.from(value).toString('base64url');\n}\n\nfunction constantTimeEqual(left: string, right: string): boolean {\n const leftHash = createHash('sha256').update(left).digest();\n const rightHash = createHash('sha256').update(right).digest();\n return timingSafeEqual(leftHash, rightHash);\n}\n\nfunction parseTokenResponse(value: unknown, resource: string): MCPTokenSet {\n const response = record(value, 'token response');\n const accessToken = boundedCredential(\n requiredString(response['access_token'], 'access_token'),\n 'access token',\n );\n const tokenType = optionalString(response['token_type'], 'token_type') ?? 'Bearer';\n if (tokenType.toLowerCase() !== 'bearer') {\n throw new Error(`Unsupported MCP OAuth token type \"${tokenType}\"`);\n }\n const expiresIn = response['expires_in'];\n let expiresAt: number | undefined;\n if (expiresIn !== undefined) {\n if (\n typeof expiresIn !== 'number' ||\n !Number.isFinite(expiresIn) ||\n expiresIn <= 0 ||\n expiresIn > 31_536_000\n ) {\n throw new Error('MCP OAuth expires_in must be between 1 second and 1 year');\n }\n expiresAt = Date.now() + Math.floor(expiresIn * 1_000);\n }\n const refresh = optionalString(response['refresh_token'], 'refresh_token');\n const scope = optionalString(response['scope'], 'scope');\n const token: MCPTokenSet = {\n accessToken,\n tokenType: 'Bearer',\n resource,\n scopes: scope ? validateScopes(scope.split(/\\s+/).filter(Boolean)) : [],\n ...(expiresAt !== undefined ? { expiresAt } : {}),\n ...(refresh ? { refreshToken: boundedCredential(refresh, 'refresh token') } : {}),\n };\n authorizationHeaderForToken(token, resource);\n return token;\n}\n\nfunction loopbackHostnameForResource(resource: string): string | undefined {\n const url = new URL(resource);\n return isLoopbackHttp(url) ? unbracket(url.hostname).toLowerCase() : undefined;\n}\n\nfunction isLoopbackHttp(url: URL): boolean {\n if (url.protocol !== 'http:') return false;\n return (\n url.hostname === 'localhost' ||\n url.hostname === '127.0.0.1' ||\n url.hostname === '[::1]' ||\n url.hostname === '::1'\n );\n}\n", "import {\n canonicalMcpResource,\n createMcpAuthorizationRequest,\n discoverMcpAuthorization,\n exchangeMcpAuthorizationCode,\n type MCPAuthorizationDiscoveryOptions,\n type MCPAuthorizationDiscoveryResult,\n type MCPAuthorizationSession,\n type MCPTokenExchangeOptions,\n type MCPTokenSet,\n parseMcpAuthorizationCallback,\n parseMcpBearerChallenge,\n} from './authorization.js';\nimport type {\n MCPAuthorizationStateEvent,\n MCPStoredAuthorization,\n MCPVaultTokenStore,\n} from './token-store.js';\n\nconst DEFAULT_PENDING_TTL_MS = 10 * 60_000;\nconst MAX_PENDING_AUTHORIZATIONS = 32;\n\ntype DiscoverAuthorization = (\n resource: string,\n options?: MCPAuthorizationDiscoveryOptions,\n) => Promise<MCPAuthorizationDiscoveryResult>;\n\ntype ExchangeAuthorizationCode = (options: MCPTokenExchangeOptions) => Promise<MCPTokenSet>;\n\nexport interface MCPAuthorizationManagerOptions {\n store: MCPVaultTokenStore;\n pendingTtlMs?: number | undefined;\n discover?: DiscoverAuthorization | undefined;\n exchange?: ExchangeAuthorizationCode | undefined;\n now?: (() => number) | undefined;\n onStateChange?: ((event: MCPAuthorizationStateEvent) => void) | undefined;\n}\n\nexport interface MCPAuthorizationStartInput {\n serverName: string;\n resource: string;\n clientId: string;\n redirectUri: string;\n scopes?: readonly string[] | undefined;\n challengeHeader?: string | null | undefined;\n signal?: AbortSignal | undefined;\n}\n\nexport interface MCPAuthorizationStartResult {\n serverName: string;\n resource: string;\n authorizationUrl: string;\n redirectUri: string;\n scopes: string[];\n expiresAt: number;\n}\n\nexport interface MCPAuthorizationCompleteInput {\n serverName: string;\n resource: string;\n callbackUrl: string;\n signal?: AbortSignal | undefined;\n}\n\nexport interface MCPAuthorizationStatus {\n serverName: string;\n resource: string;\n state: 'not_authorized' | 'pending' | 'authorized' | 'expired';\n expiresAt?: number | undefined;\n scopes: string[];\n canRefresh: boolean;\n}\n\ninterface PendingAuthorization {\n session: MCPAuthorizationSession;\n discovery: MCPAuthorizationDiscoveryResult;\n scopes: string[];\n expiresAt: number;\n}\n\n/**\n * Surface-neutral manual OAuth coordinator. PKCE verifier/state stay only in\n * this bounded, expiring in-memory map; completed credentials are handed to\n * the host-owned vault store.\n */\nexport class MCPAuthorizationManager {\n private readonly pending = new Map<string, PendingAuthorization>();\n private readonly pendingTtlMs: number;\n private readonly discover: DiscoverAuthorization;\n private readonly exchange: ExchangeAuthorizationCode;\n private readonly now: () => number;\n\n constructor(private readonly options: MCPAuthorizationManagerOptions) {\n this.pendingTtlMs = options.pendingTtlMs ?? DEFAULT_PENDING_TTL_MS;\n if (!Number.isFinite(this.pendingTtlMs) || this.pendingTtlMs <= 0) {\n throw new Error('MCP authorization pending TTL must be a positive finite number');\n }\n this.discover = options.discover ?? discoverMcpAuthorization;\n this.exchange = options.exchange ?? exchangeMcpAuthorizationCode;\n this.now = options.now ?? Date.now;\n }\n\n async begin(input: MCPAuthorizationStartInput): Promise<MCPAuthorizationStartResult> {\n const resource = canonicalMcpResource(input.resource);\n const key = authorizationKey(input.serverName, resource);\n this.pruneExpired();\n if (!this.pending.has(key) && this.pending.size >= MAX_PENDING_AUTHORIZATIONS) {\n throw new Error('Too many pending MCP authorization sessions');\n }\n const discovery = await this.discover(resource, {\n challengeHeader: input.challengeHeader,\n signal: input.signal,\n });\n const challengeScopes = parseMcpBearerChallenge(input.challengeHeader ?? null, resource).scopes;\n const scopes = input.scopes ? [...input.scopes] : challengeScopes;\n const session = createMcpAuthorizationRequest({\n authorizationServer: discovery.authorizationServer,\n clientId: input.clientId,\n redirectUri: input.redirectUri,\n resource,\n scopes,\n });\n const normalizedScopes =\n new URL(session.authorizationUrl).searchParams.get('scope')?.split(' ').filter(Boolean) ?? [];\n const expiresAt = this.now() + this.pendingTtlMs;\n this.pending.set(key, { session, discovery, scopes: normalizedScopes, expiresAt });\n return {\n serverName: boundedServerName(input.serverName),\n resource,\n authorizationUrl: session.authorizationUrl,\n redirectUri: session.redirectUri,\n scopes: [...normalizedScopes],\n expiresAt,\n };\n }\n\n async complete(input: MCPAuthorizationCompleteInput): Promise<MCPAuthorizationStatus> {\n const serverName = boundedServerName(input.serverName);\n const resource = canonicalMcpResource(input.resource);\n const key = authorizationKey(serverName, resource);\n this.pruneExpired();\n const pending = this.pending.get(key);\n if (!pending) {\n throw new Error('No live MCP authorization session exists for this server');\n }\n const code = parseMcpAuthorizationCallback(input.callbackUrl, pending.session);\n // Authorization codes and PKCE verifiers are one-shot. Remove before the\n // network exchange so retries cannot accidentally replay either value.\n this.pending.delete(key);\n const tokenSet = await this.exchange({\n authorizationServer: pending.discovery.authorizationServer,\n clientId: pending.session.clientId,\n redirectUri: pending.session.redirectUri,\n resource,\n code,\n codeVerifier: pending.session.codeVerifier,\n signal: input.signal,\n });\n const stored: MCPStoredAuthorization = {\n serverName,\n resource,\n clientId: pending.session.clientId,\n authorizationServer: pending.discovery.authorizationServer,\n tokenSet,\n updatedAt: new Date(this.now()).toISOString(),\n };\n await this.options.store.save(stored);\n this.emit('authorized', stored);\n return statusFromStored(stored, this.now());\n }\n\n async status(serverName: string, resource: string): Promise<MCPAuthorizationStatus> {\n const normalizedName = boundedServerName(serverName);\n const normalizedResource = canonicalMcpResource(resource);\n this.pruneExpired();\n const pending = this.pending.get(authorizationKey(normalizedName, normalizedResource));\n if (pending) {\n return {\n serverName: normalizedName,\n resource: normalizedResource,\n state: 'pending',\n expiresAt: pending.expiresAt,\n scopes: [...pending.scopes],\n canRefresh: false,\n };\n }\n const stored = await this.options.store.load(normalizedName, normalizedResource);\n return stored\n ? statusFromStored(stored, this.now())\n : {\n serverName: normalizedName,\n resource: normalizedResource,\n state: 'not_authorized',\n scopes: [],\n canRefresh: false,\n };\n }\n\n async disconnect(serverName: string, resource: string): Promise<boolean> {\n const normalizedName = boundedServerName(serverName);\n const normalizedResource = canonicalMcpResource(resource);\n this.pending.delete(authorizationKey(normalizedName, normalizedResource));\n const removed = await this.options.store.remove(normalizedName, normalizedResource);\n if (removed) {\n this.options.onStateChange?.({\n serverName: normalizedName,\n state: 'removed',\n resource: normalizedResource,\n });\n }\n return removed;\n }\n\n private pruneExpired(): void {\n const now = this.now();\n for (const [key, value] of this.pending) {\n if (value.expiresAt <= now) this.pending.delete(key);\n }\n }\n\n private emit(state: MCPAuthorizationStateEvent['state'], value: MCPStoredAuthorization): void {\n this.options.onStateChange?.({\n serverName: value.serverName,\n state,\n resource: value.resource,\n expiresAt: value.tokenSet.expiresAt,\n scopes: [...(value.tokenSet.scopes ?? [])],\n });\n }\n}\n\nfunction statusFromStored(value: MCPStoredAuthorization, now: number): MCPAuthorizationStatus {\n return {\n serverName: value.serverName,\n resource: value.resource,\n state:\n value.tokenSet.expiresAt !== undefined && value.tokenSet.expiresAt <= now\n ? 'expired'\n : 'authorized',\n expiresAt: value.tokenSet.expiresAt,\n scopes: [...(value.tokenSet.scopes ?? [])],\n canRefresh: !!value.tokenSet.refreshToken,\n };\n}\n\nfunction authorizationKey(serverName: string, resource: string): string {\n return `${boundedServerName(serverName)}\\0${resource}`;\n}\n\nfunction boundedServerName(value: string): string {\n if (!value || value.length > 256 || /[\\r\\n\\0]/.test(value)) {\n throw new Error('MCP authorization server name is invalid');\n }\n return value;\n}\n", "import { type ChildProcess, spawn } from 'node:child_process';\nimport { buildChildEnv } from '@wrongstack/core/utils';\nimport { toErrorMessage } from '@wrongstack/core/utils';\nimport type { MCPAuthorizationProvider } from './authorization.js';\nimport { MCP_CONSTANTS } from './constants.js';\nimport {\n type MCPGetPromptResult,\n type MCPListPromptsResult,\n type MCPListResourcesResult,\n type MCPListResourceTemplatesResult,\n type MCPReadResourceResult,\n type MCPServerMetadata,\n parseGetPromptResult,\n parseListPromptsResult,\n parseListResourcesResult,\n parseListResourceTemplatesResult,\n parseReadResourceResult,\n parseServerMetadata,\n} from './protocol.js';\nimport { normalizeMCPTools } from './tool-schema.js';\nimport { type HttpTransportOptions, SSETransport, StreamableHTTPTransport } from './transport.js';\n\nexport type Transport = 'stdio' | 'sse' | 'streamable-http';\n\nexport interface MCPClientOptions {\n name: string;\n transport: Transport;\n command?: string | undefined;\n args?: string[] | undefined;\n env?: Record<string, string> | undefined;\n url?: string | undefined;\n headers?: Record<string, string> | undefined;\n startupTimeoutMs?: number | undefined;\n requestTimeoutMs?: number | undefined;\n /** Host-owned, vault-backed authorization for HTTP transports. */\n authorizationProvider?: MCPAuthorizationProvider | undefined;\n /**\n * Allowlist of env var names to forward from the parent process (process.env)\n * to the child. Values are resolved at spawn time and merged into `env`\n * via the `extra` path of `buildChildEnv` (unfiltered). This is how built-in\n * MCP server presets (GitHub, Slack, Brave Search, \u2026) get their API tokens\n * without storing them in config.json or being scrubbed by the secret filter.\n */\n passthroughEnv?: string[] | undefined;\n}\n\nexport type ConnectionState =\n | 'idle'\n | 'connecting'\n | 'connected'\n | 'disconnected'\n | 'reconnecting'\n | 'failed'\n /** Lazy server: registered from a cached manifest, process not spawned. */\n | 'dormant';\n\nexport interface MCPTool {\n name: string;\n description?: string | undefined;\n inputSchema: Record<string, unknown>;\n}\n\nexport interface ToolCallResult {\n content: unknown;\n isError: boolean;\n}\n\nexport interface MCPRequestOptions {\n signal?: AbortSignal | undefined;\n}\n\nexport interface MCPPageOptions extends MCPRequestOptions {\n cursor?: string | undefined;\n}\n\ninterface JsonRpcRequest {\n jsonrpc: '2.0';\n id: number;\n method: string;\n params?: unknown | undefined;\n}\n\nexport interface JsonRpcResponse {\n jsonrpc: '2.0';\n id: number;\n result?: unknown | undefined;\n error?: { code: number | undefined; message: string; data?: unknown | undefined } | undefined;\n}\n\ntype JsonRpcServerRequest = {\n jsonrpc: '2.0';\n id: number | string;\n method: string;\n params?: unknown | undefined;\n};\n\nfunction isJsonRpcResponse(value: unknown): value is JsonRpcResponse {\n if (typeof value !== 'object' || value === null) return false;\n const response = value as Record<string, unknown>;\n if (response['jsonrpc'] !== '2.0' || typeof response['id'] !== 'number') return false;\n if (Object.hasOwn(response, 'method')) return false;\n\n const hasResult = Object.hasOwn(response, 'result');\n const hasError = Object.hasOwn(response, 'error');\n if (hasResult === hasError) return false;\n if (!hasError) return true;\n\n const error = response['error'];\n return (\n typeof error === 'object' &&\n error !== null &&\n typeof (error as Record<string, unknown>)['code'] === 'number' &&\n typeof (error as Record<string, unknown>)['message'] === 'string'\n );\n}\n\ntype ExitListener = (name: string, code: number | null, signal: string | null) => void;\n/**\n * Fired when the server sends `notifications/tools/list_changed`. The\n * client refreshes its cached tool list before invoking listeners, so\n * subscribers can call `listTools()` for the fresh set.\n */\ntype ToolsChangedListener = (name: string, tools: MCPTool[]) => void;\nexport type MCPListChangedListener = (name: string) => void;\n\n/**\n * Lightweight MCP client supporting three transport types:\n * - stdio: spawns a child process and communicates over pipes\n * - sse: connects to an HTTP SSE endpoint for server events, POST for requests\n * - streamable-http: session-based HTTP transport with NDJSON responses\n */\nexport class MCPClient {\n /**\n * Maximum bytes the rx buffer may accumulate before the connection is\n * forcefully closed. A well-behaved JSON-RPC server emits newline-delimited\n * messages that are individually much smaller than this; a server that never\n * sends a newline would grow the buffer without limit and OOM the process.\n * 16 MiB is generous for any legitimate single message while bounding the\n * worst-case memory to a predictable cap.\n */\n private static readonly MAX_RX_BUFFER_BYTES = 16 * 1024 * 1024;\n\n private state: ConnectionState = 'idle';\n private child?: ChildProcess | undefined;\n private nextId = 1;\n /**\n * In-flight JSON-RPC calls keyed by id. `resolve` settles the call; `reject`\n * is invoked from {@link failPending} when the underlying transport dies\n * (stdio child exit, `close()`) so callers don't hang forever.\n */\n private readonly pending = new Map<\n number,\n { resolve: (res: JsonRpcResponse) => void; reject: (err: Error) => void; timer: NodeJS.Timeout }\n >();\n private rxBuffer = '';\n private _tools: MCPTool[] = [];\n /** Server-declared handshake metadata. Populated for stdio in the first protocol slice. */\n private _serverMetadata?: MCPServerMetadata | undefined;\n /** Cached tool list \u2014 survives reconnects so the registry can re-register without re-discovering. */\n private _toolsCache?: MCPTool[] | undefined;\n private _drainPending = false;\n private _lastNotifySkipped = false;\n // HTTP transports\n private sseTransport?: SSETransport | undefined;\n private httpTransport?: StreamableHTTPTransport | undefined;\n /** Notified when the stdio child process exits so the registry can attempt reconnect. */\n private readonly exitListeners = new Set<ExitListener>();\n /** Notified when the server announces a tools/list_changed notification. */\n private readonly toolsChangedListeners = new Set<ToolsChangedListener>();\n private readonly resourcesChangedListeners = new Set<MCPListChangedListener>();\n private readonly promptsChangedListeners = new Set<MCPListChangedListener>();\n /** Notified when an HTTP transport (SSE or streamable-http) disconnects. */\n private readonly disconnectListeners = new Set<() => void>();\n\n constructor(public readonly opts: MCPClientOptions) {}\n\n getState(): ConnectionState {\n return this.state;\n }\n\n getServerMetadata(): MCPServerMetadata | undefined {\n const metadata = this._serverMetadata;\n if (!metadata) return undefined;\n return {\n ...metadata,\n capabilities: { ...metadata.capabilities },\n serverInfo: { ...metadata.serverInfo },\n };\n }\n\n listTools(): MCPTool[] {\n return this._tools.length > 0\n ? [...this._tools]\n : this._toolsCache\n ? [...this._toolsCache]\n : [];\n }\n\n /** Returns true if a prior notify() call was skipped due to backpressure. */\n hadNotifySkipped(): boolean {\n return this._lastNotifySkipped;\n }\n\n /**\n * Register a listener for child-process exit events.\n * The registry uses this to trigger reconnection.\n */\n addExitListener(listener: ExitListener): void {\n this.exitListeners.add(listener);\n }\n\n removeExitListener(listener: ExitListener): void {\n this.exitListeners.delete(listener);\n }\n\n /**\n * Register a listener for transport disconnect events (SSE / streamable-http).\n * Used by the registry to trigger reconnection for HTTP-based servers.\n */\n addDisconnectListener(listener: () => void): void {\n this.disconnectListeners.add(listener);\n }\n\n removeDisconnectListener(listener: () => void): void {\n this.disconnectListeners.delete(listener);\n }\n\n async connect(): Promise<void> {\n this.state = 'connecting';\n this._serverMetadata = undefined;\n\n if (this.opts.transport === 'stdio') {\n await this.connectStdio();\n } else if (this.opts.transport === 'sse') {\n await this.connectSSE();\n } else if (this.opts.transport === 'streamable-http') {\n await this.connectStreamableHTTP();\n } else {\n this.state = 'failed';\n throw new Error(`Unknown transport \"${this.opts.transport}\"`);\n }\n }\n\n private async connectStdio(): Promise<void> {\n if (!this.opts.command) {\n this.state = 'failed';\n throw new Error('MCP stdio transport requires \"command\"');\n }\n\n // Defense-in-depth: clear any rx state from a previous connect attempt\n // on this instance. The registry normally creates a fresh client per\n // (re)connect cycle, but a leftover rxBuffer from a half-initialized\n // attempt would corrupt JSON-RPC parsing on the new stream.\n this.rxBuffer = '';\n\n // On Windows, MCP servers are usually launched via `npx`/`npm`/`uvx`,\n // which resolve to `.cmd` shims. Since the CVE-2024-27980 fix Node refuses\n // to spawn `.cmd`/`.bat` without a shell (raw spawn throws ENOENT), so the\n // whole npx-based preset catalog is unusable without a shell. We pass the\n // full command line as a single string (with each token cmd.exe-quoted) and\n // `shell: true` \u2014 an empty args array avoids the DEP0190 warning that\n // `shell:true` + an args array triggers. Server command+args come from\n // config (admin-controlled), not the model, so shell use is not an\n // injection vector here.\n // Resolve passthroughEnv: forward explicitly-listed env var names from\n // the parent process to the child. This lets MCP server presets (GitHub,\n // Slack, Brave Search, \u2026) get their API tokens without storing them in\n // config.json or being scrubbed by buildChildEnv()'s secret filter.\n const extraEnv: Record<string, string> = { ...this.opts.env };\n if (this.opts.passthroughEnv) {\n for (const name of this.opts.passthroughEnv) {\n const val = process.env[name];\n if (val !== undefined) {\n extraEnv[name] = val;\n }\n }\n }\n const isWin = process.platform === 'win32';\n const rawArgs = this.opts.args ?? [];\n const spawnEnv = buildChildEnv({ extra: extraEnv });\n const stdio: ['pipe', 'pipe', 'pipe'] = ['pipe', 'pipe', 'pipe'];\n const child = isWin\n ? spawn([this.opts.command, ...rawArgs].map(quoteWindowsArg).join(' '), {\n env: spawnEnv,\n stdio,\n shell: true,\n // Without this every MCP server spawned from a console-less host\n // (WebUI server, scheduled runs) opens a visible console window.\n windowsHide: true,\n })\n : spawn(this.opts.command, rawArgs, { env: spawnEnv, stdio, windowsHide: true });\n this.child = child;\n\n child.stdout?.on('data', (chunk: Buffer) => this.onData(chunk.toString()));\n child.stderr?.on('data', () => {\n // intentionally discard stderr noise from server\n });\n child.stdin?.on('error', (err: Error) => {\n // Pipe failures such as EPIPE are emitted asynchronously by Writable;\n // the try/catch around stdin.write() cannot intercept them. Always own\n // the stream error so a child that exits during startup rejects pending\n // requests instead of surfacing as an uncaught process exception.\n this.failPending(`MCP \"${this.opts.name}\" stdin error: ${toErrorMessage(err)}`);\n });\n child.on('exit', (code, signal) => {\n this.state = 'disconnected';\n // Reject any in-flight JSON-RPC requests \u2014 without this, callers\n // (e.g. callTool during a tool invocation) await forever on a child\n // that has already gone away.\n this.failPending(\n `MCP \"${this.opts.name}\" child exited (code=${code ?? 'null'} signal=${signal ?? 'null'})`,\n );\n for (const listener of this.exitListeners) {\n try {\n listener(this.opts.name, code, signal);\n } catch {\n /* ignore */\n }\n }\n });\n child.on('error', (err: Error) => {\n this.state = 'failed';\n // Spawn/runtime errors (ENOENT, EACCES, ...) can fire *after* the child\n // handle exists but often without a matching 'exit' event. Without\n // failing in-flight requests here, callers awaiting the startup\n // `initialize` (or any tools/call) hang until their timeout instead of\n // rejecting promptly.\n this.failPending(`MCP \"${this.opts.name}\" child error: ${toErrorMessage(err)}`);\n });\n\n const initialize = await this.request(\n 'initialize',\n {\n protocolVersion: MCP_CONSTANTS.PROTOCOL_VERSION,\n capabilities: { tools: {} },\n clientInfo: MCP_CONSTANTS.CLIENT_INFO,\n },\n this.opts.startupTimeoutMs ?? 10_000,\n );\n if (initialize.error) {\n this.state = 'failed';\n throw new Error(`MCP initialize failed: ${initialize.error.message}`);\n }\n try {\n this._serverMetadata = parseServerMetadata(initialize.result);\n } catch (err) {\n this.state = 'failed';\n throw new Error(`MCP initialize returned malformed server metadata: ${toErrorMessage(err)}`);\n }\n try {\n await this.notify('notifications/initialized', {});\n } catch (err) {\n console.warn(\n '[MCP] notify(\"notifications/initialized\") failed for \"' +\n this.opts.name +\n '\": ' +\n toErrorMessage(err),\n );\n }\n const toolsRes = await this.request('tools/list', {});\n if (toolsRes.error) {\n this._tools = [];\n } else {\n const result = toolsRes.result as { tools?: MCPTool[] | undefined } | undefined;\n this._tools = normalizeMCPTools(result?.tools);\n }\n // Cache tools so reconnect can re-register without re-discovering\n this._toolsCache = this._tools;\n this.state = 'connected';\n }\n\n private async connectSSE(): Promise<void> {\n if (!this.opts.url) {\n this.state = 'failed';\n throw new Error('MCP SSE transport requires \"url\"');\n }\n const httpOpts: HttpTransportOptions = {\n name: this.opts.name,\n url: this.opts.url,\n headers: this.opts.headers,\n startupTimeoutMs: this.opts.startupTimeoutMs,\n requestTimeoutMs: this.opts.requestTimeoutMs,\n authorizationProvider: this.opts.authorizationProvider,\n };\n this.sseTransport = new SSETransport(httpOpts);\n this.sseTransport.onDisconnect(() => {\n this.state = 'disconnected';\n for (const cb of this.disconnectListeners) {\n try {\n cb();\n } catch {\n /* ignore */\n }\n }\n });\n this.sseTransport.onToolsChanged((tools) => {\n this._tools = tools;\n // Keep the reconnect-recovery cache in sync. Without this, an empty\n // tools update would leave `_toolsCache` pointing at the previous\n // non-empty list, and `listTools()` would serve the stale cache\n // (since it falls back to the cache when `_tools` is empty).\n this._toolsCache = tools;\n for (const cb of this.toolsChangedListeners) {\n try {\n cb(this.opts.name, tools);\n } catch {\n /* ignore */\n }\n }\n });\n this.sseTransport.onResourcesChanged(() => this.emitCapabilityChanged('resources'));\n this.sseTransport.onPromptsChanged(() => this.emitCapabilityChanged('prompts'));\n try {\n await this.sseTransport.connect();\n } catch (err) {\n // Tear down the partial transport deterministically: its SSE read\n // loop is async-running on a `ReadableStreamDefaultReader`, and its\n // `AbortController` is wired into the connect-time startup timer.\n // Without this close(), the reader can keep the response body alive\n // until GC. The transport is fresh (never reached the success\n // path), so close() is safe and idempotent.\n const t = this.sseTransport;\n this.sseTransport = undefined;\n await t.close().catch(() => {\n /* best-effort cleanup */\n });\n this.state = 'failed';\n throw err;\n }\n this._tools = this.sseTransport.listTools();\n this._toolsCache = this._tools;\n this._serverMetadata = this.sseTransport.getServerMetadata();\n this.state = 'connected';\n }\n\n private async connectStreamableHTTP(): Promise<void> {\n if (!this.opts.url) {\n this.state = 'failed';\n throw new Error('MCP streamable-http transport requires \"url\"');\n }\n const httpOpts: HttpTransportOptions = {\n name: this.opts.name,\n url: this.opts.url,\n headers: this.opts.headers,\n startupTimeoutMs: this.opts.startupTimeoutMs,\n requestTimeoutMs: this.opts.requestTimeoutMs,\n authorizationProvider: this.opts.authorizationProvider,\n };\n this.httpTransport = new StreamableHTTPTransport(httpOpts);\n this.httpTransport.onDisconnect(() => {\n this.state = 'disconnected';\n for (const cb of this.disconnectListeners) {\n try {\n cb();\n } catch {\n /* ignore */\n }\n }\n });\n this.httpTransport.onToolsChanged((tools) => {\n this._tools = tools;\n // Same cache-sync reasoning as the SSE branch above \u2014 keep\n // `_toolsCache` in lockstep with `_tools` on every transport\n // update so the empty-list fallback in `listTools()` never serves\n // stale data.\n this._toolsCache = tools;\n for (const cb of this.toolsChangedListeners) {\n try {\n cb(this.opts.name, tools);\n } catch {\n /* ignore */\n }\n }\n });\n this.httpTransport.onResourcesChanged(() => this.emitCapabilityChanged('resources'));\n this.httpTransport.onPromptsChanged(() => this.emitCapabilityChanged('prompts'));\n try {\n await this.httpTransport.connect();\n } catch (err) {\n // Same teardown reasoning as the SSE branch \u2014 the partial transport's\n // `AbortController` and any in-flight header/state would otherwise\n // outlive this client instance until GC.\n const t = this.httpTransport;\n this.httpTransport = undefined;\n await t.close().catch(() => {\n /* best-effort cleanup */\n });\n this.state = 'failed';\n throw err;\n }\n this._tools = this.httpTransport.listTools();\n this._toolsCache = this._tools;\n this._serverMetadata = this.httpTransport.getServerMetadata();\n this.state = 'connected';\n }\n\n async callTool(\n name: string,\n input: unknown,\n opts?: { signal?: AbortSignal | undefined },\n ): Promise<ToolCallResult> {\n if (this.state !== 'connected') {\n throw new Error(`MCP client \"${this.opts.name}\" not connected (state=${this.state})`);\n }\n // Delegate to the active transport\n if (this.sseTransport) {\n return this.sseTransport.callTool(name, input, opts);\n }\n if (this.httpTransport) {\n return this.httpTransport.callTool(name, input, opts);\n }\n // stdio\n const res = await this.request('tools/call', { name, arguments: input }, undefined, opts);\n if (res.error) {\n return { content: res.error.message, isError: true };\n }\n const result = res.result as\n | { content?: unknown | undefined; isError?: boolean | undefined }\n | undefined;\n return {\n content: result?.content ?? '',\n isError: Boolean(result?.isError),\n };\n }\n\n async listResources(opts: MCPPageOptions = {}): Promise<MCPListResourcesResult> {\n const params = pageParams(opts.cursor, 'resources/list cursor');\n return this.requestCapability(\n 'resources',\n 'resources/list',\n params,\n parseListResourcesResult,\n opts,\n );\n }\n\n async listResourceTemplates(opts: MCPPageOptions = {}): Promise<MCPListResourceTemplatesResult> {\n const params = pageParams(opts.cursor, 'resources/templates/list cursor');\n return this.requestCapability(\n 'resources',\n 'resources/templates/list',\n params,\n parseListResourceTemplatesResult,\n opts,\n );\n }\n\n async readResource(uri: string, opts: MCPRequestOptions = {}): Promise<MCPReadResourceResult> {\n validateProtocolString(uri, 'resource URI');\n return this.requestCapability(\n 'resources',\n 'resources/read',\n { uri },\n parseReadResourceResult,\n opts,\n );\n }\n\n async subscribeResource(uri: string, opts: MCPRequestOptions = {}): Promise<void> {\n validateProtocolString(uri, 'resource URI');\n this.requireResourceSubscriptions('resources/subscribe');\n await this.requestCapability(\n 'resources',\n 'resources/subscribe',\n { uri },\n parseEmptyResult,\n opts,\n );\n }\n\n async unsubscribeResource(uri: string, opts: MCPRequestOptions = {}): Promise<void> {\n validateProtocolString(uri, 'resource URI');\n this.requireResourceSubscriptions('resources/unsubscribe');\n await this.requestCapability(\n 'resources',\n 'resources/unsubscribe',\n { uri },\n parseEmptyResult,\n opts,\n );\n }\n\n async listPrompts(opts: MCPPageOptions = {}): Promise<MCPListPromptsResult> {\n const params = pageParams(opts.cursor, 'prompts/list cursor');\n return this.requestCapability('prompts', 'prompts/list', params, parseListPromptsResult, opts);\n }\n\n async getPrompt(\n name: string,\n args?: Record<string, string> | undefined,\n opts: MCPRequestOptions = {},\n ): Promise<MCPGetPromptResult> {\n validateProtocolString(name, 'prompt name');\n if (args && Object.keys(args).length > 64) {\n throw new Error('MCP prompt arguments exceed the limit of 64');\n }\n for (const [key, value] of Object.entries(args ?? {})) {\n validateProtocolString(key, 'prompt argument name');\n validateProtocolString(value, `prompt argument \"${key}\"`, true);\n }\n return this.requestCapability(\n 'prompts',\n 'prompts/get',\n args === undefined ? { name } : { name, arguments: args },\n parseGetPromptResult,\n opts,\n );\n }\n\n async close(): Promise<void> {\n if (this.child) {\n const child = this.child;\n // Always register the listener first. Checking exitCode/signalCode\n // before registering creates a TOCTOU race: the child can exit between\n // the check and child.once('exit', ...), so the listener never fires\n // and exitPromise hangs forever. The double-check below handles the\n // case where the child already exited before we registered.\n const exitPromise = new Promise<void>((resolve) => {\n child.once('exit', () => resolve());\n if (child.exitCode !== null || child.signalCode !== null) resolve();\n });\n try {\n // Initial SIGTERM lets the server flush logs / clean up sockets.\n child.kill();\n } catch {\n // ignore\n }\n // Wait briefly for graceful exit, then escalate to SIGKILL. A stuck\n // server that ignores SIGTERM would otherwise stay alive after\n // close() returns \u2014 orphan child processes accumulate over restarts.\n const GRACEFUL_MS = 800;\n const FORCE_TIMEOUT_MS = 1200;\n const gracefulRace = await Promise.race([\n exitPromise.then(() => 'exited' as const),\n new Promise<'timeout'>((resolve) => setTimeout(() => resolve('timeout'), GRACEFUL_MS)),\n ]);\n if (gracefulRace === 'timeout') {\n try {\n // SIGKILL is ignored by `kill('SIGKILL')` on Windows in older\n // Node, but `child.kill('SIGKILL')` maps to TerminateProcess\n // under the hood for spawned children since Node 18 \u2014 safe to\n // call cross-platform.\n child.kill('SIGKILL');\n } catch {\n // ignore\n }\n await Promise.race([\n exitPromise,\n new Promise<void>((resolve) => setTimeout(resolve, FORCE_TIMEOUT_MS)),\n ]);\n }\n }\n // Reject pending requests BEFORE closing transports. This matters for\n // in-flight HTTP requests: they are not yet in `this.pending` (waiting\n // for a response from the network), so failPending() must run while the\n // transport is still alive. After this, the transport close is safe to\n // call even on a never-started or HTTP-only client \u2014 the exit handler\n // may have already run failPending, but calling it again with the same\n // pending set is a no-op (failPending guards on `this.pending.size`).\n this.failPending(`MCP \"${this.opts.name}\" closed`);\n this.sseTransport?.close();\n this.httpTransport?.close();\n this.state = 'disconnected';\n }\n\n private request(\n method: string,\n params: unknown,\n timeoutMs = this.opts.requestTimeoutMs ?? 60_000,\n opts?: { signal?: AbortSignal | undefined },\n ): Promise<JsonRpcResponse> {\n // For HTTP transports, delegate to the transport's request method.\n // SSE and streamable-http both use postRaw which handles the full\n // round-trip including timeout signal.\n if (this.sseTransport) return this.sseTransport.request(method, params, timeoutMs, opts);\n if (this.httpTransport) return this.httpTransport.request(method, params, timeoutMs, opts);\n\n // stdio path\n const signal = opts?.signal;\n if (signal?.aborted) {\n const err = new Error(`MCP \"${this.opts.name}\" request \"${method}\" aborted before send`);\n err.name = 'AbortError';\n return Promise.reject(err);\n }\n const id = this.nextId++;\n const req: JsonRpcRequest = { jsonrpc: '2.0', id, method, params };\n return new Promise((resolve, reject) => {\n // Abort support: drop the pending entry, notify the server per the MCP\n // cancellation spec (`notifications/cancelled`, best-effort \u2014 the\n // server SHOULD stop processing), and surface an AbortError so the\n // executor classifies it as user cancellation (never retried).\n const onAbort = signal\n ? () => {\n const pending = this.pending.get(id);\n this.pending.delete(id);\n if (pending) clearTimeout(pending.timer);\n void this.notify('notifications/cancelled', {\n requestId: id,\n reason: 'client aborted',\n }).catch(() => {\n /* best-effort \u2014 the child may already be gone */\n });\n const err = new Error(`MCP \"${this.opts.name}\" request \"${method}\" aborted by client`);\n err.name = 'AbortError';\n reject(err);\n }\n : undefined;\n if (signal && onAbort) signal.addEventListener('abort', onAbort, { once: true });\n const detach = () => {\n if (signal && onAbort) signal.removeEventListener('abort', onAbort);\n };\n const timer = setTimeout(() => {\n this.pending.delete(id);\n detach();\n reject(\n new Error(`MCP \"${this.opts.name}\" request \"${method}\" timed out after ${timeoutMs}ms`),\n );\n }, timeoutMs);\n this.pending.set(id, {\n resolve: (res) => {\n clearTimeout(timer);\n detach();\n resolve(res);\n },\n reject: (err) => {\n clearTimeout(timer);\n detach();\n reject(err);\n },\n timer,\n });\n const stdin = this.child?.stdin;\n if (!stdin || stdin.destroyed) {\n // No writable stdin (child never spawned, already exited, or stream\n // destroyed). Reject immediately instead of leaving the request\n // pending until it times out.\n const pending = this.pending.get(id);\n this.pending.delete(id);\n if (pending) clearTimeout(pending.timer);\n detach();\n reject(new Error(`MCP \"${this.opts.name}\" request \"${method}\": stdin not writable`));\n return;\n }\n try {\n stdin.write(JSON.stringify(req) + '\\n');\n } catch (err) {\n const pending = this.pending.get(id);\n this.pending.delete(id);\n if (pending) clearTimeout(pending.timer);\n detach();\n reject(err);\n }\n });\n }\n\n private async requestCapability<T>(\n capability: 'resources' | 'prompts',\n method: string,\n params: unknown,\n parse: (value: unknown) => T,\n opts: MCPRequestOptions,\n ): Promise<T> {\n if (this.state !== 'connected') {\n throw new Error(`MCP client \"${this.opts.name}\" not connected (state=${this.state})`);\n }\n const metadata = this._serverMetadata;\n if (!metadata) {\n throw new Error(\n `MCP server \"${this.opts.name}\" capability metadata is unavailable for ${method}`,\n );\n }\n if (!metadata.capabilities[capability]) {\n throw new Error(\n `MCP server \"${this.opts.name}\" does not advertise the ${capability} capability`,\n );\n }\n const response = await this.request(method, params, undefined, opts);\n if (response.error) {\n throw new Error(`MCP ${method} failed: ${response.error.message}`);\n }\n return parse(response.result);\n }\n\n private requireResourceSubscriptions(method: string): void {\n if (this.state !== 'connected') {\n throw new Error(`MCP client \"${this.opts.name}\" not connected (state=${this.state})`);\n }\n if (this._serverMetadata?.capabilities.resources?.subscribe !== true) {\n throw new Error(\n `MCP server \"${this.opts.name}\" does not advertise resource subscriptions for ${method}`,\n );\n }\n }\n\n /**\n * Reject every in-flight {@link request} call. Used when the underlying\n * transport dies \u2014 without this, callers awaiting `tools/call` over a\n * killed stdio child or a closed transport would hang indefinitely.\n */\n private failPending(reason: string): void {\n if (this.pending.size === 0) return;\n const err = new Error(reason);\n for (const [, entry] of this.pending) {\n try {\n clearTimeout(entry.timer);\n entry.reject(err);\n } catch {\n /* ignore */\n }\n }\n this.pending.clear();\n }\n\n private async notify(method: string, params: unknown): Promise<void> {\n const req = { jsonrpc: '2.0', method, params };\n const encoded = JSON.stringify(req) + '\\n';\n try {\n const ok = this.child?.stdin?.write(encoded);\n if (!ok) {\n // Only the first caller waits for drain; others just warn and return.\n // This avoids a race where two concurrent notify() calls each start\n // their own drain-wait, then both resolve and the buffer is still full.\n if (this._drainPending) {\n this._lastNotifySkipped = true;\n console.warn(\n JSON.stringify({\n level: 'warn',\n event: 'mcp.notify_skipped_backpressure',\n server: this.opts.name,\n method,\n message: 'stdin buffer backpressure (already waiting for drain)',\n timestamp: new Date().toISOString(),\n }),\n );\n return;\n }\n this._drainPending = true;\n await new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => {\n this.child?.stdin?.removeListener?.('drain', onDrain);\n this.child?.stdin?.removeListener?.('error', onError);\n this._drainPending = false;\n reject(new Error(`MCP notify(\"${method}\") drain timeout`));\n }, 500);\n const onDrain = () => {\n clearTimeout(timeout);\n this.child?.stdin?.removeListener?.('drain', onDrain);\n this.child?.stdin?.removeListener?.('error', onError);\n this._drainPending = false;\n resolve();\n };\n const onError = (err: Error) => {\n clearTimeout(timeout);\n this.child?.stdin?.removeListener?.('drain', onDrain);\n this.child?.stdin?.removeListener?.('error', onError);\n this._drainPending = false;\n reject(err);\n };\n this.child?.stdin?.once('drain', onDrain);\n this.child?.stdin?.once('error', onError);\n });\n }\n } catch (err) {\n throw new Error(`[MCP] notify(\"${method}\") failed: ${toErrorMessage(err)}`);\n }\n }\n\n private onData(s: string): void {\n this.rxBuffer += s;\n\n // Guard against a malicious or buggy server that never emits a newline \u2014\n // without this cap the buffer grows without limit and OOMs the process.\n if (this.rxBuffer.length > MCPClient.MAX_RX_BUFFER_BYTES) {\n const truncated = this.rxBuffer.length;\n this.rxBuffer = '';\n this.failPending(\n `MCP \"${this.opts.name}\" rx buffer overflow (${truncated} bytes without a newline) \u2014 closing connection`,\n );\n void this.close();\n return;\n }\n\n let idx = this.rxBuffer.indexOf('\\n');\n while (idx !== -1) {\n const line = this.rxBuffer.slice(0, idx).trim();\n this.rxBuffer = this.rxBuffer.slice(idx + 1);\n if (line) this.onLine(line);\n idx = this.rxBuffer.indexOf('\\n');\n }\n }\n\n private onLine(line: string): void {\n let msg: unknown;\n try {\n msg = JSON.parse(line);\n } catch {\n return;\n }\n\n if (typeof msg !== 'object' || msg === null) return;\n const envelope = msg as Record<string, unknown>;\n if (envelope['jsonrpc'] !== '2.0') return;\n\n // A server request is never a response, even if its id collides with one\n // of our pending calls. Resolve pending calls only after the envelope has\n // passed the strict response guard below.\n if (typeof envelope['method'] === 'string') {\n const id = envelope['id'];\n if (typeof id === 'number' || typeof id === 'string') {\n this.handleServerRequest({\n jsonrpc: '2.0',\n id,\n method: envelope['method'],\n params: envelope['params'],\n });\n return;\n }\n\n // Notifications have a `method` but no `id`. The MCP spec defines\n // list_changed notifications for cache invalidation.\n if (Object.hasOwn(envelope, 'id')) return;\n if (envelope['method'] === 'notifications/tools/list_changed') {\n void this.handleToolsListChanged();\n } else if (envelope['method'] === 'notifications/resources/list_changed') {\n this.emitCapabilityChanged('resources');\n } else if (envelope['method'] === 'notifications/prompts/list_changed') {\n this.emitCapabilityChanged('prompts');\n }\n return;\n }\n\n if (!isJsonRpcResponse(msg)) return;\n if (this.pending.has(msg.id)) {\n const entry = this.pending.get(msg.id);\n this.pending.delete(msg.id);\n entry?.resolve(msg);\n }\n }\n\n private handleServerRequest(request: JsonRpcServerRequest): void {\n const message =\n request.method === 'sampling/createMessage'\n ? 'Client sampling is disabled by policy'\n : `Method not found: ${request.method}`;\n const response = {\n jsonrpc: '2.0',\n id: request.id,\n error: { code: -32601, message },\n };\n\n try {\n this.child?.stdin?.write(`${JSON.stringify(response)}\\n`);\n } catch {\n // Best-effort protocol reply. A closed stdio stream is handled by the\n // normal child-exit path, which also rejects every pending client call.\n }\n }\n\n /**\n * L2-C: refresh the cached tool list when the server announces a\n * `tools/list_changed`. Listeners (the registry) re-wrap and\n * re-register. Failures are swallowed \u2014 a stale cache is preferable\n * to a hard crash on a transient notification glitch.\n */\n private async handleToolsListChanged(): Promise<void> {\n try {\n const toolsRes = await this.request('tools/list', {});\n const tools = normalizeMCPTools(\n (toolsRes.result as { tools?: unknown | undefined } | undefined)?.tools,\n );\n this._tools = tools;\n this._toolsCache = tools;\n for (const listener of this.toolsChangedListeners) {\n try {\n listener(this.opts.name, [...tools]);\n } catch {\n // listeners must be best-effort\n }\n }\n } catch {\n // ignore \u2014 keep the existing cache\n }\n }\n\n addToolsChangedListener(listener: ToolsChangedListener): void {\n this.toolsChangedListeners.add(listener);\n }\n\n removeToolsChangedListener(listener: ToolsChangedListener): void {\n this.toolsChangedListeners.delete(listener);\n }\n\n addResourcesChangedListener(listener: MCPListChangedListener): void {\n this.resourcesChangedListeners.add(listener);\n }\n\n removeResourcesChangedListener(listener: MCPListChangedListener): void {\n this.resourcesChangedListeners.delete(listener);\n }\n\n addPromptsChangedListener(listener: MCPListChangedListener): void {\n this.promptsChangedListeners.add(listener);\n }\n\n removePromptsChangedListener(listener: MCPListChangedListener): void {\n this.promptsChangedListeners.delete(listener);\n }\n\n private emitCapabilityChanged(capability: 'resources' | 'prompts'): void {\n const listeners =\n capability === 'resources' ? this.resourcesChangedListeners : this.promptsChangedListeners;\n for (const listener of listeners) {\n try {\n listener(this.opts.name);\n } catch {\n /* listeners are best-effort */\n }\n }\n }\n}\n\n/**\n * Quote a single argument for `cmd.exe` when spawning with `shell: true` on\n * Windows. Only args containing whitespace or quotes need wrapping; inside\n * double quotes cmd.exe escapes a literal `\"` as `\"\"`. Backslashes are literal\n * inside cmd quotes, so paths like `C:\\Program Files\\x` pass through unharmed.\n */\nexport function quoteWindowsArg(arg: string): string {\n if (!/[\\s\"]/.test(arg)) return arg;\n return `\"${arg.replace(/\"/g, '\"\"')}\"`;\n}\n\nconst MAX_PROTOCOL_INPUT_CHARS = 8_192;\n\nfunction validateProtocolString(\n value: unknown,\n label: string,\n allowEmpty = false,\n): asserts value is string {\n if (typeof value !== 'string' || (!allowEmpty && value.length === 0)) {\n throw new Error(`MCP ${label} must be ${allowEmpty ? 'a string' : 'a non-empty string'}`);\n }\n if (value.length > MAX_PROTOCOL_INPUT_CHARS) {\n throw new Error(`MCP ${label} exceeds ${MAX_PROTOCOL_INPUT_CHARS} characters`);\n }\n}\n\nfunction pageParams(cursor: string | undefined, label: string): Record<string, string> {\n if (cursor === undefined) return {};\n validateProtocolString(cursor, label);\n return { cursor };\n}\n\nfunction parseEmptyResult(value: unknown): void {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error('Malformed MCP empty result: expected object');\n }\n}\n", "/**\n * Shared constants for the MCP package.\n *\n * Centralizing these values means:\n * - Protocol version and client identity are updated in one place\n * - Reconnect parameters can be overridden via config in the future\n * - No scattered magic values across multiple files\n */\nexport const MCP_CONSTANTS = Object.freeze({\n /** MCP protocol version advertised during handshake. */\n PROTOCOL_VERSION: '2024-11-05',\n\n /** Identity announced to MCP servers during `initialize`. */\n CLIENT_INFO: Object.freeze({\n name: 'wrongstack',\n version: '0.1.10',\n }),\n\n /** Reconnection behaviour when a transport disconnects. */\n RECONNECT: Object.freeze({\n /** Max full reconnect cycles before the slot is marked `failed`. */\n MAX_CYCLES: 5,\n /** Base delay between cycles (exponential backoff applied on top). */\n BASE_DELAY_MS: 1000,\n /** Jitter factor applied to the backoff (0 = no jitter, 1 = full). */\n JITTER_FACTOR: 0.2,\n /** Max connection attempts within a single cycle. */\n MAX_ATTEMPTS: 3,\n /** Base multiplier for the exponential backoff formula (`delay = BASE * multiplier^attempt`). */\n BACKOFF_MULTIPLIER: 2,\n }),\n\n /** Timing for graceful / forced disconnect. */\n DISCONNECT: Object.freeze({\n /** Ms to wait for in-flight requests to complete before force-closing. */\n GRACEFUL_MS: 800,\n /** Ms after which the force disconnect is triggered. */\n FORCE_TIMEOUT_MS: 1200,\n }),\n\n /** Lazy-connect idle lifecycle. */\n IDLE: Object.freeze({\n /** Default ms a lazy server stays connected with no tool calls before auto-sleep. */\n DEFAULT_TIMEOUT_MS: 300_000,\n /** How often the idle sweep runs (kept well below the timeout). */\n SWEEP_INTERVAL_MS: 30_000,\n }),\n\n /** JSON-RPC response timeout for outstanding requests. */\n RESPONSE_TIMEOUT_MS: 500,\n\n /** Max buffer size for the SSE reader. */\n SSE_READER_MAX_BUFFER: 256 * 1024,\n\n /** Max characters logged from a request body. */\n REQUEST_LOG_CAP: 1024,\n} as const);", "/** Typed MCP protocol surface for server discovery, resources, and prompts. */\n\nexport interface MCPImplementationInfo {\n name: string;\n version: string;\n title?: string | undefined;\n}\n\nexport interface MCPServerCapabilities {\n tools?: { listChanged?: boolean | undefined } | undefined;\n resources?: { subscribe?: boolean | undefined; listChanged?: boolean | undefined } | undefined;\n prompts?: { listChanged?: boolean | undefined } | undefined;\n logging?: Record<string, never> | undefined;\n [capability: string]: unknown;\n}\n\nexport interface MCPServerMetadata {\n protocolVersion: string;\n capabilities: MCPServerCapabilities;\n serverInfo: MCPImplementationInfo;\n instructions?: string | undefined;\n}\n\nexport interface MCPResource {\n uri: string;\n name: string;\n title?: string | undefined;\n description?: string | undefined;\n mimeType?: string | undefined;\n size?: number | undefined;\n annotations?: Record<string, unknown> | undefined;\n}\n\nexport interface MCPResourceTemplate {\n uriTemplate: string;\n name: string;\n title?: string | undefined;\n description?: string | undefined;\n mimeType?: string | undefined;\n annotations?: Record<string, unknown> | undefined;\n}\n\nexport interface MCPResourceContents {\n uri: string;\n mimeType?: string | undefined;\n text?: string | undefined;\n blob?: string | undefined;\n}\n\nexport interface MCPPromptArgument {\n name: string;\n description?: string | undefined;\n required?: boolean | undefined;\n}\n\nexport interface MCPPrompt {\n name: string;\n title?: string | undefined;\n description?: string | undefined;\n arguments?: MCPPromptArgument[] | undefined;\n}\n\nexport interface MCPPromptMessage {\n role: 'user' | 'assistant';\n /** Preserve text, image, audio, embedded-resource, and resource-link blocks. */\n content: unknown;\n}\n\nexport interface MCPListResourcesResult {\n resources: MCPResource[];\n nextCursor?: string | undefined;\n}\n\nexport interface MCPListResourceTemplatesResult {\n resourceTemplates: MCPResourceTemplate[];\n nextCursor?: string | undefined;\n}\n\nexport interface MCPReadResourceResult {\n contents: MCPResourceContents[];\n}\n\nexport interface MCPListPromptsResult {\n prompts: MCPPrompt[];\n nextCursor?: string | undefined;\n}\n\nexport interface MCPGetPromptResult {\n description?: string | undefined;\n messages: MCPPromptMessage[];\n}\n\nfunction record(value: unknown, label: string): Record<string, unknown> {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error(`Malformed MCP ${label}: expected object`);\n }\n return value as Record<string, unknown>;\n}\n\nfunction requiredString(value: unknown, label: string): string {\n if (typeof value !== 'string' || value.length === 0) {\n throw new Error(`Malformed MCP ${label}: expected non-empty string`);\n }\n return value;\n}\n\nfunction optionalString(value: unknown, label: string): string | undefined {\n if (value === undefined) return undefined;\n if (typeof value !== 'string') throw new Error(`Malformed MCP ${label}: expected string`);\n return value;\n}\n\nfunction optionalRecord(value: unknown, label: string): Record<string, unknown> | undefined {\n if (value === undefined) return undefined;\n return record(value, label);\n}\n\nfunction optionalCursor(value: unknown, label: string): string | undefined {\n return optionalString(value, `${label}.nextCursor`);\n}\n\nexport function parseServerMetadata(value: unknown): MCPServerMetadata {\n const input = record(value, 'initialize result');\n const serverInfo = record(input['serverInfo'], 'initialize.serverInfo');\n const capabilities = record(input['capabilities'], 'initialize.capabilities');\n return {\n protocolVersion: requiredString(input['protocolVersion'], 'initialize.protocolVersion'),\n capabilities: capabilities as MCPServerCapabilities,\n serverInfo: {\n name: requiredString(serverInfo['name'], 'initialize.serverInfo.name'),\n version: requiredString(serverInfo['version'], 'initialize.serverInfo.version'),\n title: optionalString(serverInfo['title'], 'initialize.serverInfo.title'),\n },\n instructions: optionalString(input['instructions'], 'initialize.instructions'),\n };\n}\n\nfunction parseResource(value: unknown, index: number): MCPResource {\n const input = record(value, `resources/list.resources[${index}]`);\n const size = input['size'];\n if (size !== undefined && (typeof size !== 'number' || !Number.isFinite(size) || size < 0)) {\n throw new Error(`Malformed MCP resources/list.resources[${index}].size`);\n }\n return {\n uri: requiredString(input['uri'], `resources/list.resources[${index}].uri`),\n name: requiredString(input['name'], `resources/list.resources[${index}].name`),\n title: optionalString(input['title'], `resources/list.resources[${index}].title`),\n description: optionalString(\n input['description'],\n `resources/list.resources[${index}].description`,\n ),\n mimeType: optionalString(input['mimeType'], `resources/list.resources[${index}].mimeType`),\n size: size as number | undefined,\n annotations: optionalRecord(\n input['annotations'],\n `resources/list.resources[${index}].annotations`,\n ),\n };\n}\n\nexport function parseListResourcesResult(value: unknown): MCPListResourcesResult {\n const input = record(value, 'resources/list result');\n if (!Array.isArray(input['resources'])) {\n throw new Error('Malformed MCP resources/list result: resources must be an array');\n }\n return {\n resources: input['resources'].map(parseResource),\n nextCursor: optionalCursor(input['nextCursor'], 'resources/list'),\n };\n}\n\nexport function parseListResourceTemplatesResult(value: unknown): MCPListResourceTemplatesResult {\n const input = record(value, 'resources/templates/list result');\n const templates = input['resourceTemplates'];\n if (!Array.isArray(templates)) {\n throw new Error(\n 'Malformed MCP resources/templates/list result: resourceTemplates must be an array',\n );\n }\n return {\n resourceTemplates: templates.map((value, index) => {\n const template = record(value, `resources/templates/list.resourceTemplates[${index}]`);\n return {\n uriTemplate: requiredString(\n template['uriTemplate'],\n `resources/templates/list.resourceTemplates[${index}].uriTemplate`,\n ),\n name: requiredString(\n template['name'],\n `resources/templates/list.resourceTemplates[${index}].name`,\n ),\n title: optionalString(\n template['title'],\n `resources/templates/list.resourceTemplates[${index}].title`,\n ),\n description: optionalString(\n template['description'],\n `resources/templates/list.resourceTemplates[${index}].description`,\n ),\n mimeType: optionalString(\n template['mimeType'],\n `resources/templates/list.resourceTemplates[${index}].mimeType`,\n ),\n annotations: optionalRecord(\n template['annotations'],\n `resources/templates/list.resourceTemplates[${index}].annotations`,\n ),\n };\n }),\n nextCursor: optionalCursor(input['nextCursor'], 'resources/templates/list'),\n };\n}\n\nexport function parseReadResourceResult(value: unknown): MCPReadResourceResult {\n const input = record(value, 'resources/read result');\n if (!Array.isArray(input['contents'])) {\n throw new Error('Malformed MCP resources/read result: contents must be an array');\n }\n return {\n contents: input['contents'].map((value, index) => {\n const content = record(value, `resources/read.contents[${index}]`);\n const text = optionalString(content['text'], `resources/read.contents[${index}].text`);\n const blob = optionalString(content['blob'], `resources/read.contents[${index}].blob`);\n if (text === undefined && blob === undefined) {\n throw new Error(`Malformed MCP resources/read.contents[${index}]: expected text or blob`);\n }\n return {\n uri: requiredString(content['uri'], `resources/read.contents[${index}].uri`),\n mimeType: optionalString(content['mimeType'], `resources/read.contents[${index}].mimeType`),\n text,\n blob,\n };\n }),\n };\n}\n\nfunction parsePromptArgument(\n value: unknown,\n promptIndex: number,\n argIndex: number,\n): MCPPromptArgument {\n const input = record(value, `prompts/list.prompts[${promptIndex}].arguments[${argIndex}]`);\n const required = input['required'];\n if (required !== undefined && typeof required !== 'boolean') {\n throw new Error(\n `Malformed MCP prompts/list.prompts[${promptIndex}].arguments[${argIndex}].required`,\n );\n }\n return {\n name: requiredString(\n input['name'],\n `prompts/list.prompts[${promptIndex}].arguments[${argIndex}].name`,\n ),\n description: optionalString(\n input['description'],\n `prompts/list.prompts[${promptIndex}].arguments[${argIndex}].description`,\n ),\n required: required as boolean | undefined,\n };\n}\n\nexport function parseListPromptsResult(value: unknown): MCPListPromptsResult {\n const input = record(value, 'prompts/list result');\n if (!Array.isArray(input['prompts'])) {\n throw new Error('Malformed MCP prompts/list result: prompts must be an array');\n }\n return {\n prompts: input['prompts'].map((value, index) => {\n const prompt = record(value, `prompts/list.prompts[${index}]`);\n const args = prompt['arguments'];\n if (args !== undefined && !Array.isArray(args)) {\n throw new Error(`Malformed MCP prompts/list.prompts[${index}].arguments`);\n }\n return {\n name: requiredString(prompt['name'], `prompts/list.prompts[${index}].name`),\n title: optionalString(prompt['title'], `prompts/list.prompts[${index}].title`),\n description: optionalString(\n prompt['description'],\n `prompts/list.prompts[${index}].description`,\n ),\n arguments: args?.map((arg, argIndex) => parsePromptArgument(arg, index, argIndex)),\n };\n }),\n nextCursor: optionalCursor(input['nextCursor'], 'prompts/list'),\n };\n}\n\nexport function parseGetPromptResult(value: unknown): MCPGetPromptResult {\n const input = record(value, 'prompts/get result');\n if (!Array.isArray(input['messages'])) {\n throw new Error('Malformed MCP prompts/get result: messages must be an array');\n }\n return {\n description: optionalString(input['description'], 'prompts/get.description'),\n messages: input['messages'].map((value, index) => {\n const message = record(value, `prompts/get.messages[${index}]`);\n const role = message['role'];\n if (role !== 'user' && role !== 'assistant') {\n throw new Error(`Malformed MCP prompts/get.messages[${index}].role`);\n }\n if (message['content'] === undefined) {\n throw new Error(`Malformed MCP prompts/get.messages[${index}].content`);\n }\n return { role, content: message['content'] };\n }),\n };\n}\n", "import type { MCPTool } from './client.js';\n\nexport function normalizeMCPTools(value: unknown): MCPTool[] {\n if (!Array.isArray(value)) return [];\n const tools: MCPTool[] = [];\n for (const raw of value) {\n if (!raw || typeof raw !== 'object') continue;\n const t = raw as { name?: unknown | undefined; description?: unknown | undefined; inputSchema?: unknown | undefined };\n if (typeof t.name !== 'string' || t.name.trim().length === 0) continue;\n const inputSchema =\n t.inputSchema && typeof t.inputSchema === 'object' && !Array.isArray(t.inputSchema)\n ? (t.inputSchema as Record<string, unknown>)\n : { type: 'object', properties: {} };\n // Log when a tool's schema is absent or invalid \u2014 this could indicate a\n // broken, misbehaving, or (if the server is untrusted) adversarial MCP\n // server trying to confuse the LLM with misleading type info.\n if (!t.inputSchema || typeof t.inputSchema !== 'object' || Array.isArray(t.inputSchema)) {\n console.warn(JSON.stringify({\n level: 'warn',\n event: 'mcp.tool_schema_invalid',\n tool: t.name,\n message: 'no/invalid inputSchema \u2014 defaulting to empty object',\n timestamp: new Date().toISOString(),\n }));\n }\n tools.push({\n name: t.name,\n ...(typeof t.description === 'string' ? { description: t.description } : {}),\n inputSchema,\n });\n }\n return tools;\n}\n", "import { ToolError } from '@wrongstack/core/types';\n\nexport type JsonRpcResult = {\n jsonrpc: string;\n id?: number | undefined;\n result?: unknown | undefined;\n error?: { code: number | undefined; message: string; data?: unknown | undefined } | undefined;\n};\n\ntype JsonRpcMethodEnvelope = {\n jsonrpc: '2.0';\n id?: number | string | undefined;\n method: string;\n params?: unknown | undefined;\n};\n\ntype JsonRpcEnvelope = JsonRpcResult | JsonRpcMethodEnvelope;\n\nexport function isJsonRpcResult(v: unknown): v is JsonRpcResult {\n if (typeof v !== 'object' || v === null) return false;\n const r = v as Record<string, unknown>;\n if (r['jsonrpc'] !== '2.0' || typeof r['id'] !== 'number') return false;\n if (Object.hasOwn(r, 'method')) return false;\n\n const hasResult = Object.hasOwn(r, 'result');\n const hasError = Object.hasOwn(r, 'error');\n if (hasResult === hasError) return false;\n if (hasError) {\n const error = r['error'];\n return (\n typeof error === 'object' &&\n error !== null &&\n typeof (error as Record<string, unknown>)['code'] === 'number' &&\n typeof (error as Record<string, unknown>)['message'] === 'string'\n );\n }\n return true;\n}\n\nfunction isJsonRpcMethodEnvelope(v: unknown): v is JsonRpcMethodEnvelope {\n if (typeof v !== 'object' || v === null) return false;\n const envelope = v as Record<string, unknown>;\n if (envelope['jsonrpc'] !== '2.0' || typeof envelope['method'] !== 'string') return false;\n const id = envelope['id'];\n return id === undefined || typeof id === 'number' || typeof id === 'string';\n}\n\n/**\n * Extract JSON-RPC envelopes from a streamable-http response body. Handles BOTH\n * plain NDJSON (one JSON object per line) AND SSE framing\n * (`event: message\\ndata: {...}` blocks) \u2014 modern MCP servers (e.g. Context7)\n * reply with `text/event-stream` even on a single POST, so the data must be\n * un-prefixed before parsing. Multi-line `data:` values within one event are\n * joined per the SSE spec.\n */\nexport function extractJsonRpcEnvelopes(text: string): JsonRpcEnvelope[] {\n const out: JsonRpcEnvelope[] = [];\n let dataBuf: string[] = [];\n const flush = () => {\n if (dataBuf.length === 0) return;\n const joined = dataBuf.join('\\n').trim();\n dataBuf = [];\n if (!joined) return;\n try {\n const parsed = JSON.parse(joined);\n if (isJsonRpcResult(parsed) || isJsonRpcMethodEnvelope(parsed)) out.push(parsed);\n } catch {\n /* ignore non-JSON event data */\n }\n };\n for (const raw of text.split('\\n')) {\n const line = raw.replace(/\\r$/, '');\n if (line === '') {\n flush(); // blank line ends an SSE event\n continue;\n }\n if (line.startsWith(':')) continue; // SSE comment\n if (line.startsWith('data:')) {\n let v = line.slice(5);\n if (v.startsWith(' ')) v = v.slice(1);\n dataBuf.push(v);\n continue;\n }\n if (line.startsWith('event:') || line.startsWith('id:') || line.startsWith('retry:')) {\n continue; // other SSE fields\n }\n // Plain NDJSON line (no SSE framing).\n const trimmed = line.trim();\n if (trimmed.startsWith('{') || trimmed.startsWith('[')) {\n try {\n const parsed = JSON.parse(trimmed);\n if (isJsonRpcResult(parsed) || isJsonRpcMethodEnvelope(parsed)) out.push(parsed);\n } catch {\n /* ignore */\n }\n }\n }\n flush();\n return out;\n}\n\n/** Extract only response envelopes; notifications and server requests are not responses. */\nexport function extractJsonRpcResults(text: string): JsonRpcResult[] {\n return extractJsonRpcEnvelopes(text).filter(isJsonRpcResult);\n}\n\nexport function assertMatchingJsonRpcResult(\n data: unknown,\n expectedId: number,\n method: string,\n): JsonRpcResult {\n if (!isJsonRpcResult(data)) {\n throw new ToolError({\n message: 'Invalid JSON-RPC response: not a JSON-RPC 2.0 envelope',\n code: 'TOOL_EXECUTION_FAILED',\n toolName: 'mcp_transport_jsonrpc',\n context: { method, expectedId, reason: 'not-jsonrpc-envelope' },\n });\n }\n if (data.id !== expectedId) {\n throw new ToolError({\n message: `Invalid JSON-RPC response: id mismatch for ${method} (expected ${expectedId}, got ${data.id})`,\n code: 'TOOL_EXECUTION_FAILED',\n toolName: 'mcp_transport_jsonrpc',\n context: { method, expectedId, actualId: data.id, reason: 'id-mismatch' },\n });\n }\n return data;\n}\n", "import { ToolError } from '@wrongstack/core/types';\n\n/**\n * SSE-based MCP transport using native fetch.\n *\n * Communication pattern:\n * - Client connects to SSE endpoint to receive server messages (JSON-RPC events)\n * - Client sends JSON-RPC requests via HTTP POST to the same or separate endpoint\n * - Server sends results/errors via the SSE stream\n *\n * The SSE reader parses the SSE protocol (event:, data:, blank line to dispatch).\n */\n/**\n * Cap on the pending-line buffer. The upstream SSE parser\n * (packages/providers/src/sse.ts) already enforces 256 KB; this\n * reader is used only inside MCP HTTP transports, but defense-in-depth\n * says we should never let a malicious stream pin memory.\n */\nconst SSE_READER_MAX_BUFFER = 256 * 1024;\n/** Max data lines buffered per event before flush. Prevents a malicious\n * server from accumulating unbounded data: lines without a blank-line\n * delimiter would grow this array indefinitely. */\nconst SSE_READER_MAX_DATA_LINES = 1024;\n\nexport class SSEReader {\n private buffer = '';\n private dataLines: string[] = [];\n private listeners: Array<\n (event: {\n jsonrpc?: string | undefined;\n method?: string | undefined;\n params?: unknown | undefined;\n id?: number | undefined;\n }) => void\n > = [];\n\n onMessage(\n cb: (data: {\n jsonrpc?: string | undefined;\n method?: string | undefined;\n params?: unknown | undefined;\n id?: number | undefined;\n }) => void,\n ): () => void {\n this.listeners.push(cb);\n return () => {\n const idx = this.listeners.indexOf(cb);\n if (idx >= 0) this.listeners.splice(idx, 1);\n };\n }\n\n feed(chunk: string): void {\n // Guard against a single chunk that exceeds the buffer cap.\n if (chunk.length > SSE_READER_MAX_BUFFER) {\n throw new ToolError({\n message: `SSE: chunk size ${chunk.length} exceeds max buffer ${SSE_READER_MAX_BUFFER} \u2014 refusing to accumulate`,\n code: 'TOOL_EXECUTION_FAILED',\n toolName: 'mcp_transport_sse_reader',\n context: { phase: 'feed', chunkLength: chunk.length, maxBuffer: SSE_READER_MAX_BUFFER },\n });\n }\n this.buffer += chunk;\n if (this.buffer.length > SSE_READER_MAX_BUFFER) {\n throw new ToolError({\n message: `SSE: pending line exceeds ${SSE_READER_MAX_BUFFER} bytes \u2014 upstream is not framing events`,\n code: 'TOOL_EXECUTION_FAILED',\n toolName: 'mcp_transport_sse_reader',\n context: {\n phase: 'feed',\n bufferLength: this.buffer.length,\n maxBuffer: SSE_READER_MAX_BUFFER,\n },\n });\n }\n // Scan with a moving cursor and slice the retained tail ONCE at the end,\n // instead of `buffer = buffer.slice(idx+1)` per line (which re-copies the\n // whole remaining buffer for every newline \u2014 O(n\u00B2) for many small lines).\n let start = 0;\n let idx = this.buffer.indexOf('\\n', start);\n while (idx !== -1) {\n let end = idx;\n if (end > start && this.buffer.charCodeAt(end - 1) === 13 /* \\r */) end--;\n this.processLine(this.buffer.slice(start, end));\n start = idx + 1;\n idx = this.buffer.indexOf('\\n', start);\n }\n if (start > 0) this.buffer = this.buffer.slice(start);\n }\n\n private processLine(line: string): void {\n if (line === '') {\n this.flush();\n return;\n }\n if (line.startsWith(':')) return;\n\n const colonIdx = line.indexOf(':');\n const field = colonIdx === -1 ? line : line.slice(0, colonIdx);\n let value = colonIdx === -1 ? '' : line.slice(colonIdx + 1);\n if (value.startsWith(' ')) value = value.slice(1);\n\n if (field === 'event') {\n // The current transport only cares about JSON-RPC payloads in data\n // fields. Event names are accepted for spec compatibility.\n } else if (field === 'data') {\n if (this.dataLines.length >= SSE_READER_MAX_DATA_LINES) {\n throw new ToolError({\n message: `SSE: exceeded ${SSE_READER_MAX_DATA_LINES} data lines per event \u2014 upstream is not sending blank-line delimiters`,\n code: 'TOOL_EXECUTION_FAILED',\n toolName: 'mcp_transport_sse_reader',\n context: {\n phase: 'processLine',\n dataLineCount: this.dataLines.length,\n maxDataLines: SSE_READER_MAX_DATA_LINES,\n },\n });\n }\n this.dataLines.push(value);\n }\n }\n\n private flush(): void {\n if (this.dataLines.length === 0) {\n return;\n }\n const data = this.dataLines.join('\\n').trim();\n this.dataLines = [];\n if (!data) return;\n try {\n const parsed = JSON.parse(data) as {\n jsonrpc?: string | undefined;\n method?: string | undefined;\n params?: unknown | undefined;\n id?: number | undefined;\n };\n this.dispatch(parsed);\n } catch {\n // ignore parse errors\n }\n }\n\n private dispatch(msg: {\n jsonrpc?: string | undefined;\n method?: string | undefined;\n params?: unknown | undefined;\n id?: number | undefined;\n }): void {\n for (const cb of this.listeners) {\n try {\n cb(msg);\n } catch {\n /* ignore */\n }\n }\n }\n\n reset(): void {\n this.buffer = '';\n this.dataLines = [];\n this.listeners = [];\n }\n}\n", "import * as https from 'node:https';\nimport { ConfigError } from '@wrongstack/core/types';\nimport type { HttpDispatcher } from '@wrongstack/core/utils';\nimport {\n authorizationHeaderForToken,\n canonicalMcpResource,\n type MCPAuthorizationProvider,\n parseMcpBearerChallenge,\n} from './authorization.js';\nimport type { ConnectionState, MCPTool } from './client.js';\nimport type { MCPServerMetadata } from './protocol.js';\nimport { isTlsUnsafeAllowed, validateTransportUrl } from './transport-security.js';\n\nexport interface HttpTransportOptions {\n name: string;\n url: string;\n headers?: Record<string, string> | undefined;\n startupTimeoutMs?: number | undefined;\n requestTimeoutMs?: number | undefined;\n authorizationProvider?: MCPAuthorizationProvider | undefined;\n /**\n * Per-request TLS configuration. When set, an https.Agent is created\n * and passed to fetch via the `dispatch` option. This avoids globally\n * disabling certificate validation (NODE_TLS_REJECT_UNAUTHORIZED) which\n * would affect all provider API calls in the same process.\n *\n * \u26A0\uFE0F Security gate: `rejectUnauthorized: false` REQUIRES\n * `WRONGSTACK_UNSAFE_MCP_TLS=1` as an explicit opt-in.\n *\n * Without this gate, an active network attacker between the client and the\n * MCP server can read and modify tool calls and responses. Only use this\n * for local development with self-signed certificates; production MCP\n * servers must present a valid certificate.\n */\n tls?: { ca?: string | undefined; rejectUnauthorized?: boolean | undefined };\n}\n\n/**\n * Abort error whose `name` is `'AbortError'` so the core executor's\n * classifyToolError maps it to FATAL / not-retryable (user cancellation).\n */\nexport function makeAbortError(method: string): Error {\n const err = new Error(`MCP request \"${method}\" aborted by client`);\n err.name = 'AbortError';\n return err;\n}\n\nexport function createTimeoutSignal(\n parent: AbortSignal | undefined,\n timeoutMs: number,\n): { signal: AbortSignal; dispose: () => void } {\n const ctrl = new AbortController();\n const onAbort = () => ctrl.abort(parent?.reason);\n if (parent?.aborted) {\n ctrl.abort(parent.reason);\n } else {\n parent?.addEventListener('abort', onAbort, { once: true });\n }\n const timer = setTimeout(\n () => ctrl.abort(new Error(`MCP HTTP request timed out after ${timeoutMs}ms`)),\n timeoutMs,\n );\n return {\n signal: ctrl.signal,\n dispose: () => {\n clearTimeout(timer);\n parent?.removeEventListener('abort', onAbort);\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Shared base class \u2014 consolidates all duplicated fields, constructor logic,\n// and private helpers that are identical between SSETransport and\n// StreamableHTTPTransport.\n// ---------------------------------------------------------------------------\n\n/**\n * Fields and methods shared by all HTTP-based MCP transports.\n * Subclasses override `connect()`, `close()`, `callTool()`, `request()`.\n */\nexport abstract class BaseHTTPTransport {\n protected state: ConnectionState = 'idle';\n protected readonly url: string;\n protected readonly headers: Record<string, string>;\n protected readonly timeout: number;\n protected readonly requestTimeout: number;\n protected readonly name: string;\n protected readonly authorizationProvider?: MCPAuthorizationProvider | undefined;\n protected readonly authorizationResource: string;\n /** Per-request TLS agent \u2014 created once from HttpTransportOptions.tls */\n protected readonly tlsAgent?: https.Agent | undefined;\n protected readonly tools: MCPTool[] = [];\n protected serverMetadata?: MCPServerMetadata | undefined;\n protected abortController?: AbortController | undefined;\n protected readonly disconnectHandlers: Array<() => void> = [];\n protected readonly toolsChangedListeners = new Set<(tools: MCPTool[]) => void>();\n protected readonly resourcesChangedListeners = new Set<() => void>();\n protected readonly promptsChangedListeners = new Set<() => void>();\n protected protocolVersion?: string | undefined;\n\n constructor(opts: HttpTransportOptions, transportName: string) {\n validateTransportUrl(opts.url);\n this.name = opts.name;\n this.url = opts.url;\n this.headers = { ...opts.headers };\n this.authorizationProvider = opts.authorizationProvider;\n this.authorizationResource = canonicalMcpResource(opts.url);\n this.timeout = opts.startupTimeoutMs ?? 10_000;\n this.requestTimeout = opts.requestTimeoutMs ?? 60_000;\n if (opts.tls) {\n if (opts.tls.rejectUnauthorized === false) {\n if (!isTlsUnsafeAllowed()) {\n throw new ConfigError({\n message:\n `[mcp:${transportName}] TLS verification disabled \u2014 set WRONGSTACK_UNSAFE_MCP_TLS=1 ` +\n `to allow. Rejecting insecure configuration for ${this.url}.`,\n code: 'CONFIG_INVALID',\n context: { field: 'tls.rejectUnauthorized', transportName, url: this.url },\n });\n }\n console.error(\n `[mcp:${transportName}] \u26A0\uFE0F TLS verification DISABLED for ${this.url}. ` +\n `Network attacks are possible \u2014 only use on localhost.`,\n );\n }\n this.tlsAgent = new https.Agent({\n ca: opts.tls.ca,\n rejectUnauthorized: opts.tls.rejectUnauthorized,\n });\n }\n }\n\n getState(): ConnectionState {\n return this.state;\n }\n\n protected async fetchWithAuthorization(\n input: string,\n init: RequestInit,\n signal?: AbortSignal | undefined,\n ): Promise<Response> {\n const context = {\n serverName: this.name,\n resource: this.authorizationResource,\n signal,\n };\n const send = async (): Promise<Response> => {\n signal?.throwIfAborted();\n const headers = new Headers(init.headers);\n if (this.protocolVersion) headers.set('MCP-Protocol-Version', this.protocolVersion);\n const token = await this.authorizationProvider?.getAccessToken(context);\n signal?.throwIfAborted();\n if (token) {\n headers.set(\n 'Authorization',\n authorizationHeaderForToken(token, this.authorizationResource),\n );\n }\n return fetch(input, { ...init, headers });\n };\n\n let response = await send();\n if (response.status !== 401 || !this.authorizationProvider?.handleUnauthorized) {\n return response;\n }\n const challenge = parseMcpBearerChallenge(\n response.headers.get('www-authenticate'),\n this.authorizationResource,\n );\n const retry = await this.authorizationProvider.handleUnauthorized(challenge, context);\n if (!retry) return response;\n await response.body?.cancel().catch(() => undefined);\n response = await send();\n return response;\n }\n\n listTools(): MCPTool[] {\n return [...this.tools];\n }\n\n getServerMetadata(): MCPServerMetadata | undefined {\n const metadata = this.serverMetadata;\n if (!metadata) return undefined;\n return {\n ...metadata,\n capabilities: { ...metadata.capabilities },\n serverInfo: { ...metadata.serverInfo },\n };\n }\n\n onDisconnect(cb: () => void): () => void {\n this.disconnectHandlers.push(cb);\n return () => {\n const idx = this.disconnectHandlers.indexOf(cb);\n if (idx >= 0) this.disconnectHandlers.splice(idx, 1);\n };\n }\n\n onToolsChanged(cb: (tools: MCPTool[]) => void): () => void {\n this.toolsChangedListeners.add(cb);\n return () => {\n this.toolsChangedListeners.delete(cb);\n };\n }\n\n onResourcesChanged(cb: () => void): () => void {\n this.resourcesChangedListeners.add(cb);\n return () => this.resourcesChangedListeners.delete(cb);\n }\n\n onPromptsChanged(cb: () => void): () => void {\n this.promptsChangedListeners.add(cb);\n return () => this.promptsChangedListeners.delete(cb);\n }\n\n /**\n * Fire all disconnect handlers. Subclasses call this when the connection\n * drops so the registry can schedule reconnects.\n */\n protected notifyDisconnect(): void {\n for (const cb of this.disconnectHandlers) {\n try {\n cb();\n } catch {\n /* ignore */\n }\n }\n }\n\n protected notifyResourcesChanged(): void {\n for (const cb of this.resourcesChangedListeners) {\n try {\n cb();\n } catch {\n /* ignore */\n }\n }\n }\n\n protected notifyPromptsChanged(): void {\n for (const cb of this.promptsChangedListeners) {\n try {\n cb();\n } catch {\n /* ignore */\n }\n }\n }\n\n /**\n * Apply the pinned TLS agent (if configured) to a `RequestInit` object.\n * Uses `HttpDispatcher` from `@wrongstack/core`'s dispatcher-types shim,\n * which declares `https.Agent` compatible with `RequestInit.dispatcher`.\n * Verified safe: https.Agent implements the `dispatch(req, opts)` method\n * that fetch requires at runtime.\n */\n protected applyTlsAgent(fetchOpts: RequestInit): void {\n if (this.tlsAgent) {\n // The global `RequestInit.dispatcher` type now accepts `HttpDispatcher`\n // (see dispatcher-types.d.ts). The cast through `unknown` is the standard\n // pattern for \"I know this is compatible at runtime.\"\n fetchOpts.dispatcher = this.tlsAgent as never as HttpDispatcher;\n }\n }\n\n /** Generate the next JSON-RPC request id. Subclasses provide the counter. */\n protected abstract genId(): number;\n}\n", "import * as net from 'node:net';\nimport { ConfigError } from '@wrongstack/core/types';\n\nexport function isTlsUnsafeAllowed(): boolean {\n return process.env['WRONGSTACK_UNSAFE_MCP_TLS'] === '1';\n}\n\n/**\n * Validate that an MCP transport URL is not targeting private/internal\n * addresses. This is a defense-in-depth SSRF check \u2014 MCP servers are\n * typically local or LAN, but config manipulation could point to metadata\n * endpoints (169.254.169.254) or internal services.\n *\n * The check is intentionally lighter than fetch.ts's assertNotPrivate:\n * MCP URLs are admin-configured, not LLM-supplied, so we only block\n * the most obvious attack vectors.\n */\nexport function validateTransportUrl(rawUrl: string): void {\n let url: URL;\n try {\n url = new URL(rawUrl);\n } catch {\n throw new ConfigError({\n message: `MCP transport: invalid URL \"${rawUrl}\"`,\n code: 'CONFIG_INVALID',\n context: { field: 'url', rawUrl },\n });\n }\n\n if (url.protocol !== 'http:' && url.protocol !== 'https:') {\n throw new ConfigError({\n message: `MCP transport: unsupported protocol \"${url.protocol}\" \u2014 only http/https allowed`,\n code: 'CONFIG_INVALID',\n context: { field: 'url', rawUrl, protocol: url.protocol },\n });\n }\n\n const hostname = url.hostname;\n // URL.hostname keeps the brackets on IPv6 literals; strip them so net.isIP\n // and prefix checks see the bare address.\n const host =\n hostname.startsWith('[') && hostname.endsWith(']') ? hostname.slice(1, -1) : hostname;\n\n // Block cloud metadata endpoints (IMDS) \u2014 these are never valid MCP servers\n const ipVersion = net.isIP(host);\n if (ipVersion === 4) {\n const parts = host.split('.').map(Number);\n // 169.254.x.x (link-local / IMDS)\n if (parts[0] === 169 && parts[1] === 254) {\n throw new ConfigError({\n message: `MCP transport: blocked link-local/IMDS address \"${hostname}\" \u2014 likely not a valid MCP server`,\n code: 'CONFIG_INVALID',\n context: { field: 'url', rawUrl, hostname },\n });\n }\n } else if (ipVersion === 6) {\n const lower = host.toLowerCase();\n // fe80::/10 link-local (first hextet fe80\u2013febf) and the AWS IPv6 IMDS\n // address fd00:ec2::254 \u2014 the IPv6 counterparts of the IPv4 block above.\n const linkLocal = /^fe[89ab]/.test(lower);\n if (linkLocal || lower === 'fd00:ec2::254') {\n throw new ConfigError({\n message: `MCP transport: blocked link-local/IMDS address \"${hostname}\" \u2014 likely not a valid MCP server`,\n code: 'CONFIG_INVALID',\n context: { field: 'url', rawUrl, hostname },\n });\n }\n }\n\n // Plaintext http: is only permitted for loopback addresses where the\n // attacker would already need machine-level access. Remote HTTP MCP servers\n // must use TLS so an active network attacker cannot read or modify tool\n // calls and responses.\n if (url.protocol === 'http:') {\n const isLoopback =\n hostname === 'localhost' ||\n hostname === '127.0.0.1' ||\n hostname === '::1' ||\n hostname === '[::1]';\n if (!isLoopback) {\n throw new ConfigError({\n message: `MCP transport: http:// is only allowed for loopback addresses; use https:// for \"${hostname}\"`,\n code: 'CONFIG_INVALID',\n context: { field: 'url', rawUrl, hostname, protocol: url.protocol },\n });\n }\n }\n}\n", "import { randomBytes } from 'node:crypto';\nimport { ToolError } from '@wrongstack/core/types';\nimport type { JsonRpcResponse, ToolCallResult } from './client.js';\nimport { MCP_CONSTANTS } from './constants.js';\nimport { parseServerMetadata } from './protocol.js';\nimport { SSEReader } from './sse-reader.js';\nimport {\n BaseHTTPTransport,\n createTimeoutSignal,\n type HttpTransportOptions,\n makeAbortError,\n} from './transport-base.js';\nimport { assertMatchingJsonRpcResult, type JsonRpcResult } from './transport-jsonrpc.js';\nimport { normalizeMCPTools } from './tool-schema.js';\n\n// ---------------------------------------------------------------------------\n// SSE Transport\n// ---------------------------------------------------------------------------\n\n/**\n * SSE transport for MCP over HTTP.\n *\n * Uses native fetch API with ReadableStream to consume SSE events.\n * HTTP POST is used to send JSON-RPC requests.\n */\nexport class SSETransport extends BaseHTTPTransport {\n private _nextId = 1;\n private readerDone = false;\n private readLoopAbort?: AbortController | undefined;\n private reader?: globalThis.ReadableStreamDefaultReader<string> | undefined;\n\n constructor(opts: HttpTransportOptions) {\n super(opts, 'SSETransport');\n }\n\n protected override genId(): number {\n return this._nextId++;\n }\n\n /** Refresh tool list when server sends notifications/tools/list_changed. */\n private async handleToolsListChanged(): Promise<void> {\n try {\n const res = await this.httpPost('tools/list', {});\n if (!res.error) {\n this.tools.splice(\n 0,\n this.tools.length,\n ...normalizeMCPTools((res.result as { tools?: unknown | undefined } | undefined)?.tools),\n );\n for (const cb of this.toolsChangedListeners) {\n try {\n cb([...this.tools]);\n } catch {\n /* ignore */\n }\n }\n }\n } catch {\n /* ignore transient failures */\n }\n }\n\n async connect(): Promise<void> {\n this.state = 'connecting';\n this.serverMetadata = undefined;\n this.abortController = new AbortController();\n const signal = this.abortController.signal;\n const startupTimer = setTimeout(() => this.abortController?.abort(), this.timeout);\n\n try {\n const sseUrl = this.buildSSEUrl();\n const fetchOpts: RequestInit = {\n headers: this.headers,\n signal,\n };\n this.applyTlsAgent(fetchOpts);\n const response = await this.fetchWithAuthorization(sseUrl, fetchOpts, signal);\n\n if (!response.ok) {\n throw new ToolError({\n message: `SSE connect HTTP ${response.status}: ${response.statusText}`,\n code: 'TOOL_EXECUTION_FAILED',\n toolName: 'mcp_transport_sse_connect',\n context: { url: sseUrl, status: response.status, statusText: response.statusText },\n });\n }\n\n if (!response.body) {\n throw new ToolError({\n message: 'SSE response has no body',\n code: 'TOOL_EXECUTION_FAILED',\n toolName: 'mcp_transport_sse_connect',\n context: { url: sseUrl, reason: 'missing-body' },\n });\n }\n\n const textDecoder = new TextDecoder();\n const sseReader = new SSEReader();\n this.readLoopAbort = new AbortController();\n\n sseReader.onMessage((msg) => {\n // Server-initiated notifications (no id). Handle list_changed for L2-C.\n if (msg.method && !msg.id) {\n if (msg.method === 'notifications/tools/list_changed') {\n void this.handleToolsListChanged();\n } else if (msg.method === 'notifications/resources/list_changed') {\n this.notifyResourcesChanged();\n } else if (msg.method === 'notifications/prompts/list_changed') {\n this.notifyPromptsChanged();\n }\n }\n });\n\n const reader = response.body.getReader();\n this.reader = {\n cancel: () => reader.cancel(),\n releaseLock: () => reader.releaseLock(),\n } as globalThis.ReadableStreamDefaultReader<string>;\n\n this.readSSEBody(reader, textDecoder, sseReader);\n\n const initRes = await this.httpPost('initialize', {\n protocolVersion: MCP_CONSTANTS.PROTOCOL_VERSION,\n capabilities: { tools: {} },\n clientInfo: MCP_CONSTANTS.CLIENT_INFO,\n });\n\n if (initRes.error) {\n throw new ToolError({\n message: `initialize failed: ${initRes.error.message}`,\n code: 'TOOL_EXECUTION_FAILED',\n toolName: 'mcp_transport_initialize',\n context: { transport: 'sse', url: this.url },\n });\n }\n this.serverMetadata = parseServerMetadata(initRes.result);\n this.protocolVersion = this.serverMetadata.protocolVersion;\n\n try {\n await this.httpPost('notifications/initialized', {});\n } catch {\n // servers may not require it\n }\n\n const toolsRes = await this.httpPost('tools/list', {});\n if (toolsRes.error) {\n this.tools.splice(0, this.tools.length);\n } else {\n const result = toolsRes.result as { tools?: unknown | undefined } | undefined;\n this.tools.splice(0, this.tools.length, ...normalizeMCPTools(result?.tools));\n }\n\n this.state = 'connected';\n clearTimeout(startupTimer);\n } catch (err) {\n clearTimeout(startupTimer);\n this.state = 'failed';\n this.abortController.abort();\n throw err;\n }\n }\n\n private async readSSEBody(\n reader: globalThis.ReadableStreamDefaultReader<Uint8Array>,\n decoder: InstanceType<typeof TextDecoder>,\n sseReader: SSEReader,\n ): Promise<void> {\n try {\n while (!this.readerDone) {\n const { done, value } = await reader.read();\n if (done) break;\n const chunk = decoder.decode(value, { stream: true });\n sseReader.feed(chunk);\n }\n } catch {\n // SSE read error \u2014 connection lost. Transition to disconnected so\n // callTool and health checks see the correct state, then notify\n // disconnect handlers so the registry can schedule a reconnect.\n if (this.state !== 'disconnected' && this.state !== 'failed') {\n this.state = 'disconnected';\n this.notifyDisconnect();\n }\n }\n }\n\n private buildSSEUrl(): string {\n try {\n const url = new URL(this.url);\n // Cryptographically random session ID instead of timestamp \u2014\n // prevents an attacker on the same LAN from guessing the session\n // param and reconnecting to the SSE stream.\n url.searchParams.set('session', randomBytes(16).toString('hex'));\n return url.toString();\n } catch {\n return this.url;\n }\n }\n\n private async httpPost(\n method: string,\n params: unknown,\n opts?: { signal?: AbortSignal | undefined },\n ): Promise<JsonRpcResult> {\n const id = this.genId();\n const body = JSON.stringify({ jsonrpc: '2.0', id, method, params });\n\n const external = opts?.signal;\n const parent =\n external && this.abortController\n ? AbortSignal.any([this.abortController.signal, external])\n : (external ?? this.abortController?.signal);\n const timeoutSignal = createTimeoutSignal(parent, this.requestTimeout);\n const fetchOpts: RequestInit = {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...this.headers,\n },\n body,\n signal: timeoutSignal.signal,\n };\n this.applyTlsAgent(fetchOpts);\n // fetch lives INSIDE the try so dispose() runs on every exit path \u2014 a\n // rejected fetch must not leak the timeout timer / abort listener.\n try {\n const res = await this.fetchWithAuthorization(this.url, fetchOpts, timeoutSignal.signal);\n if (!res.ok) {\n // Cap the body \u2014 a misbehaving server could return megabytes of\n // HTML and that's not useful in an error message anyway.\n const body = await res.text();\n const cap = MCP_CONSTANTS.REQUEST_LOG_CAP;\n const snippet =\n body.length > cap ? `${body.slice(0, cap)}\u2026 [${body.length} bytes total]` : body;\n throw new ToolError({\n message: `HTTP ${res.status}: ${snippet}`,\n code: 'TOOL_EXECUTION_FAILED',\n toolName: method,\n context: { transport: 'sse', url: this.url, status: res.status },\n });\n }\n\n let data: unknown;\n try {\n data = await res.json();\n } catch (err) {\n throw new ToolError({\n message: `Invalid JSON-RPC response: ${err instanceof Error ? err.message : 'parse failed'}`,\n code: 'TOOL_EXECUTION_FAILED',\n toolName: method,\n context: { transport: 'sse', url: this.url, phase: 'parse-json' },\n cause: err,\n });\n }\n return assertMatchingJsonRpcResult(data, id, method);\n } catch (err) {\n if (external?.aborted && !method.startsWith('notifications/')) {\n // MCP spec cancellation: tell the server to stop the in-flight\n // request. Best-effort fire-and-forget \u2014 the caller is already\n // unwinding on the abort.\n void this.httpPost('notifications/cancelled', {\n requestId: id,\n reason: 'client aborted',\n }).catch(() => {});\n throw makeAbortError(method);\n }\n throw err;\n } finally {\n timeoutSignal.dispose();\n }\n }\n\n async callTool(\n name: string,\n input: unknown,\n opts?: { signal?: AbortSignal | undefined },\n ): Promise<ToolCallResult> {\n if (this.state !== 'connected') {\n throw new ToolError({\n message: `SSE transport not connected (state=${this.state})`,\n code: 'TOOL_EXECUTION_FAILED',\n toolName: name,\n context: { transport: 'sse', state: this.state },\n });\n }\n const res = await this.httpPost('tools/call', { name, arguments: input }, opts);\n if (res.error) {\n return { content: res.error.message, isError: true };\n }\n const result = res.result as\n | { content?: unknown | undefined; isError?: boolean | undefined }\n | undefined;\n return {\n content: result?.content ?? '',\n isError: Boolean(result?.isError),\n };\n }\n\n /** Generic JSON-RPC request \u2014 used by MCPClient.request() for SSE transports. */\n async request(\n method: string,\n params: unknown,\n timeoutMs?: number,\n opts?: { signal?: AbortSignal | undefined },\n ): Promise<JsonRpcResponse> {\n const id = this.genId();\n const body = JSON.stringify({ jsonrpc: '2.0', id, method, params });\n\n const external = opts?.signal;\n const parent =\n external && this.abortController\n ? AbortSignal.any([this.abortController.signal, external])\n : (external ?? this.abortController?.signal);\n const timeoutSignal = createTimeoutSignal(parent, timeoutMs ?? this.requestTimeout);\n const fetchOpts: RequestInit = {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...this.headers,\n },\n body,\n signal: timeoutSignal.signal,\n };\n this.applyTlsAgent(fetchOpts);\n // dispose() clears the timeout timer and the parent-abort listener. It must\n // run on EVERY exit path (fetch rejection, !res.ok, JSON parse error,\n // mismatched result) \u2014 not just success \u2014 or the timer keeps ticking and the\n // abort listener leaks for the full timeout on each failed request.\n try {\n const res = await this.fetchWithAuthorization(this.url, fetchOpts, timeoutSignal.signal);\n\n if (!res.ok) {\n throw new ToolError({\n message: `HTTP ${res.status}: ${res.statusText}`,\n code: 'TOOL_EXECUTION_FAILED',\n toolName: method,\n context: {\n transport: 'sse',\n url: this.url,\n status: res.status,\n statusText: res.statusText,\n },\n });\n }\n\n let data: unknown;\n try {\n data = await res.json();\n } catch (err) {\n throw new ToolError({\n message: `Invalid JSON-RPC response: ${err instanceof Error ? err.message : 'parse failed'}`,\n code: 'TOOL_EXECUTION_FAILED',\n toolName: method,\n context: { transport: 'sse', url: this.url, phase: 'parse-json' },\n cause: err,\n });\n }\n const result = assertMatchingJsonRpcResult(data, id, method);\n return { jsonrpc: '2.0', id, result: result.result, error: result.error };\n } catch (err) {\n if (external?.aborted && !method.startsWith('notifications/')) {\n void this.httpPost('notifications/cancelled', {\n requestId: id,\n reason: 'client aborted',\n }).catch(() => {});\n throw makeAbortError(method);\n }\n throw err;\n } finally {\n timeoutSignal.dispose();\n }\n }\n\n async close(): Promise<void> {\n // Idempotent \u2014 safe to call multiple times.\n if (this.state === 'disconnected') return;\n this.readerDone = true;\n this.readLoopAbort?.abort();\n try {\n this.reader?.cancel();\n } catch {\n /* ignore */\n }\n try {\n this.reader?.releaseLock();\n } catch {\n /* ignore */\n }\n this.abortController?.abort();\n this.disconnectHandlers.splice(0, this.disconnectHandlers.length);\n this.state = 'disconnected';\n }\n}\n", "import type { JsonRpcResponse, ToolCallResult } from './client.js';\nimport { MCP_CONSTANTS } from './constants.js';\nimport { parseServerMetadata } from './protocol.js';\nimport {\n BaseHTTPTransport,\n createTimeoutSignal,\n type HttpTransportOptions,\n makeAbortError,\n} from './transport-base.js';\nimport {\n assertMatchingJsonRpcResult,\n extractJsonRpcEnvelopes,\n extractJsonRpcResults,\n isJsonRpcResult,\n type JsonRpcResult,\n} from './transport-jsonrpc.js';\nimport { normalizeMCPTools } from './tool-schema.js';\n\n// ---------------------------------------------------------------------------\n// Streamable HTTP Transport\n// ---------------------------------------------------------------------------\n\n/**\n * Streamable HTTP transport for MCP.\n *\n * Uses session-based HTTP with NDJSON responses.\n */\nexport class StreamableHTTPTransport extends BaseHTTPTransport {\n private _nextId = 1;\n private sessionId?: string | undefined;\n\n constructor(opts: HttpTransportOptions) {\n super(opts, 'StreamableHTTP');\n }\n\n protected override genId(): number {\n return this._nextId++;\n }\n\n private consumeResponseText(text: string, requestId: number): JsonRpcResult | undefined {\n const envelopes = extractJsonRpcEnvelopes(text);\n for (const envelope of envelopes) {\n if ('method' in envelope && envelope.id === undefined) {\n this.handleNotification(envelope.method);\n }\n }\n const responses = envelopes.filter(isJsonRpcResult);\n return (\n responses.find((envelope) => envelope.id === requestId) ??\n responses.find((envelope) => envelope.id !== undefined) ??\n responses[0]\n );\n }\n\n private handleNotification(method: string): void {\n if (method === 'notifications/resources/list_changed') {\n this.notifyResourcesChanged();\n } else if (method === 'notifications/prompts/list_changed') {\n this.notifyPromptsChanged();\n } else if (method === 'notifications/tools/list_changed') {\n void this.refreshTools();\n }\n }\n\n private async refreshTools(): Promise<void> {\n try {\n const response = await this.postRaw('tools/list', {});\n if (response.error) return;\n const tools = normalizeMCPTools(\n (response.result as { tools?: unknown | undefined } | undefined)?.tools,\n );\n this.tools.splice(0, this.tools.length, ...tools);\n for (const listener of this.toolsChangedListeners) {\n try {\n listener([...tools]);\n } catch {\n /* ignore */\n }\n }\n } catch {\n /* keep the last known tool catalog */\n }\n }\n\n async connect(): Promise<void> {\n this.state = 'connecting';\n this.serverMetadata = undefined;\n this.abortController = new AbortController();\n const signal = this.abortController.signal;\n const startupTimer = setTimeout(() => this.abortController?.abort(), this.timeout);\n\n try {\n const initFetchOpts: RequestInit = {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'application/json, text/event-stream',\n ...this.headers,\n },\n body: JSON.stringify({\n jsonrpc: '2.0',\n id: this.genId(),\n method: 'initialize',\n params: {\n protocolVersion: MCP_CONSTANTS.PROTOCOL_VERSION,\n capabilities: { tools: {} },\n clientInfo: MCP_CONSTANTS.CLIENT_INFO,\n },\n }),\n signal,\n };\n this.applyTlsAgent(initFetchOpts);\n const initRes = await this.fetchWithAuthorization(this.url, initFetchOpts, signal);\n\n if (!initRes.ok) {\n throw new Error(`initialize HTTP ${initRes.status}: ${initRes.statusText}`);\n }\n\n const contentType = initRes.headers.get('content-type') ?? '';\n let data: JsonRpcResult | undefined;\n\n if (contentType.includes('application/json')) {\n const parsed = await initRes.json();\n if (isJsonRpcResult(parsed)) data = parsed;\n } else {\n // text/event-stream or NDJSON \u2014 handle SSE `data:` framing.\n data = extractJsonRpcResults(await initRes.text())[0];\n }\n\n if (!data) {\n throw new Error('Could not parse initialize response');\n }\n data = assertMatchingJsonRpcResult(data, this._nextId - 1, 'initialize');\n\n if (data.error) {\n throw new Error(`initialize failed: ${data.error.message}`);\n }\n this.serverMetadata = parseServerMetadata(data.result);\n this.protocolVersion = this.serverMetadata.protocolVersion;\n\n // MCP Streamable HTTP spec: the server assigns a session via the\n // `Mcp-Session-Id` response header, which the client must echo on every\n // subsequent request. (Header lookups are case-insensitive.)\n this.sessionId = initRes.headers.get('mcp-session-id') ?? undefined;\n await this.postRaw('notifications/initialized', {});\n\n const toolsRes = await this.postRaw('tools/list', {});\n if (toolsRes.error) {\n this.tools.splice(0, this.tools.length);\n } else {\n const result = toolsRes.result as { tools?: unknown | undefined } | undefined;\n this.tools.splice(0, this.tools.length, ...normalizeMCPTools(result?.tools));\n }\n\n this.state = 'connected';\n clearTimeout(startupTimer);\n } catch (err) {\n clearTimeout(startupTimer);\n this.state = 'failed';\n this.abortController.abort();\n throw err;\n }\n }\n\n private async postRaw(\n method: string,\n params: unknown,\n opts?: { signal?: AbortSignal | undefined },\n ): Promise<JsonRpcResult> {\n const id = this.genId();\n const body = JSON.stringify({ jsonrpc: '2.0', id, method, params });\n\n const external = opts?.signal;\n const parent =\n external && this.abortController\n ? AbortSignal.any([this.abortController.signal, external])\n : (external ?? this.abortController?.signal);\n const timeoutSignal = createTimeoutSignal(parent, this.requestTimeout);\n const fetchOpts: RequestInit = {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'application/json, text/event-stream',\n ...(this.sessionId ? { 'Mcp-Session-Id': this.sessionId } : {}),\n ...this.headers,\n },\n body,\n signal: timeoutSignal.signal,\n };\n this.applyTlsAgent(fetchOpts);\n // fetch lives INSIDE the try so dispose() runs on every exit path \u2014 a\n // rejected fetch must not leak the timeout timer / abort listener.\n try {\n const res = await this.fetchWithAuthorization(this.url, fetchOpts, timeoutSignal.signal);\n if (!res.ok) {\n throw new Error(`HTTP ${res.status}: ${res.statusText}`);\n }\n\n // Notifications get no JSON-RPC reply (the server returns 202 / empty body).\n if (method.startsWith('notifications/')) {\n await res.text().catch(() => undefined);\n return { jsonrpc: '2.0' };\n }\n\n const match = this.consumeResponseText(await res.text(), id);\n if (match) {\n return assertMatchingJsonRpcResult(match, id, method);\n }\n throw new Error('Could not parse response as JSON-RPC');\n } catch (err) {\n if (external?.aborted && !method.startsWith('notifications/')) {\n // MCP spec cancellation: tell the server to stop the in-flight\n // request. Best-effort fire-and-forget.\n void this.postRaw('notifications/cancelled', {\n requestId: id,\n reason: 'client aborted',\n }).catch(() => {});\n throw makeAbortError(method);\n }\n throw err;\n } finally {\n timeoutSignal.dispose();\n }\n }\n\n /** Generic JSON-RPC request \u2014 used by MCPClient.request() for SSE/streamable-http transports. */\n async request(\n method: string,\n params: unknown,\n timeoutMs?: number,\n opts?: { signal?: AbortSignal | undefined },\n ): Promise<JsonRpcResponse> {\n const id = this.genId();\n const body = JSON.stringify({ jsonrpc: '2.0', id, method, params });\n\n const external = opts?.signal;\n const parent =\n external && this.abortController\n ? AbortSignal.any([this.abortController.signal, external])\n : (external ?? this.abortController?.signal);\n const timeoutSignal = createTimeoutSignal(parent, timeoutMs ?? this.requestTimeout);\n const fetchOpts: RequestInit = {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'application/json, text/event-stream',\n ...(this.sessionId ? { 'Mcp-Session-Id': this.sessionId } : {}),\n ...this.headers,\n },\n body,\n signal: timeoutSignal.signal,\n };\n this.applyTlsAgent(fetchOpts);\n try {\n const res = await this.fetchWithAuthorization(this.url, fetchOpts, timeoutSignal.signal);\n if (!res.ok) {\n throw new Error(`HTTP ${res.status}: ${res.statusText}`);\n }\n\n if (method.startsWith('notifications/')) {\n await res.text().catch(() => undefined);\n return { jsonrpc: '2.0', id };\n }\n\n const parsed = this.consumeResponseText(await res.text(), id);\n if (parsed) {\n // Convert JsonRpcResult to JsonRpcResponse\n return {\n jsonrpc: '2.0',\n id,\n result: parsed.result,\n error: parsed.error,\n };\n }\n throw new Error('Could not parse response as JSON-RPC');\n } catch (err) {\n if (external?.aborted && !method.startsWith('notifications/')) {\n void this.postRaw('notifications/cancelled', {\n requestId: id,\n reason: 'client aborted',\n }).catch(() => {});\n throw makeAbortError(method);\n }\n throw err;\n } finally {\n timeoutSignal.dispose();\n }\n }\n\n async callTool(\n name: string,\n input: unknown,\n opts?: { signal?: AbortSignal | undefined },\n ): Promise<ToolCallResult> {\n if (this.state !== 'connected') {\n throw new Error(`streamable-http transport not connected (state=${this.state})`);\n }\n const res = await this.postRaw('tools/call', { name, arguments: input }, opts);\n if (res.error) {\n return { content: res.error.message, isError: true };\n }\n const result = res.result as\n | { content?: unknown | undefined; isError?: boolean | undefined }\n | undefined;\n return {\n content: result?.content ?? '',\n isError: Boolean(result?.isError),\n };\n }\n\n async close(): Promise<void> {\n if (this.state === 'disconnected') return;\n this.state = 'disconnected';\n this.abortController?.abort();\n // Intentionally do NOT fire disconnect handlers \u2014 those trigger\n // reconnection in the registry, which would fight an explicit close().\n this.disconnectHandlers.splice(0, this.disconnectHandlers.length);\n }\n}\n", "import type {\n MCPGetPromptResult,\n MCPPromptMessage,\n MCPReadResourceResult,\n MCPResourceContents,\n} from './protocol.js';\n\nexport const DEFAULT_MCP_INSERTION_MAX_BYTES = 256 * 1024;\nexport const DEFAULT_MCP_RESOURCE_SCHEMES = [\n 'file',\n 'git',\n 'http',\n 'https',\n 'mcp',\n 'mem',\n 'repo',\n 'resource',\n] as const;\n\nexport interface MCPInsertionPolicy {\n maxBytes?: number | undefined;\n allowedUriSchemes?: readonly string[] | undefined;\n}\n\nexport interface MCPContentProvenance {\n origin: 'mcp';\n serverName: string;\n capability: 'resource' | 'prompt';\n resourceUri?: string | undefined;\n promptName?: string | undefined;\n promptArgumentNames?: string[] | undefined;\n}\n\nexport interface MCPResourceInsertion {\n kind: 'resource';\n untrusted: true;\n byteSize: number;\n provenance: MCPContentProvenance;\n contents: MCPResourceContents[];\n}\n\nexport interface MCPPromptInsertion {\n kind: 'prompt';\n untrusted: true;\n byteSize: number;\n provenance: MCPContentProvenance;\n description?: string | undefined;\n messages: MCPPromptMessage[];\n}\n\nexport function prepareResourceInsertion(\n serverName: string,\n requestedUri: string,\n result: MCPReadResourceResult,\n policy: MCPInsertionPolicy = {},\n): MCPResourceInsertion {\n requireIdentity(serverName, 'server name');\n validateUri(requestedUri, policy);\n if (result.contents.length > 64) {\n throw new Error('MCP resource insertion exceeds the limit of 64 content blocks');\n }\n let byteSize = 0;\n for (const content of result.contents) {\n validateUri(content.uri, policy);\n if (content.text !== undefined) byteSize += utf8Bytes(content.text);\n if (content.blob !== undefined) byteSize += base64DecodedBytes(content.blob);\n enforceSize(byteSize, policy);\n }\n return {\n kind: 'resource',\n untrusted: true,\n byteSize,\n provenance: {\n origin: 'mcp',\n serverName,\n capability: 'resource',\n resourceUri: requestedUri,\n },\n contents: structuredClone(result.contents),\n };\n}\n\nexport function preparePromptInsertion(\n serverName: string,\n promptName: string,\n args: Record<string, string> | undefined,\n result: MCPGetPromptResult,\n policy: MCPInsertionPolicy = {},\n): MCPPromptInsertion {\n requireIdentity(serverName, 'server name');\n requireIdentity(promptName, 'prompt name');\n if (result.messages.length > 128) {\n throw new Error('MCP prompt insertion exceeds the limit of 128 messages');\n }\n for (const message of result.messages) validateEmbeddedUris(message.content, policy, 0);\n let serialized: string;\n try {\n serialized = JSON.stringify(result.messages);\n } catch {\n throw new Error('MCP prompt insertion contains non-serializable content');\n }\n const byteSize = utf8Bytes(serialized);\n enforceSize(byteSize, policy);\n return {\n kind: 'prompt',\n untrusted: true,\n byteSize,\n provenance: {\n origin: 'mcp',\n serverName,\n capability: 'prompt',\n promptName,\n promptArgumentNames: Object.keys(args ?? {}).sort(),\n },\n description: result.description,\n messages: structuredClone(result.messages),\n };\n}\n\nfunction validateEmbeddedUris(value: unknown, policy: MCPInsertionPolicy, depth: number): void {\n if (depth > 32) throw new Error('MCP prompt insertion exceeds the nesting depth limit');\n if (Array.isArray(value)) {\n for (const item of value) validateEmbeddedUris(item, policy, depth + 1);\n return;\n }\n if (!value || typeof value !== 'object') return;\n for (const [key, nested] of Object.entries(value as Record<string, unknown>)) {\n if (key === 'uri' && typeof nested === 'string') validateUri(nested, policy);\n validateEmbeddedUris(nested, policy, depth + 1);\n }\n}\n\nfunction validateUri(uri: string, policy: MCPInsertionPolicy): void {\n if (uri.length === 0 || uri.length > 8_192) {\n throw new Error('MCP insertion URI must contain 1\u20138192 characters');\n }\n let parsed: URL;\n try {\n parsed = new URL(uri);\n } catch {\n throw new Error('MCP insertion URI must be absolute');\n }\n const scheme = parsed.protocol.slice(0, -1).toLowerCase();\n const allowed = new Set(\n (policy.allowedUriSchemes ?? DEFAULT_MCP_RESOURCE_SCHEMES).map((value) => value.toLowerCase()),\n );\n if (!allowed.has(scheme)) {\n throw new Error(`MCP insertion URI scheme \"${scheme}\" is not allowed`);\n }\n if ((scheme === 'http' || scheme === 'https') && (parsed.username || parsed.password)) {\n throw new Error('MCP insertion URI must not contain credentials');\n }\n}\n\nfunction enforceSize(byteSize: number, policy: MCPInsertionPolicy): void {\n const maxBytes = policy.maxBytes ?? DEFAULT_MCP_INSERTION_MAX_BYTES;\n if (!Number.isSafeInteger(maxBytes) || maxBytes <= 0) {\n throw new Error('MCP insertion maxBytes must be a positive safe integer');\n }\n if (byteSize > maxBytes) {\n throw new Error(`MCP insertion exceeds the ${maxBytes}-byte content limit`);\n }\n}\n\nfunction base64DecodedBytes(blob: string): number {\n if (!/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(blob)) {\n throw new Error('MCP resource insertion contains invalid base64 content');\n }\n const padding = blob.endsWith('==') ? 2 : blob.endsWith('=') ? 1 : 0;\n return (blob.length / 4) * 3 - padding;\n}\n\nfunction utf8Bytes(value: string): number {\n return new TextEncoder().encode(value).byteLength;\n}\n\nfunction requireIdentity(value: string, label: string): void {\n if (value.length === 0 || value.length > 256) {\n throw new Error(`MCP insertion ${label} must contain 1\u2013256 characters`);\n }\n}\n", "/**\n * Shared, surface-agnostic MCP server management.\n *\n * One source of truth for add / update / remove / enable / disable / restart /\n * discover / list. Every surface delegates here so the REPL (`/mcp`), the TUI,\n * and BOTH WebUI servers behave identically and never drift:\n *\n * - REPL / TUI : packages/cli/src/slash-commands/mcp-utils.ts (colored strings)\n * - WebUI : packages/webui/src/server/mcp-handlers.ts (WS events)\n *\n * The functions are pure with respect to rendering \u2014 they mutate the config\n * file on disk and the live {@link MCPRegistry}, then return structured results.\n * Callers translate those results into whatever their surface needs.\n *\n * MCP records live in two places:\n * - persistent : active profile `config.json` \u2192 `mcpServers`\n * - live state : the in-process {@link MCPRegistry}\n */\nimport { randomBytes } from 'node:crypto';\nimport * as fs from 'node:fs/promises';\nimport type { MCPHealthConfig, MCPServerConfig, Permission } from '@wrongstack/core/types';\nimport type { MCPRegistry } from './registry.js';\n\n/** Transport values accepted from UI surfaces (UI also offers a bare \"http\"). */\ntype TransportInput = 'stdio' | 'sse' | 'streamable-http' | 'http';\n\n/** Loosely-typed server input as it arrives from a UI or command surface. */\nexport interface McpServerInput {\n name: string;\n transport?: TransportInput | string | undefined;\n description?: string | undefined;\n enabled?: boolean | undefined;\n command?: string | undefined;\n args?: string[] | undefined;\n env?: Record<string, string> | undefined;\n url?: string | undefined;\n headers?: Record<string, string> | undefined;\n allowedTools?: string[] | undefined;\n permission?: Permission | undefined;\n /** Lazy connect \u2014 spawn the process only on first tool call (see config). */\n lazy?: boolean | undefined;\n /** Env var names to forward from parent process at spawn time. */\n passthroughEnv?: string[] | undefined;\n /** Operational-health thresholds (optional; omitted means no threshold checks). */\n health?: MCPHealthConfig | undefined;\n}\n\n/** Projected view of one server, merging disk config with live registry state. */\nexport interface McpServerInfo {\n name: string;\n transport: MCPServerConfig['transport'];\n description?: string | undefined;\n enabled: boolean;\n /** Raw registry state ('connected' | 'connecting' | \u2026 | 'failed'), or 'stopped' when not running. */\n status: string;\n /** Real tool names discovered from the live server (empty when not connected). */\n tools: string[];\n url?: string | undefined;\n command?: string | undefined;\n args?: string[] | undefined;\n env?: Record<string, string> | undefined;\n /** Lazy-connect opt-in (spawn on first tool call). */\n lazy?: boolean | undefined;\n}\n\nexport interface McpOpResult {\n ok: boolean;\n message: string;\n /** The affected server's projected view, when applicable. */\n server?: McpServerInfo | undefined;\n /** Raw registry state after a start/restart attempt. */\n state?: string | undefined;\n /** Real tool names after a start/restart attempt. */\n tools?: string[] | undefined;\n /** Set when a config change persisted but the registry start/stop failed. */\n registryError?: string | undefined;\n}\n\nexport interface McpManageDeps {\n /** Absolute path to the active profile config.json that owns `mcpServers`. */\n configPath: string;\n /** Live registry for runtime start/stop/restart. */\n registry: MCPRegistry;\n /** Built-in presets (from core `allServers()`), used by name-only `add`. */\n presets?: Record<string, MCPServerConfig> | undefined;\n}\n\n// \u2500\u2500 config IO (atomic) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nasync function readConfig(path: string): Promise<Record<string, unknown>> {\n try {\n return JSON.parse(await fs.readFile(path, 'utf8')) as Record<string, unknown>;\n } catch {\n return {};\n }\n}\n\nasync function writeConfig(path: string, cfg: Record<string, unknown>): Promise<void> {\n const raw = JSON.stringify(cfg, null, 2);\n // Unique temp name (pid + random) so two concurrent writers (e.g. WebUI and\n // REPL editing MCP config at once) don't clobber a shared `${path}.tmp` and\n // corrupt the config. Clean up the temp file if the rename fails.\n const tmp = `${path}.${process.pid}.${randomBytes(6).toString('hex')}.tmp`;\n await fs.writeFile(tmp, raw, 'utf8');\n try {\n await fs.rename(tmp, path);\n } catch (err) {\n await fs.rm(tmp, { force: true }).catch(() => undefined);\n throw err;\n }\n}\n\nfunction isMcpServerRecord(value: unknown): value is Record<string, MCPServerConfig> {\n return !!value && typeof value === 'object' && !Array.isArray(value);\n}\n\nasync function readServers(configPath: string): Promise<{\n full: Record<string, unknown>;\n servers: Record<string, MCPServerConfig>;\n}> {\n const full = await readConfig(configPath);\n const servers = isMcpServerRecord(full.mcpServers) ? { ...full.mcpServers } : {};\n return { full, servers };\n}\n\nasync function persist(\n configPath: string,\n full: Record<string, unknown>,\n servers: Record<string, MCPServerConfig>,\n): Promise<void> {\n full.mcpServers = servers;\n await writeConfig(configPath, full);\n}\n\n// \u2500\u2500 helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Normalise UI transport values; UI offers a bare \"http\" \u2192 streamable-http. */\nfunction normalizeTransport(t: string | undefined): MCPServerConfig['transport'] {\n if (t === 'sse') return 'sse';\n if (t === 'http' || t === 'streamable-http') return 'streamable-http';\n return 'stdio';\n}\n\n/**\n * Build a clean MCPServerConfig from loose input, omitting undefined keys so\n * `exactOptionalPropertyTypes` stays satisfied and we never write `null`-ish\n * holes into config.json. `base` lets `update` merge onto an existing entry.\n */\nfunction buildConfig(input: McpServerInput, base?: MCPServerConfig | undefined): MCPServerConfig {\n const cfg: MCPServerConfig = {\n name: input.name,\n transport: input.transport\n ? normalizeTransport(String(input.transport))\n : (base?.transport ?? 'stdio'),\n };\n const description = input.description ?? base?.description;\n if (description !== undefined) cfg.description = description;\n const command = input.command ?? base?.command;\n if (command !== undefined) cfg.command = command;\n const args = input.args ?? base?.args;\n if (args !== undefined) cfg.args = args;\n const env = input.env ?? base?.env;\n if (env !== undefined) cfg.env = env;\n const url = input.url ?? base?.url;\n if (url !== undefined) cfg.url = url;\n const headers = input.headers ?? base?.headers;\n if (headers !== undefined) cfg.headers = headers;\n const allowedTools = input.allowedTools ?? base?.allowedTools;\n if (allowedTools !== undefined) cfg.allowedTools = allowedTools;\n const permission = input.permission ?? base?.permission;\n if (permission !== undefined) cfg.permission = permission;\n const enabled = input.enabled ?? base?.enabled;\n if (enabled !== undefined) cfg.enabled = enabled;\n const lazy = input.lazy ?? base?.lazy;\n if (lazy !== undefined) cfg.lazy = lazy;\n const passthroughEnv = input.passthroughEnv ?? base?.passthroughEnv;\n if (passthroughEnv !== undefined) cfg.passthroughEnv = passthroughEnv;\n const health = input.health ?? base?.health;\n if (health !== undefined) cfg.health = health;\n return cfg;\n}\n\n/** Project a config entry + live registry state into a wire-friendly view. */\nfunction projectServer(name: string, cfg: MCPServerConfig, registry: MCPRegistry): McpServerInfo {\n const live = registry.list().find((s) => s.name === name);\n const info: McpServerInfo = {\n name,\n transport: cfg.transport,\n enabled: cfg.enabled !== false,\n status: live ? live.state : 'stopped',\n tools: live?.tools ?? [],\n };\n if (cfg.description !== undefined) info.description = cfg.description;\n if (cfg.url !== undefined) info.url = cfg.url;\n if (cfg.command !== undefined) info.command = cfg.command;\n if (cfg.args !== undefined) info.args = cfg.args;\n if (cfg.env !== undefined) info.env = cfg.env;\n if (cfg.lazy !== undefined) info.lazy = cfg.lazy;\n return info;\n}\n\nfunction liveState(name: string, registry: MCPRegistry): { state: string; tools: string[] } {\n const live = registry.list().find((s) => s.name === name);\n return { state: live?.state ?? 'stopped', tools: live?.tools ?? [] };\n}\n\nfunction errMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\n// \u2500\u2500 operations \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** List all configured servers, merged with live registry status + tool names. */\nexport async function listMcp(deps: McpManageDeps): Promise<McpServerInfo[]> {\n const { servers } = await readServers(deps.configPath);\n return Object.entries(servers).map(([name, cfg]) =>\n projectServer(name, { ...cfg, name }, deps.registry),\n );\n}\n\n/**\n * Add a new server. `input` may be a fully-specified config, or just a `name`\n * matching a known preset (`deps.presets`). Fails if the server already exists.\n * When enabled, the server is started immediately via the registry.\n */\nexport async function addMcp(input: McpServerInput, deps: McpManageDeps): Promise<McpOpResult> {\n if (!input.name) return { ok: false, message: 'Server name is required' };\n\n const { full, servers } = await readServers(deps.configPath);\n if (servers[input.name]) {\n return { ok: false, message: `Server \"${input.name}\" already exists` };\n }\n\n // Name-only add resolves a preset; an explicit transport/command means the\n // caller supplied the full config and the preset (if any) is just a base.\n const preset = deps.presets?.[input.name];\n const hasExplicitConfig = !!(input.transport || input.command || input.url);\n const cfg = hasExplicitConfig\n ? buildConfig(input, preset)\n : preset\n ? buildConfig({ ...input, name: input.name }, preset)\n : buildConfig(input);\n\n if (!hasExplicitConfig && !preset) {\n const known = Object.keys(deps.presets ?? {}).join(', ');\n return {\n ok: false,\n message: known\n ? `Unknown server \"${input.name}\". Available presets: ${known}`\n : `No configuration provided for \"${input.name}\"`,\n };\n }\n\n cfg.enabled = input.enabled ?? false;\n servers[input.name] = cfg;\n await persist(deps.configPath, full, servers);\n\n if (cfg.enabled) {\n return startServer(input.name, cfg, deps, `Server \"${input.name}\" added`);\n }\n trackDisabled(deps.registry, cfg);\n return {\n ok: true,\n message: `Server \"${input.name}\" added (disabled)`,\n server: projectServer(input.name, cfg, deps.registry),\n };\n}\n\n/** Update an existing server's config, then re-apply it to the live registry. */\nexport async function updateMcp(input: McpServerInput, deps: McpManageDeps): Promise<McpOpResult> {\n if (!input.name) return { ok: false, message: 'Server name is required' };\n\n const { full, servers } = await readServers(deps.configPath);\n const existing = servers[input.name];\n if (!existing) return { ok: false, message: `Server \"${input.name}\" not found` };\n\n const cfg = buildConfig(input, { ...existing, name: input.name });\n servers[input.name] = cfg;\n await persist(deps.configPath, full, servers);\n\n // Re-apply to the registry so edits take effect without a manual restart.\n if (cfg.enabled !== false) {\n return startServer(input.name, cfg, deps, `Server \"${input.name}\" updated`, { restart: true });\n }\n await safeStop(input.name, deps);\n trackDisabled(deps.registry, cfg);\n return {\n ok: true,\n message: `Server \"${input.name}\" updated`,\n server: projectServer(input.name, cfg, deps.registry),\n };\n}\n\n/** Remove a server from config and stop it if running. */\nexport async function removeMcp(name: string, deps: McpManageDeps): Promise<McpOpResult> {\n if (!name) return { ok: false, message: 'Server name is required' };\n const { full, servers } = await readServers(deps.configPath);\n if (!servers[name]) return { ok: false, message: `Server \"${name}\" not found` };\n\n await safeStop(name, deps);\n forgetRegistryState(deps.registry, name);\n delete servers[name];\n await persist(deps.configPath, full, servers);\n return { ok: true, message: `Server \"${name}\" removed` };\n}\n\n/** Enable a server in config and start it. */\nexport async function enableMcp(name: string, deps: McpManageDeps): Promise<McpOpResult> {\n if (!name) return { ok: false, message: 'Server name is required' };\n const { full, servers } = await readServers(deps.configPath);\n const cfg = servers[name];\n if (!cfg) {\n return { ok: false, message: `Server \"${name}\" is not in config. Add it first.` };\n }\n cfg.enabled = true;\n servers[name] = cfg;\n await persist(deps.configPath, full, servers);\n return startServer(name, cfg, deps, `Server \"${name}\" enabled`, { restart: true });\n}\n\n/** Disable a server in config and stop it. */\nexport async function disableMcp(name: string, deps: McpManageDeps): Promise<McpOpResult> {\n if (!name) return { ok: false, message: 'Server name is required' };\n const { full, servers } = await readServers(deps.configPath);\n const cfg = servers[name];\n if (!cfg) return { ok: false, message: `Server \"${name}\" is not in config.` };\n\n await safeStop(name, deps);\n cfg.enabled = false;\n trackDisabled(deps.registry, { ...cfg, name });\n servers[name] = cfg;\n await persist(deps.configPath, full, servers);\n return {\n ok: true,\n message: `Server \"${name}\" disabled`,\n server: projectServer(name, cfg, deps.registry),\n };\n}\n\n/** Restart a running server (or start it from config if registered but stopped). */\nexport async function restartMcp(name: string, deps: McpManageDeps): Promise<McpOpResult> {\n if (!name) return { ok: false, message: 'Server name is required' };\n const registered = deps.registry.list().some((s) => s.name === name);\n if (registered) {\n try {\n await deps.registry.restart(name);\n const { state, tools } = liveState(name, deps.registry);\n return { ok: true, message: `Server \"${name}\" restarted`, state, tools };\n } catch (err) {\n return { ok: false, message: `Failed to restart \"${name}\": ${errMessage(err)}` };\n }\n }\n // Not in the registry yet \u2014 start it from config if it exists and is enabled.\n const { servers } = await readServers(deps.configPath);\n const cfg = servers[name];\n if (!cfg) return { ok: false, message: `Server \"${name}\" is not in config.` };\n return startServer(name, { ...cfg, name }, deps, `Server \"${name}\" started`, { restart: true });\n}\n\n/**\n * Discover a server's tools. Tools are discovered on connect, so this ensures\n * the server is running and returns its live tool list.\n */\nexport async function discoverMcp(name: string, deps: McpManageDeps): Promise<McpOpResult> {\n if (!name) return { ok: false, message: 'Server name is required' };\n const result = await restartMcp(name, deps);\n if (!result.ok) return result;\n const { state, tools } = liveState(name, deps.registry);\n return {\n ok: true,\n message: `Discovered ${tools.length} tool${tools.length === 1 ? '' : 's'} from \"${name}\"`,\n state,\n tools,\n };\n}\n\n// \u2500\u2500 registry helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Start (or restart) a server in the registry. Config has already been\n * persisted by the caller; a registry failure is reported but not fatal \u2014 the\n * config change stands so the user can retry/restart.\n */\nasync function startServer(\n name: string,\n cfg: MCPServerConfig,\n deps: McpManageDeps,\n okMessage: string,\n opts?: { restart?: boolean },\n): Promise<McpOpResult> {\n try {\n const alreadyRegistered = deps.registry.list().some((s) => s.name === name);\n if (alreadyRegistered && opts?.restart) {\n await deps.registry.restart(name);\n } else if (alreadyRegistered) {\n await deps.registry.restart(name);\n } else {\n await deps.registry.start({ ...cfg, enabled: true });\n }\n const { state, tools } = liveState(name, deps.registry);\n return {\n ok: true,\n message: okMessage,\n server: projectServer(name, cfg, deps.registry),\n state,\n tools,\n };\n } catch (err) {\n const message = errMessage(err);\n return {\n ok: true, // config persisted \u2014 surface a soft warning, not a hard failure\n message: `${okMessage} in config, but failed to start: ${message}`,\n server: projectServer(name, cfg, deps.registry),\n registryError: message,\n };\n }\n}\n\n/** Stop a server, swallowing \"not running\" errors. */\nasync function safeStop(name: string, deps: McpManageDeps): Promise<void> {\n try {\n await deps.registry.stop(name);\n } catch {\n // Server may not be running \u2014 ignore.\n }\n}\n\nfunction trackDisabled(registry: MCPRegistry, cfg: MCPServerConfig): void {\n if (typeof registry.markDisabled === 'function') registry.markDisabled(cfg);\n}\n\nfunction forgetRegistryState(registry: MCPRegistry, name: string): void {\n if (typeof registry.forget === 'function') registry.forget(name);\n}\n", "/**\n * On-disk cache of MCP server capability manifests.\n *\n * Lazy-connect needs to register a server's tools WITHOUT spawning it. That is\n * only possible once we have seen the tool list at least once \u2014 so the first\n * successful connect persists the discovered `tools/list` here, and later boots\n * register resolver-backed wrappers straight from this cache.\n *\n * A `configHash` (over the connection-defining fields) is stored alongside the\n * tools so that changing a server's command/args/url/transport invalidates the\n * stale manifest and forces a fresh discovery connect.\n *\n * All operations are best-effort: a read miss or IO error simply means \"no\n * cache\", which falls back to a normal connect.\n */\nimport { createHash } from 'node:crypto';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type { MCPTool } from './client.js';\nimport {\n type MCPPrompt,\n type MCPResource,\n type MCPResourceTemplate,\n type MCPServerMetadata,\n parseListPromptsResult,\n parseListResourcesResult,\n parseListResourceTemplatesResult,\n parseServerMetadata,\n} from './protocol.js';\n\ninterface ManifestFile {\n version?: number | undefined;\n configHash: string;\n tools: MCPTool[];\n serverMetadata?: MCPServerMetadata | undefined;\n resources?: MCPResource[] | undefined;\n resourceTemplates?: MCPResourceTemplate[] | undefined;\n prompts?: MCPPrompt[] | undefined;\n}\n\nexport interface MCPCapabilityManifest {\n tools: MCPTool[];\n serverMetadata?: MCPServerMetadata | undefined;\n resources?: MCPResource[] | undefined;\n resourceTemplates?: MCPResourceTemplate[] | undefined;\n prompts?: MCPPrompt[] | undefined;\n}\n\n/** Stable hash of the fields that define how/where we connect to a server. */\nexport function manifestConfigHash(cfg: {\n transport: string;\n command?: string | undefined;\n args?: string[] | undefined;\n url?: string | undefined;\n}): string {\n const basis = JSON.stringify({\n transport: cfg.transport,\n command: cfg.command ?? null,\n args: cfg.args ?? null,\n url: cfg.url ?? null,\n });\n return createHash('sha256').update(basis).digest('hex').slice(0, 16);\n}\n\n/** Filesystem-safe file name for a server within the manifest cache dir. */\nfunction manifestFile(cacheDir: string, name: string): string {\n const safe = name.replace(/[^a-zA-Z0-9._-]/g, '_');\n return path.join(cacheDir, 'mcp-tools', `${safe}.json`);\n}\n\n/**\n * Read a server's cached tools. Returns null when there is no cache or when the\n * stored `configHash` no longer matches (server config changed \u2192 stale).\n */\nexport async function readManifest(\n cacheDir: string,\n name: string,\n configHash: string,\n): Promise<MCPTool[] | null> {\n const manifest = await readCapabilityManifest(cacheDir, name, configHash);\n return manifest?.tools ?? null;\n}\n\n/**\n * Read a complete capability manifest. Legacy tools-only files are accepted and\n * upgraded in memory, so existing lazy caches remain valid.\n */\nexport async function readCapabilityManifest(\n cacheDir: string,\n name: string,\n configHash: string,\n): Promise<MCPCapabilityManifest | null> {\n try {\n const raw = await fs.readFile(manifestFile(cacheDir, name), 'utf8');\n const parsed = JSON.parse(raw) as ManifestFile;\n if (parsed.configHash !== configHash || !Array.isArray(parsed.tools)) return null;\n return {\n tools: parsed.tools,\n serverMetadata:\n parsed.serverMetadata === undefined\n ? undefined\n : parseServerMetadata(parsed.serverMetadata),\n resources:\n parsed.resources === undefined\n ? undefined\n : parseListResourcesResult({ resources: parsed.resources }).resources,\n resourceTemplates:\n parsed.resourceTemplates === undefined\n ? undefined\n : parseListResourceTemplatesResult({ resourceTemplates: parsed.resourceTemplates })\n .resourceTemplates,\n prompts:\n parsed.prompts === undefined\n ? undefined\n : parseListPromptsResult({ prompts: parsed.prompts }).prompts,\n };\n } catch {\n return null;\n }\n}\n\n/** Persist a server's discovered tools. Best-effort \u2014 IO errors are swallowed. */\nexport async function writeManifest(\n cacheDir: string,\n name: string,\n configHash: string,\n tools: MCPTool[],\n): Promise<void> {\n const previous = await readCapabilityManifest(cacheDir, name, configHash);\n await writeCapabilityManifest(cacheDir, name, configHash, {\n ...previous,\n tools,\n });\n}\n\n/** Persist a complete capability manifest using an atomic replace. */\nexport async function writeCapabilityManifest(\n cacheDir: string,\n name: string,\n configHash: string,\n manifest: MCPCapabilityManifest,\n): Promise<void> {\n try {\n const file = manifestFile(cacheDir, name);\n await fs.mkdir(path.dirname(file), { recursive: true });\n const body: ManifestFile = { version: 2, configHash, ...manifest };\n const tmp = `${file}.tmp`;\n await fs.writeFile(tmp, JSON.stringify(body, null, 2), 'utf8');\n await fs.rename(tmp, file);\n } catch {\n // best-effort cache \u2014 a write failure just means a cold discovery next boot\n }\n}\n", "import type { MCPHealthThresholds } from '@wrongstack/core/types';\nimport type { ConnectionState } from './client.js';\n\n/** Operator-facing health state. Intentionally separate from transport lifecycle state. */\nexport type MCPHealthState =\n | 'disabled'\n | 'dormant'\n | 'connecting'\n | 'healthy'\n | 'degraded'\n | 'failed';\n\nexport type MCPFailureKind = 'transport' | 'protocol' | 'tool';\n\nexport type MCPOperationKind =\n | 'connect'\n | 'reconnect'\n | 'discover'\n | 'call'\n | 'wake'\n | 'sleep'\n | 'restart'\n | 'stop'\n | 'failure';\n\n/**\n * Safe lifecycle event. `reason` is a bounded code owned by WrongStack, never\n * a server error message, command, URL, tool name, argument, or token.\n */\nexport interface MCPOperationEvent {\n serverName: string;\n kind: MCPOperationKind;\n at: number;\n connectionState: ConnectionState;\n healthState: MCPHealthState;\n reason?: string | undefined;\n failureKind?: MCPFailureKind | undefined;\n durationMs?: number | undefined;\n}\n\nexport interface MCPLatencySummary {\n count: number;\n lastMs?: number | undefined;\n minMs?: number | undefined;\n maxMs?: number | undefined;\n p50Ms?: number | undefined;\n p95Ms?: number | undefined;\n}\n\nexport interface MCPServerOperationalHealth {\n name: string;\n connectionState: ConnectionState;\n healthState: MCPHealthState;\n lastSuccessAt?: number | undefined;\n lastFailureAt?: number | undefined;\n lastFailureKind?: MCPFailureKind | undefined;\n lastReason?: string | undefined;\n consecutiveFailures: number;\n failures: Record<MCPFailureKind, number>;\n reconnectCount: number;\n wakeCount: number;\n sleepCount: number;\n restartCount: number;\n connectionLatency: MCPLatencySummary;\n discoveryLatency: MCPLatencySummary;\n callLatency: MCPLatencySummary;\n inFlightCalls: number;\n peakInFlightCalls: number;\n recentEvents: MCPOperationEvent[];\n /** Last evaluation of configured health thresholds; empty if none configured. */\n healthChecks: MCPHealthCheckResult[];\n}\n\n/** Result of comparing one operational metric against its configured threshold. */\nexport interface MCPHealthCheckResult {\n name: string;\n passed: boolean;\n value?: number | undefined;\n threshold?: number | undefined;\n}\n\nexport type MCPOperationListener = (event: Readonly<MCPOperationEvent>) => void;\n\nexport const MCP_OPERATION_LIMITS = Object.freeze({\n LATENCY_SAMPLES: 128,\n RECENT_EVENTS: 32,\n REASON_CHARS: 64,\n});\n\nconst SAFE_OPERATION_REASONS = new Set([\n 'automatic',\n 'complete',\n 'connect-attempt-failed',\n 'connected',\n 'http-disconnect',\n 'http-disconnect-lazy',\n 'idle-timeout',\n 'lazy-demand',\n 'manual',\n 'ok',\n 'process-exit',\n 'process-exit-lazy',\n 'prompt-discovery-failed',\n 'reconnect-exhausted',\n 'resource-discovery-failed',\n 'resource-template-discovery-failed',\n 'started',\n 'tool-call-failed',\n]);\n\nexport interface MCPServerOperationState {\n lastSuccessAt?: number | undefined;\n lastFailureAt?: number | undefined;\n lastFailureKind?: MCPFailureKind | undefined;\n lastReason?: string | undefined;\n consecutiveFailures: number;\n failures: Record<MCPFailureKind, number>;\n reconnectCount: number;\n wakeCount: number;\n sleepCount: number;\n restartCount: number;\n connectionSamples: number[];\n discoverySamples: number[];\n callSamples: number[];\n inFlightCalls: number;\n peakInFlightCalls: number;\n recentEvents: MCPOperationEvent[];\n}\n\nexport function createMCPServerOperationState(): MCPServerOperationState {\n return {\n consecutiveFailures: 0,\n failures: { transport: 0, protocol: 0, tool: 0 },\n reconnectCount: 0,\n wakeCount: 0,\n sleepCount: 0,\n restartCount: 0,\n connectionSamples: [],\n discoverySamples: [],\n callSamples: [],\n inFlightCalls: 0,\n peakInFlightCalls: 0,\n recentEvents: [],\n };\n}\n\nexport function healthStateFor(\n connectionState: ConnectionState,\n operations: MCPServerOperationState,\n enabled = true,\n): MCPHealthState {\n if (!enabled) return 'disabled';\n if (connectionState === 'dormant') return 'dormant';\n if (\n connectionState === 'connecting' ||\n connectionState === 'reconnecting' ||\n connectionState === 'idle'\n ) {\n return 'connecting';\n }\n if (connectionState === 'failed') return 'failed';\n if (connectionState === 'disconnected' || operations.consecutiveFailures > 0) return 'degraded';\n return 'healthy';\n}\n\n/**\n * Compare bounded latency/in-flight samples against configured thresholds.\n * Returns one check per configured threshold. All thresholds are optional;\n * omitted thresholds produce no check and cannot mark a server degraded.\n */\nexport function evaluateHealthThresholds(\n operations: MCPServerOperationState,\n thresholds: MCPHealthThresholds | undefined,\n): MCPHealthCheckResult[] {\n if (!thresholds) return [];\n const checks: MCPHealthCheckResult[] = [];\n if (thresholds.connectionLatencyP95Ms !== undefined && operations.connectionSamples.length > 0) {\n const value = percentile([...operations.connectionSamples].sort((a, b) => a - b), 0.95);\n checks.push({\n name: 'connection-latency-p95',\n passed: value <= thresholds.connectionLatencyP95Ms,\n value,\n threshold: thresholds.connectionLatencyP95Ms,\n });\n }\n if (thresholds.discoveryLatencyP95Ms !== undefined && operations.discoverySamples.length > 0) {\n const value = percentile([...operations.discoverySamples].sort((a, b) => a - b), 0.95);\n checks.push({\n name: 'discovery-latency-p95',\n passed: value <= thresholds.discoveryLatencyP95Ms,\n value,\n threshold: thresholds.discoveryLatencyP95Ms,\n });\n }\n if (thresholds.callLatencyP95Ms !== undefined && operations.callSamples.length > 0) {\n const value = percentile([...operations.callSamples].sort((a, b) => a - b), 0.95);\n checks.push({\n name: 'call-latency-p95',\n passed: value <= thresholds.callLatencyP95Ms,\n value,\n threshold: thresholds.callLatencyP95Ms,\n });\n }\n if (thresholds.inFlightCalls !== undefined) {\n checks.push({\n name: 'in-flight-calls',\n passed: operations.peakInFlightCalls <= thresholds.inFlightCalls,\n value: operations.peakInFlightCalls,\n threshold: thresholds.inFlightCalls,\n });\n }\n return checks;\n}\n\n/**\n * Apply threshold checks to a lifecycle-derived health state. Only `healthy`\n * can be downgraded to `degraded`; existing degraded/failed states are kept\n * so the original lifecycle reason remains authoritative.\n */\nexport function applyHealthThresholds(\n state: MCPHealthState,\n checks: readonly MCPHealthCheckResult[],\n): MCPHealthState {\n if (state !== 'healthy') return state;\n return checks.some((c) => !c.passed) ? 'degraded' : 'healthy';\n}\n\nexport function summarizeLatency(samples: readonly number[]): MCPLatencySummary {\n if (samples.length === 0) return { count: 0 };\n const sorted = [...samples].sort((a, b) => a - b);\n return {\n count: samples.length,\n lastMs: samples[samples.length - 1],\n minMs: sorted[0],\n maxMs: sorted[sorted.length - 1],\n p50Ms: percentile(sorted, 0.5),\n p95Ms: percentile(sorted, 0.95),\n };\n}\n\nexport function pushBounded<T>(target: T[], value: T, limit: number): void {\n target.push(value);\n if (target.length > limit) target.splice(0, target.length - limit);\n}\n\nexport function safeOperationReason(reason: string): string {\n const normalized = reason.toLowerCase().replace(/[^a-z0-9_.:-]+/g, '-');\n const bounded = normalized.slice(0, MCP_OPERATION_LIMITS.REASON_CHARS);\n return SAFE_OPERATION_REASONS.has(bounded) ? bounded : 'other';\n}\n\nfunction percentile(sorted: readonly number[], ratio: number): number {\n return sorted[Math.min(sorted.length - 1, Math.max(0, Math.ceil(sorted.length * ratio) - 1))]!;\n}\n", "import type { EventBus } from '@wrongstack/core/kernel';\nimport type { ToolRegistry } from '@wrongstack/core/registry';\nimport type { Logger, MCPServerConfig, Tool } from '@wrongstack/core/types';\nimport { expectDefined } from '@wrongstack/core/utils';\nimport type { MCPAuthorizationProvider } from './authorization.js';\nimport type {\n MCPAuthorizationManager,\n MCPAuthorizationStartResult,\n MCPAuthorizationStatus,\n} from './authorization-manager.js';\nimport { type ConnectionState, MCPClient, type MCPTool } from './client.js';\nimport { MCP_CONSTANTS } from './constants.js';\nimport {\n type MCPInsertionPolicy,\n type MCPPromptInsertion,\n type MCPResourceInsertion,\n preparePromptInsertion,\n prepareResourceInsertion,\n} from './content-selection.js';\nimport {\n manifestConfigHash,\n readCapabilityManifest,\n writeCapabilityManifest,\n} from './manifest-cache.js';\nimport {\n applyHealthThresholds,\n createMCPServerOperationState,\n evaluateHealthThresholds,\n healthStateFor,\n MCP_OPERATION_LIMITS,\n type MCPFailureKind,\n type MCPOperationEvent,\n type MCPOperationKind,\n type MCPOperationListener,\n type MCPServerOperationalHealth,\n type MCPServerOperationState,\n pushBounded,\n safeOperationReason,\n summarizeLatency,\n} from './operations.js';\nimport type {\n MCPGetPromptResult,\n MCPPrompt,\n MCPReadResourceResult,\n MCPResource,\n MCPResourceTemplate,\n MCPServerMetadata,\n} from './protocol.js';\nimport { wrapMCPTool } from './wrap-tool.js';\n\ninterface ServerSlot {\n cfg: MCPServerConfig;\n client?: MCPClient | undefined;\n state: ConnectionState;\n /** Tools currently registered in toolRegistry (empty in lazy mode). */\n toolNames: string[];\n /** Cached tools when lazyMode is active (not registered in toolRegistry). */\n lazyTools: Tool[];\n serverMetadata?: MCPServerMetadata | undefined;\n resources?: MCPResource[] | undefined;\n resourceTemplates?: MCPResourceTemplate[] | undefined;\n prompts?: MCPPrompt[] | undefined;\n /** Serializes replacements so rapid list-change notifications cannot restore stale data. */\n manifestWrite?: Promise<void> | undefined;\n attempts: number;\n /** Set when a reconnect cycle is already running for this slot. */\n reconnectPending: boolean;\n /**\n * Handle to the pending backoff timer scheduled by `scheduleReconnect`.\n * Stored so `stop` / `stopAll` / `sleepIdle` / exhaustion paths can cancel\n * it \u2014 a stale timer that fires after the slot has been torn down would\n * resurrect the server via `attemptReconnect` (which doesn't gate on\n * `slot.state`).\n */\n reconnectTimer?: NodeJS.Timeout | undefined;\n /**\n * L2-B: number of full reconnect *cycles* (where one cycle = one\n * `attemptConnect` invocation, which itself can try multiple times\n * before giving up). After `MAX_RECONNECT_CYCLES`, the slot stays\n * `failed` until a manual `restart()` resets it.\n */\n reconnectCycles: number;\n /**\n * Slot-scoped, bound disconnect callback. Stored so the matching\n * `removeDisconnectListener` call can hand back the *same* reference \u2014\n * a fresh arrow `() => onTransportDisconnect(slot.cfg.name)` would\n * not match the one we added and the set-based listener registry\n * would silently keep the old handler, causing duplicate reconnect\n * cycles after a few transport flaps.\n */\n onDisconnect?: (() => void) | undefined;\n /**\n * Lazy-connect: the server process is not spawned at boot. Tools are\n * registered from a cached manifest and the process only spawns on the first\n * tool call (via {@link MCPRegistry.ensureConnected}), then auto-sleeps.\n */\n lazy: boolean;\n /** Epoch ms of the last tool call \u2014 drives idle auto-sleep. */\n lastUsed: number;\n /** Single-flight guard so concurrent first-calls trigger only one connect. */\n connecting?: Promise<MCPClient> | undefined;\n /** Whether this lazy server's resolver wrappers are registered (register once). */\n registeredLazy: boolean;\n /** Bounded, payload-free operational telemetry for this server. */\n operations: MCPServerOperationState;\n}\n\nexport interface MCPRegistryOptions {\n toolRegistry: ToolRegistry;\n events: EventBus;\n log: Logger;\n /**\n * Directory for the on-disk tool-manifest cache (lazy-connect). Without it,\n * `lazy` servers cannot register tools cold and fall back to eager connect.\n * Typically `wpaths.cacheDir` (`~/.wrongstack/cache`).\n */\n cacheDir?: string | undefined;\n /**\n * Idle window (ms) after which a connected lazy server is auto-stopped and\n * re-woken on the next tool call. 0 disables idle auto-sleep.\n * Default: {@link MCP_CONSTANTS.IDLE.DEFAULT_TIMEOUT_MS}.\n */\n idleTimeoutMs?: number | undefined;\n /**\n * Lazy mode: when true, MCP server tools are NOT registered into the\n * tool registry on connect. They are cached internally and can be\n * activated on demand via `activateServer(name)`. This is used in\n * token-saving mode to avoid bloating the system prompt with 50-100+\n * MCP tool descriptions. The model uses `mcp_control({ action: \"activate\", server: \"...\" })`\n * to temporarily enable tools when needed.\n * Default: false.\n */\n lazyMode?: boolean | undefined;\n /** Resolve host-owned, vault-backed OAuth state for an HTTP server. */\n authorizationProviderFactory?:\n | ((server: Readonly<MCPServerConfig>) => MCPAuthorizationProvider | undefined)\n | undefined;\n /** Coordinate manual/headless OAuth start, completion, status, and logout. */\n authorizationManager?: MCPAuthorizationManager | undefined;\n}\n\nexport interface MCPRegistryCatalog {\n name: string;\n state: ConnectionState;\n serverMetadata?: MCPServerMetadata | undefined;\n resources?: MCPResource[] | undefined;\n resourceTemplates?: MCPResourceTemplate[] | undefined;\n prompts?: MCPPrompt[] | undefined;\n}\n\nexport class MCPRegistry {\n private readonly servers = new Map<string, ServerSlot>();\n /** Configured-off servers are tracked without creating a transport/client. */\n private readonly disabledServers = new Map<string, MCPServerConfig>();\n private readonly toolRegistry: ToolRegistry;\n private readonly events: EventBus;\n private readonly log: Logger;\n private readonly lazyMode: boolean;\n private readonly cacheDir?: string | undefined;\n private readonly idleTimeoutMs: number;\n private readonly authorizationProviderFactory?: MCPRegistryOptions['authorizationProviderFactory'];\n private readonly authorizationManager?: MCPAuthorizationManager | undefined;\n private readonly operationListeners = new Set<MCPOperationListener>();\n /** Single shared idle sweep timer (started lazily; unref'd; cleared on stopAll). */\n private idleTimer?: ReturnType<typeof setInterval> | undefined;\n\n constructor(opts: MCPRegistryOptions) {\n this.toolRegistry = opts.toolRegistry;\n this.events = opts.events;\n this.log = opts.log;\n this.lazyMode = opts.lazyMode ?? false;\n this.cacheDir = opts.cacheDir;\n this.idleTimeoutMs = opts.idleTimeoutMs ?? MCP_CONSTANTS.IDLE.DEFAULT_TIMEOUT_MS;\n this.authorizationProviderFactory = opts.authorizationProviderFactory;\n this.authorizationManager = opts.authorizationManager;\n }\n\n private requireSlot(name: string): ServerSlot {\n const slot = this.servers.get(name);\n if (!slot) throw new Error(`MCP server \"${name}\" not registered`);\n return slot;\n }\n\n async beginAuthorization(\n name: string,\n input: {\n clientId: string;\n redirectUri: string;\n scopes?: readonly string[] | undefined;\n challengeHeader?: string | null | undefined;\n signal?: AbortSignal | undefined;\n },\n ): Promise<MCPAuthorizationStartResult> {\n const manager = this.requireAuthorizationManager();\n const cfg = this.requireHttpServerConfig(name);\n return manager.begin({\n serverName: name,\n resource: cfg.url!,\n ...input,\n });\n }\n\n async completeAuthorization(\n name: string,\n callbackUrl: string,\n signal?: AbortSignal | undefined,\n ): Promise<MCPAuthorizationStatus> {\n const manager = this.requireAuthorizationManager();\n const cfg = this.requireHttpServerConfig(name);\n return manager.complete({ serverName: name, resource: cfg.url!, callbackUrl, signal });\n }\n\n async authorizationStatus(name: string): Promise<MCPAuthorizationStatus> {\n const manager = this.requireAuthorizationManager();\n const cfg = this.requireHttpServerConfig(name);\n return manager.status(name, cfg.url!);\n }\n\n async disconnectAuthorization(name: string): Promise<boolean> {\n const manager = this.requireAuthorizationManager();\n const cfg = this.requireHttpServerConfig(name);\n return manager.disconnect(name, cfg.url!);\n }\n\n private requireAuthorizationManager(): MCPAuthorizationManager {\n if (!this.authorizationManager) {\n throw new Error('MCP authorization management is not configured for this host');\n }\n return this.authorizationManager;\n }\n\n private requireHttpServerConfig(name: string): MCPServerConfig {\n const cfg = this.servers.get(name)?.cfg ?? this.disabledServers.get(name);\n if (!cfg) throw new Error(`MCP server \"${name}\" not registered`);\n if (cfg.transport === 'stdio' || !cfg.url) {\n throw new Error(`MCP server \"${name}\" does not use an HTTP transport`);\n }\n return cfg;\n }\n\n async start(cfg: MCPServerConfig): Promise<void> {\n if (cfg.enabled === false) {\n if (this.servers.has(cfg.name)) {\n await this.stop(cfg.name);\n }\n this.markDisabled(cfg);\n return;\n }\n this.disabledServers.delete(cfg.name);\n // Reject duplicate registrations explicitly. Without this, calling\n // start() twice with the same name would overwrite the slot in\n // `this.servers` and orphan the previous slot's client (still\n // connected, with listeners wired into a slot that's no longer\n // reachable from the registry). Callers that want a clean re-start\n // should use `restart(name)`.\n if (this.servers.has(cfg.name)) {\n throw new Error(\n `MCP server \"${cfg.name}\" is already registered \u2014 use restart() to re-cycle a running server`,\n );\n }\n // Lazy-connect requires a manifest cache dir to register tools cold.\n const lazy = !!cfg.lazy && !!this.cacheDir;\n const slot: ServerSlot = {\n cfg,\n state: 'idle',\n toolNames: [],\n lazyTools: [],\n attempts: 0,\n reconnectPending: false,\n reconnectCycles: 0,\n lazy,\n lastUsed: Date.now(),\n registeredLazy: false,\n operations: createMCPServerOperationState(),\n };\n this.servers.set(cfg.name, slot);\n if (lazy) {\n await this.startLazy(slot);\n } else {\n await this.attemptConnect(slot);\n }\n }\n\n /** Record an intentionally disabled configuration without opening a transport. */\n markDisabled(cfg: MCPServerConfig): void {\n this.servers.delete(cfg.name);\n this.disabledServers.set(cfg.name, { ...cfg, enabled: false });\n }\n\n /** Remove residual operational/configuration state after a management delete. */\n forget(name: string): void {\n this.servers.delete(name);\n this.disabledServers.delete(name);\n }\n\n /**\n * Boot a lazy server WITHOUT spawning it. If a tool manifest is cached (from a\n * prior connect with matching config), register resolver-backed wrappers and\n * go `dormant` \u2014 the process spawns on the first tool call. If there is no\n * cache yet, do a one-time cold discovery connect to learn + cache the tools.\n */\n private async startLazy(slot: ServerSlot): Promise<void> {\n const cacheDir = this.cacheDir;\n if (!cacheDir) {\n await this.attemptConnect(slot);\n return;\n }\n const hash = manifestConfigHash(slot.cfg);\n const cached = await readCapabilityManifest(cacheDir, slot.cfg.name, hash);\n if (cached) {\n slot.serverMetadata = cached.serverMetadata;\n slot.resources = cached.resources;\n slot.resourceTemplates = cached.resourceTemplates;\n slot.prompts = cached.prompts;\n this.applyTools(slot, cached.tools);\n slot.state = 'dormant';\n this.ensureIdleSweep();\n this.log.info(\n `MCP server \"${slot.cfg.name}\" registered lazily from cache (${cached.tools.length} tools, dormant)`,\n );\n return;\n }\n // No cache \u2014 must connect once to discover the tool list, then it stays\n // connected and becomes eligible for idle auto-sleep.\n await this.attemptConnect(slot);\n }\n\n /**\n * Ensure a lazy server is connected, spawning it on demand. Single-flight:\n * concurrent first-calls share one connect. Resolver wrappers call this.\n */\n async ensureConnected(name: string): Promise<MCPClient> {\n const slot = this.servers.get(name);\n if (!slot) throw new Error(`MCP server \"${name}\" not registered`);\n slot.lastUsed = Date.now();\n if (slot.client && slot.state === 'connected') return slot.client;\n if (slot.connecting) return slot.connecting;\n const waking = slot.state === 'dormant';\n if (waking) {\n slot.operations.wakeCount++;\n this.recordOperation(slot, 'wake', 'lazy-demand');\n }\n slot.connecting = (async () => {\n try {\n // start fresh budget \u2014 a deliberate wake is not a crash-reconnect.\n slot.attempts = 0;\n slot.reconnectCycles = 0;\n await this.attemptConnect(slot);\n if (!slot.client) {\n throw new Error(`MCP server \"${name}\" failed to connect on demand`);\n }\n slot.lastUsed = Date.now();\n this.ensureIdleSweep();\n return slot.client;\n } finally {\n slot.connecting = undefined;\n }\n })();\n return slot.connecting;\n }\n\n /**\n * Register all cached tools for a given server into the tool registry.\n * No-op if tools are already registered or the server is not connected.\n * The server connection stays alive \u2014 this only toggles tool visibility.\n */\n activateServer(name: string): void {\n const slot = this.servers.get(name);\n if (!slot) return;\n // A dormant lazy server has no client yet \u2014 its resolver wrappers connect on\n // demand, so it can still be activated (registered) without a live process.\n if (!slot.client && !slot.lazy) return;\n if (slot.toolNames.length > 0) return; // already active\n const cached = slot.lazyTools;\n if (cached.length === 0) return;\n for (const tool of cached) {\n try {\n this.toolRegistry.register(tool, `mcp:${name}`);\n slot.toolNames.push(tool.name);\n } catch (err) {\n this.log.warn(`MCP tool \"${tool.name}\" activate failed`, err);\n }\n }\n this.log.info(`MCP server \"${name}\" activated (${slot.toolNames.length} tools)`);\n this.events.emit('mcp.server.connected', { name, toolCount: slot.toolNames.length });\n }\n\n /**\n * Unregister all tools for a given server from the tool registry.\n * The server connection stays alive \u2014 this only toggles tool visibility.\n * Returns the number of tools that were deactivated.\n */\n deactivateServer(name: string): number {\n const slot = this.servers.get(name);\n if (!slot) return 0;\n const count = slot.toolNames.length;\n if (count === 0) return 0;\n for (const t of slot.toolNames) {\n try {\n this.toolRegistry.unregister(t);\n } catch {\n /* ignore */\n }\n }\n slot.toolNames = [];\n this.log.info(`MCP server \"${name}\" deactivated (${count} tools removed)`);\n this.events.emit('mcp.server.disconnected', { name, reason: 'deactivate' });\n return count;\n }\n\n /**\n * Check whether a server's tools are currently registered.\n */\n isActivated(name: string): boolean {\n const slot = this.servers.get(name);\n return slot ? slot.toolNames.length > 0 : false;\n }\n\n async stop(name: string): Promise<void> {\n const slot = this.servers.get(name);\n if (!slot) return;\n slot.reconnectPending = false;\n // Cancel the pending backoff timer. Without this, a disconnect scheduled\n // for reconnection would fire its `attemptReconnect` callback after the\n // slot has been torn down and respawn the server we just told to stop.\n if (slot.reconnectTimer) {\n clearTimeout(slot.reconnectTimer);\n slot.reconnectTimer = undefined;\n }\n if (slot.client) {\n slot.client.removeExitListener(this.onChildExit);\n if (slot.onDisconnect) slot.client.removeDisconnectListener(slot.onDisconnect);\n slot.client.removeToolsChangedListener(this.onToolsChanged);\n this.removeCatalogListeners(slot.client);\n await slot.client.close();\n slot.client = undefined;\n }\n slot.onDisconnect = undefined;\n slot.connecting = undefined;\n for (const t of slot.toolNames) this.toolRegistry.unregister(t);\n slot.toolNames = [];\n slot.lazyTools = [];\n slot.serverMetadata = undefined;\n slot.resources = undefined;\n slot.resourceTemplates = undefined;\n slot.prompts = undefined;\n // Full teardown \u2014 a future start()/restart() re-registers lazy wrappers.\n slot.registeredLazy = false;\n slot.state = 'disconnected';\n this.recordOperation(slot, 'stop', 'manual');\n this.events.emit('mcp.server.disconnected', { name, reason: 'stop' });\n }\n\n async restart(name: string): Promise<void> {\n const slot = this.servers.get(name);\n if (!slot) throw new Error(`MCP server \"${name}\" not registered`);\n slot.operations.restartCount++;\n this.recordOperation(slot, 'restart', 'manual');\n await this.stop(name);\n slot.attempts = 0;\n slot.reconnectCycles = 0; // user intent: start fresh\n await this.attemptConnect(slot);\n }\n\n list(): { name: string; state: ConnectionState; toolCount: number; tools: string[] }[] {\n return Array.from(this.servers.values()).map((s) => {\n const tools = this.toolNamesForSlot(s);\n return {\n name: s.cfg.name,\n state: s.state,\n toolCount: tools.length,\n tools,\n };\n });\n }\n\n /**\n * Subscribe to payload-free operational signals. Callers must still avoid\n * using `serverName` as an unbounded metric label.\n */\n onOperation(listener: MCPOperationListener): () => void {\n this.operationListeners.add(listener);\n return () => this.operationListeners.delete(listener);\n }\n\n /** Detailed, defensively-copied operational snapshots for CLI/WebUI/HQ. */\n operationalHealth(): MCPServerOperationalHealth[] {\n const active = Array.from(this.servers.values()).map((slot) => {\n const op = slot.operations;\n const baseHealth = healthStateFor(slot.state, op, slot.cfg.enabled !== false);\n const checks = evaluateHealthThresholds(op, slot.cfg.health?.thresholds);\n return {\n name: slot.cfg.name,\n connectionState: slot.state,\n healthState: applyHealthThresholds(baseHealth, checks),\n lastSuccessAt: op.lastSuccessAt,\n lastFailureAt: op.lastFailureAt,\n lastFailureKind: op.lastFailureKind,\n lastReason: op.lastReason,\n consecutiveFailures: op.consecutiveFailures,\n failures: { ...op.failures },\n reconnectCount: op.reconnectCount,\n wakeCount: op.wakeCount,\n sleepCount: op.sleepCount,\n restartCount: op.restartCount,\n connectionLatency: summarizeLatency(op.connectionSamples),\n discoveryLatency: summarizeLatency(op.discoverySamples),\n callLatency: summarizeLatency(op.callSamples),\n inFlightCalls: op.inFlightCalls,\n peakInFlightCalls: op.peakInFlightCalls,\n recentEvents: op.recentEvents.map((event) => ({ ...event })),\n healthChecks: checks,\n };\n });\n const disabled = Array.from(this.disabledServers.values()).map((cfg) => {\n const operations = createMCPServerOperationState();\n return {\n name: cfg.name,\n connectionState: 'idle' as const,\n healthState: 'disabled' as const,\n consecutiveFailures: 0,\n failures: { ...operations.failures },\n reconnectCount: 0,\n wakeCount: 0,\n sleepCount: 0,\n restartCount: 0,\n connectionLatency: summarizeLatency([]),\n discoveryLatency: summarizeLatency([]),\n callLatency: summarizeLatency([]),\n inFlightCalls: 0,\n peakInFlightCalls: 0,\n recentEvents: [],\n healthChecks: [],\n };\n });\n return [...active, ...disabled];\n }\n\n getCatalog(name: string): MCPRegistryCatalog | undefined {\n const slot = this.servers.get(name);\n if (!slot) return undefined;\n return catalogSnapshot(slot);\n }\n\n async listResources(name: string, opts: { refresh?: boolean } = {}): Promise<MCPResource[]> {\n const slot = this.requireSlot(name);\n if (!opts.refresh && slot.resources) return cloneRecords(slot.resources);\n const client = await this.ensureConnected(name);\n if (!client.getServerMetadata()?.capabilities.resources) return [];\n slot.resources = await collectPages(\n (cursor) => client.listResources(cursor ? { cursor } : {}),\n (page) => page.resources,\n );\n await this.persistCapabilityManifest(slot);\n return cloneRecords(slot.resources);\n }\n\n async listResourceTemplates(\n name: string,\n opts: { refresh?: boolean } = {},\n ): Promise<MCPResourceTemplate[]> {\n const slot = this.requireSlot(name);\n if (!opts.refresh && slot.resourceTemplates) return cloneRecords(slot.resourceTemplates);\n const client = await this.ensureConnected(name);\n if (!client.getServerMetadata()?.capabilities.resources) return [];\n slot.resourceTemplates = await collectPages(\n (cursor) => client.listResourceTemplates(cursor ? { cursor } : {}),\n (page) => page.resourceTemplates,\n );\n await this.persistCapabilityManifest(slot);\n return cloneRecords(slot.resourceTemplates);\n }\n\n async readResource(name: string, uri: string): Promise<MCPReadResourceResult> {\n return (await this.ensureConnected(name)).readResource(uri);\n }\n\n async selectResourceForInsertion(\n name: string,\n uri: string,\n policy?: MCPInsertionPolicy | undefined,\n ): Promise<MCPResourceInsertion> {\n return prepareResourceInsertion(name, uri, await this.readResource(name, uri), policy);\n }\n\n async subscribeResource(name: string, uri: string): Promise<void> {\n await (await this.ensureConnected(name)).subscribeResource(uri);\n }\n\n async unsubscribeResource(name: string, uri: string): Promise<void> {\n await (await this.ensureConnected(name)).unsubscribeResource(uri);\n }\n\n async listPrompts(name: string, opts: { refresh?: boolean } = {}): Promise<MCPPrompt[]> {\n const slot = this.requireSlot(name);\n if (!opts.refresh && slot.prompts) return cloneRecords(slot.prompts);\n const client = await this.ensureConnected(name);\n if (!client.getServerMetadata()?.capabilities.prompts) return [];\n slot.prompts = await collectPages(\n (cursor) => client.listPrompts(cursor ? { cursor } : {}),\n (page) => page.prompts,\n );\n await this.persistCapabilityManifest(slot);\n return cloneRecords(slot.prompts);\n }\n\n async getPrompt(\n serverName: string,\n promptName: string,\n args?: Record<string, string> | undefined,\n ): Promise<MCPGetPromptResult> {\n return (await this.ensureConnected(serverName)).getPrompt(promptName, args);\n }\n\n async selectPromptForInsertion(\n serverName: string,\n promptName: string,\n args?: Record<string, string> | undefined,\n policy?: MCPInsertionPolicy | undefined,\n ): Promise<MCPPromptInsertion> {\n return preparePromptInsertion(\n serverName,\n promptName,\n args,\n await this.getPrompt(serverName, promptName, args),\n policy,\n );\n }\n\n /**\n * Resolve the live tool names for a slot \u2014 the registered names in normal\n * mode, or the cached lazy-tool names when running in lazy mode (where\n * tools are connected but intentionally not registered).\n */\n private toolNamesForSlot(s: ServerSlot): string[] {\n return s.toolNames.length > 0 ? s.toolNames.slice() : (s.lazyTools ?? []).map((t) => t.name);\n }\n\n /**\n * Wrap + register (or cache) a server's tools. Lazy servers get resolver-backed\n * wrappers that spawn the process on first use; eager servers bind the live\n * client directly. Honours token-saving `lazyMode` (cache, don't register) and\n * a register-once guard for lazy resolver wrappers (so a wake/reconnect reuses\n * the existing registrations rather than churning the tool list).\n */\n private applyTools(slot: ServerSlot, tools: MCPTool[], client?: MCPClient | undefined): void {\n // Resolver wrappers survive sleep/wake \u2014 only register them once.\n if (slot.lazy && slot.registeredLazy && !this.lazyMode) return;\n const allowed = slot.cfg.allowedTools;\n const filtered = tools.filter((t) => !allowed || allowed.includes(t.name));\n const clientArg = slot.lazy ? () => this.ensureConnected(slot.cfg.name) : expectDefined(client);\n const wrapped = filtered.map((t) =>\n wrapMCPTool(slot.cfg.name, t, clientArg, slot.cfg.permission ?? 'confirm', {\n onStart: () => {\n slot.operations.inFlightCalls++;\n slot.operations.peakInFlightCalls = Math.max(\n slot.operations.peakInFlightCalls,\n slot.operations.inFlightCalls,\n );\n this.recordOperation(slot, 'call', 'started', undefined, undefined, false);\n },\n onFinish: ({ durationMs, ok }) => {\n slot.operations.inFlightCalls = Math.max(0, slot.operations.inFlightCalls - 1);\n pushBounded(\n slot.operations.callSamples,\n durationMs,\n MCP_OPERATION_LIMITS.LATENCY_SAMPLES,\n );\n if (ok) {\n this.recordSuccess(slot);\n this.recordOperation(slot, 'call', 'ok', undefined, durationMs, false);\n } else {\n this.recordFailure(slot, 'tool', 'tool-call-failed', durationMs);\n }\n },\n }),\n );\n if (this.lazyMode) {\n // Token-saving mode: cache without registering (mcp_use activates on demand).\n slot.lazyTools = wrapped;\n return;\n }\n for (const tool of wrapped) {\n try {\n this.toolRegistry.register(tool, `mcp:${slot.cfg.name}`);\n slot.toolNames.push(tool.name);\n } catch (err) {\n this.log.warn(`MCP tool \"${tool.name}\" not registered`, err);\n }\n }\n if (slot.lazy && wrapped.length > 0) slot.registeredLazy = true;\n }\n\n private async discoverCapabilities(slot: ServerSlot, client: MCPClient): Promise<void> {\n const startedAt = Date.now();\n slot.serverMetadata = client.getServerMetadata();\n const capabilities = slot.serverMetadata?.capabilities;\n if (capabilities?.resources) {\n try {\n slot.resources = await collectPages(\n (cursor) => client.listResources(cursor ? { cursor } : {}),\n (page) => page.resources,\n );\n } catch (err) {\n slot.resources = undefined;\n this.recordFailure(slot, 'protocol', 'resource-discovery-failed');\n this.log.warn(`MCP server \"${slot.cfg.name}\" resource discovery failed`, err);\n }\n try {\n slot.resourceTemplates = await collectPages(\n (cursor) => client.listResourceTemplates(cursor ? { cursor } : {}),\n (page) => page.resourceTemplates,\n );\n } catch (err) {\n slot.resourceTemplates = undefined;\n this.recordFailure(slot, 'protocol', 'resource-template-discovery-failed');\n this.log.warn(`MCP server \"${slot.cfg.name}\" resource template discovery failed`, err);\n }\n } else {\n slot.resources = undefined;\n slot.resourceTemplates = undefined;\n }\n if (capabilities?.prompts) {\n try {\n slot.prompts = await collectPages(\n (cursor) => client.listPrompts(cursor ? { cursor } : {}),\n (page) => page.prompts,\n );\n } catch (err) {\n slot.prompts = undefined;\n this.recordFailure(slot, 'protocol', 'prompt-discovery-failed');\n this.log.warn(`MCP server \"${slot.cfg.name}\" prompt discovery failed`, err);\n }\n } else {\n slot.prompts = undefined;\n }\n const durationMs = Date.now() - startedAt;\n pushBounded(slot.operations.discoverySamples, durationMs, MCP_OPERATION_LIMITS.LATENCY_SAMPLES);\n this.recordOperation(slot, 'discover', 'complete', undefined, durationMs, false);\n }\n\n private async persistCapabilityManifest(slot: ServerSlot): Promise<void> {\n if (!slot.lazy || !this.cacheDir) return;\n const cacheDir = this.cacheDir;\n const previous = slot.manifestWrite ?? Promise.resolve();\n const pending = previous.then(() =>\n writeCapabilityManifest(cacheDir, slot.cfg.name, manifestConfigHash(slot.cfg), {\n tools: slot.client?.listTools() ?? [],\n serverMetadata: slot.serverMetadata,\n resources: slot.resources,\n resourceTemplates: slot.resourceTemplates,\n prompts: slot.prompts,\n }),\n );\n slot.manifestWrite = pending;\n await pending;\n if (slot.manifestWrite === pending) slot.manifestWrite = undefined;\n }\n\n /** Start the shared idle sweep timer once (unref'd so it never holds the process). */\n private ensureIdleSweep(): void {\n if (this.idleTimer || this.idleTimeoutMs <= 0) return;\n this.idleTimer = setInterval(() => {\n void this.sweepIdle();\n }, MCP_CONSTANTS.IDLE.SWEEP_INTERVAL_MS);\n // Node-only: don't keep the event loop alive just for the sweep.\n this.idleTimer.unref?.();\n }\n\n /** Auto-sleep connected lazy servers that have been idle past the timeout. */\n private async sweepIdle(): Promise<void> {\n if (this.idleTimeoutMs <= 0) return;\n const now = Date.now();\n for (const slot of this.servers.values()) {\n if (\n slot.lazy &&\n slot.state === 'connected' &&\n slot.client &&\n now - slot.lastUsed > this.idleTimeoutMs\n ) {\n await this.sleepIdle(slot);\n }\n }\n }\n\n /**\n * Soft stop: close the server process but KEEP its resolver wrappers and\n * cached manifest registered, so the next tool call transparently re-wakes it.\n * Distinct from {@link stop} (full teardown for disable/remove).\n */\n private async sleepIdle(slot: ServerSlot): Promise<void> {\n slot.reconnectPending = false;\n // Defense-in-depth: a connect-failure retry timer from an earlier\n // failed cycle shouldn't outlive a fresh sleep.\n if (slot.reconnectTimer) {\n clearTimeout(slot.reconnectTimer);\n slot.reconnectTimer = undefined;\n }\n if (slot.client) {\n // Remove the exit listener BEFORE close so the teardown isn't seen as a crash.\n slot.client.removeExitListener(this.onChildExit);\n if (slot.onDisconnect) slot.client.removeDisconnectListener(slot.onDisconnect);\n slot.client.removeToolsChangedListener(this.onToolsChanged);\n this.removeCatalogListeners(slot.client);\n await slot.client.close();\n slot.client = undefined;\n }\n slot.onDisconnect = undefined;\n slot.state = 'dormant';\n slot.operations.sleepCount++;\n this.recordOperation(slot, 'sleep', 'idle-timeout');\n this.log.info(`MCP server \"${slot.cfg.name}\" idle \u2014 sleeping (tools stay registered)`);\n this.events.emit('mcp.server.disconnected', { name: slot.cfg.name, reason: 'idle-sleep' });\n }\n\n /**\n * Catalog of every server ever registered with this registry \u2014 includes\n * servers that are stopped, failed, or not yet started.\n * Useful for the `mcp_control` tool to show all known servers without\n * triggering connections.\n */\n describe(): {\n name: string;\n state: ConnectionState;\n toolCount: number;\n enabled: boolean;\n tools: string[];\n }[] {\n const active = Array.from(this.servers.values()).map((s) => {\n const tools = this.toolNamesForSlot(s);\n return {\n name: s.cfg.name,\n state: s.state,\n toolCount: tools.length,\n enabled: s.cfg.enabled !== false,\n tools,\n };\n });\n const disabled = Array.from(this.disabledServers.values()).map((cfg) => ({\n name: cfg.name,\n state: 'idle' as const,\n toolCount: 0,\n enabled: false,\n tools: [],\n }));\n return [...active, ...disabled];\n }\n\n async stopAll(): Promise<void> {\n if (this.idleTimer) {\n clearInterval(this.idleTimer);\n this.idleTimer = undefined;\n }\n for (const name of Array.from(this.servers.keys())) {\n await this.stop(name);\n }\n this.disabledServers.clear();\n }\n\n /**\n * Health check \u2014 returns 'ok' for connected servers, the current state otherwise.\n * For HTTP-based transports this could also ping the server.\n */\n health(): { name: string; alive: boolean; latencyMs?: number | undefined }[] {\n return Array.from(this.servers.values()).map((s) => ({\n name: s.cfg.name,\n alive: s.state === 'connected',\n }));\n }\n\n /**\n * L2-C: handle `notifications/tools/list_changed` from the server.\n * Unregister the previous wrapper set, then re-register the fresh\n * tool list. The client has already refreshed its cache before\n * dispatching \u2014 we just need to re-wrap and re-register.\n * In lazy mode, only update the internal cache without registering.\n */\n private readonly onToolsChanged = (name: string, _tools: { name: string }[]): void => {\n const slot = this.servers.get(name);\n if (!slot?.client) return;\n // Unregister any previously registered tools, then re-apply the fresh set.\n for (const t of slot.toolNames) {\n try {\n this.toolRegistry.unregister(t);\n } catch {\n /* ignore */\n }\n }\n slot.toolNames = [];\n slot.registeredLazy = false;\n const discovered = slot.client.listTools();\n // Refresh the lazy manifest so a future cold boot sees the new tool set.\n this.applyTools(slot, discovered, slot.client);\n void this.persistCapabilityManifest(slot);\n this.events.emit('mcp.server.connected', {\n name: slot.cfg.name,\n toolCount: slot.toolNames.length,\n });\n this.log.info(\n `MCP server \"${slot.cfg.name}\" tools refreshed (${this.toolNamesForSlot(slot).length} active)`,\n );\n };\n\n private readonly onResourcesChanged = (name: string): void => {\n const slot = this.servers.get(name);\n if (!slot) return;\n slot.resources = undefined;\n slot.resourceTemplates = undefined;\n void this.persistCapabilityManifest(slot);\n this.log.info(`MCP server \"${name}\" resource catalog invalidated`);\n };\n\n private readonly onPromptsChanged = (name: string): void => {\n const slot = this.servers.get(name);\n if (!slot) return;\n slot.prompts = undefined;\n void this.persistCapabilityManifest(slot);\n this.log.info(`MCP server \"${name}\" prompt catalog invalidated`);\n };\n\n private addCatalogListeners(client: MCPClient): void {\n client.addResourcesChangedListener(this.onResourcesChanged);\n client.addPromptsChangedListener(this.onPromptsChanged);\n }\n\n private removeCatalogListeners(client: MCPClient): void {\n client.removeResourcesChangedListener(this.onResourcesChanged);\n client.removePromptsChangedListener(this.onPromptsChanged);\n }\n\n private readonly onChildExit = (\n name: string,\n code: number | null,\n _signal: string | null,\n ): void => {\n const slot = this.servers.get(name);\n if (!slot) return;\n if (slot.lazy) {\n // Lazy server died \u2014 go dormant (keep resolver wrappers); the next tool\n // call re-spawns it. No reconnect storm for an on-demand server.\n slot.client = undefined;\n slot.state = 'dormant';\n this.recordFailure(slot, 'transport', 'process-exit-lazy');\n this.events.emit('mcp.server.disconnected', {\n name,\n reason: `exit:${code ?? 'unknown'} (dormant)`,\n });\n return;\n }\n for (const t of slot.toolNames) {\n try {\n this.toolRegistry.unregister(t);\n } catch {\n /* ignore */\n }\n }\n slot.toolNames = [];\n slot.lazyTools = [];\n slot.serverMetadata = undefined;\n slot.resources = undefined;\n slot.resourceTemplates = undefined;\n slot.prompts = undefined;\n slot.state = 'disconnected';\n this.recordFailure(slot, 'transport', 'process-exit');\n this.events.emit('mcp.server.disconnected', { name, reason: `exit:${code ?? 'unknown'}` });\n this.scheduleReconnect(slot);\n };\n\n /** Handles SSE / streamable-http disconnect \u2014 same recovery as stdio child exit. */\n private readonly onTransportDisconnect = (name: string): void => {\n const slot = this.servers.get(name);\n if (!slot) return;\n if (slot.lazy) {\n slot.client = undefined;\n slot.state = 'dormant';\n this.recordFailure(slot, 'transport', 'http-disconnect-lazy');\n this.events.emit('mcp.server.disconnected', { name, reason: 'http-disconnect (dormant)' });\n return;\n }\n for (const t of slot.toolNames) {\n try {\n this.toolRegistry.unregister(t);\n } catch {\n /* ignore */\n }\n }\n slot.toolNames = [];\n slot.lazyTools = [];\n slot.serverMetadata = undefined;\n slot.resources = undefined;\n slot.resourceTemplates = undefined;\n slot.prompts = undefined;\n slot.state = 'disconnected';\n this.recordFailure(slot, 'transport', 'http-disconnect');\n this.events.emit('mcp.server.disconnected', { name, reason: 'http-disconnect' });\n this.scheduleReconnect(slot);\n };\n\n /**\n * L2-B: maximum number of reconnect cycles before staying `failed`.\n * One cycle = one full `attemptConnect` (which itself may try up to 3\n * times). Caps total reconnect storm at ~5 cycles, then the slot\n * needs an explicit `restart()` to re-engage.\n */\n private static readonly MAX_RECONNECT_CYCLES = MCP_CONSTANTS.RECONNECT.MAX_CYCLES;\n /** Base delay between cycles, in ms. Real delay adds jitter. */\n private static readonly BASE_RECONNECT_DELAY_MS = MCP_CONSTANTS.RECONNECT.BASE_DELAY_MS;\n /** Hard ceiling on the inter-cycle delay so the user doesn't wait minutes. */\n private static readonly MAX_RECONNECT_DELAY_MS = 30_000;\n\n private scheduleReconnect(slot: ServerSlot): void {\n if (slot.reconnectPending) return;\n if (slot.reconnectCycles >= MCPRegistry.MAX_RECONNECT_CYCLES) {\n slot.state = 'failed';\n this.recordFailure(slot, 'transport', 'reconnect-exhausted');\n this.log.error(\n `MCP server \"${slot.cfg.name}\" giving up after ${slot.reconnectCycles} reconnect cycles. Use \\`/mcp restart ${slot.cfg.name}\\` to retry.`,\n );\n this.events.emit('mcp.server.disconnected', {\n name: slot.cfg.name,\n reason: `reconnect-exhausted:${slot.reconnectCycles}`,\n });\n return;\n }\n slot.reconnectPending = true;\n // Cancel any previously-scheduled timer for this slot. Defensive \u2014 the\n // `reconnectPending` early-return above normally prevents re-scheduling\n // while one is outstanding, but if the slot was torn down mid-flight\n // and re-started (`restart()`), a stale handle from the prior cycle\n // could otherwise fire and resurrect the wrong client.\n if (slot.reconnectTimer) {\n clearTimeout(slot.reconnectTimer);\n slot.reconnectTimer = undefined;\n }\n // Exponential backoff with light jitter: 1s, 2s, 4s, 8s, 16s, capped\n // at 30s. The \u00B120% jitter avoids reconnect stampedes when many\n // servers crash together.\n const base = Math.min(\n MCPRegistry.BASE_RECONNECT_DELAY_MS * 2 ** slot.reconnectCycles,\n MCPRegistry.MAX_RECONNECT_DELAY_MS,\n );\n const jitter = base * MCP_CONSTANTS.RECONNECT.JITTER_FACTOR * (Math.random() * 2 - 1);\n const delay = Math.max(100, Math.round(base + jitter));\n slot.reconnectTimer = setTimeout(() => {\n slot.reconnectTimer = undefined;\n void this.attemptReconnect(slot);\n }, delay);\n }\n\n private async attemptReconnect(slot: ServerSlot): Promise<void> {\n slot.reconnectPending = false;\n slot.reconnectCycles++;\n slot.operations.reconnectCount++;\n this.recordOperation(slot, 'reconnect', 'automatic');\n await this.attemptConnect(slot);\n }\n\n private recordSuccess(slot: ServerSlot, resetFailures = true): void {\n const operations = this.operationsFor(slot);\n operations.lastSuccessAt = Date.now();\n if (resetFailures) operations.consecutiveFailures = 0;\n }\n\n private recordFailure(\n slot: ServerSlot,\n failureKind: MCPFailureKind,\n reason: string,\n durationMs?: number | undefined,\n ): void {\n const operations = this.operationsFor(slot);\n const safeReason = safeOperationReason(reason);\n operations.lastFailureAt = Date.now();\n operations.lastFailureKind = failureKind;\n operations.lastReason = safeReason;\n operations.consecutiveFailures++;\n operations.failures[failureKind]++;\n this.recordOperation(slot, 'failure', safeReason, failureKind, durationMs);\n }\n\n private recordOperation(\n slot: ServerSlot,\n kind: MCPOperationKind,\n reason?: string | undefined,\n failureKind?: MCPFailureKind | undefined,\n durationMs?: number | undefined,\n retain = true,\n ): void {\n const operations = this.operationsFor(slot);\n const baseHealth = healthStateFor(slot.state, operations, slot.cfg.enabled !== false);\n const checks = evaluateHealthThresholds(operations, slot.cfg.health?.thresholds);\n const event: MCPOperationEvent = {\n serverName: slot.cfg.name,\n kind,\n at: Date.now(),\n connectionState: slot.state,\n healthState: applyHealthThresholds(baseHealth, checks),\n };\n if (reason !== undefined) event.reason = safeOperationReason(reason);\n if (failureKind !== undefined) event.failureKind = failureKind;\n if (durationMs !== undefined) event.durationMs = Math.max(0, Math.round(durationMs));\n if (retain) {\n pushBounded(operations.recentEvents, event, MCP_OPERATION_LIMITS.RECENT_EVENTS);\n }\n for (const listener of this.operationListeners) {\n try {\n listener({ ...event });\n } catch {\n // Observability must never affect MCP execution.\n }\n }\n }\n\n /** Keeps private-method unit fixtures from needing to duplicate every slot field. */\n private operationsFor(slot: ServerSlot): MCPServerOperationState {\n if (!slot.operations) slot.operations = createMCPServerOperationState();\n return slot.operations;\n }\n\n private async attemptConnect(slot: ServerSlot): Promise<void> {\n const MAX_ATTEMPTS = MCP_CONSTANTS.RECONNECT.MAX_ATTEMPTS;\n let attempt = 0;\n while (attempt < MAX_ATTEMPTS) {\n attempt++;\n const startedAt = Date.now();\n slot.state = attempt === 1 ? 'connecting' : 'reconnecting';\n slot.attempts = attempt;\n let client: MCPClient | undefined;\n let boundDisconnect: (() => void) | undefined;\n try {\n client = new MCPClient({\n name: slot.cfg.name,\n transport: slot.cfg.transport,\n command: slot.cfg.command,\n args: slot.cfg.args,\n env: slot.cfg.env,\n url: slot.cfg.url,\n headers: slot.cfg.headers,\n startupTimeoutMs: slot.cfg.startupTimeoutMs,\n requestTimeoutMs: slot.cfg.requestTimeoutMs,\n passthroughEnv: slot.cfg.passthroughEnv,\n authorizationProvider: this.authorizationProviderFactory?.(slot.cfg),\n });\n if (slot.cfg.transport === 'stdio') {\n client.addExitListener(this.onChildExit);\n } else {\n // SSE / streamable-http \u2014 wire transport disconnect to registry reconnect.\n // Capture the bound function so we can hand the same reference to\n // removeDisconnectListener on cleanup paths.\n boundDisconnect = () => this.onTransportDisconnect(slot.cfg.name);\n client.addDisconnectListener(boundDisconnect);\n }\n // L2-C: react to server-side tool changes by re-registering wrappers.\n client.addToolsChangedListener(this.onToolsChanged);\n this.addCatalogListeners(client);\n await client.connect();\n // Close any prior client before swapping refs so the old transport\n // can release its abort controller, child process, and listeners\n // instead of being held until GC.\n if (slot.client && slot.client !== client) {\n const prior = slot.client;\n const priorDisconnect = slot.onDisconnect;\n slot.client.removeExitListener(this.onChildExit);\n if (priorDisconnect) prior.removeDisconnectListener(priorDisconnect);\n prior.removeToolsChangedListener(this.onToolsChanged);\n this.removeCatalogListeners(prior);\n prior.close().catch(() => {\n /* best-effort */\n });\n }\n slot.client = client;\n slot.onDisconnect = boundDisconnect;\n const isReconnect = slot.reconnectCycles > 0 || attempt > 1;\n slot.state = 'connected';\n // L2-B: a healthy connect resets the cycle counter so future\n // crashes get the full reconnect budget again.\n slot.reconnectCycles = 0;\n const mc = client as MCPClient;\n const discovered = mc.listTools();\n await this.discoverCapabilities(slot, mc);\n // Lazy servers persist their manifest so later boots can register cold.\n await this.persistCapabilityManifest(slot);\n this.applyTools(slot, discovered, mc);\n const durationMs = Date.now() - startedAt;\n pushBounded(\n slot.operations.connectionSamples,\n durationMs,\n MCP_OPERATION_LIMITS.LATENCY_SAMPLES,\n );\n this.recordSuccess(slot, (slot.operations.lastFailureAt ?? 0) < startedAt);\n this.recordOperation(\n slot,\n isReconnect ? 'reconnect' : 'connect',\n 'connected',\n undefined,\n durationMs,\n );\n slot.lastUsed = Date.now();\n if (slot.lazy) this.ensureIdleSweep();\n this.events.emit(isReconnect ? 'mcp.server.reconnected' : 'mcp.server.connected', {\n name: slot.cfg.name,\n toolCount: slot.toolNames.length,\n });\n return; // success\n } catch (err) {\n this.recordFailure(slot, 'transport', 'connect-attempt-failed', Date.now() - startedAt);\n this.log.warn(`MCP server \"${slot.cfg.name}\" connect attempt ${attempt} failed`, err);\n if (client) {\n client.removeExitListener(this.onChildExit);\n if (boundDisconnect) client.removeDisconnectListener(boundDisconnect);\n client.removeToolsChangedListener(this.onToolsChanged);\n this.removeCatalogListeners(client);\n await client.close().catch(() => {\n /* ignore */\n });\n }\n if (attempt >= MAX_ATTEMPTS) {\n this.log.error(\n `MCP server \"${slot.cfg.name}\" connect exhausted after ${MAX_ATTEMPTS} attempts`,\n err,\n );\n slot.state = 'failed';\n slot.client = undefined;\n // The connect() loop itself doesn't schedule a backoff timer (it\n // only awaits inline setTimeouts within the `while`), but a\n // prior `scheduleReconnect` cycle may have left one outstanding.\n // Drop it so the user can `restart()` without waiting on a stale\n // fire that would race the fresh `attemptConnect`.\n if (slot.reconnectTimer) {\n clearTimeout(slot.reconnectTimer);\n slot.reconnectTimer = undefined;\n }\n slot.reconnectPending = false;\n this.events.emit('mcp.server.disconnected', {\n name: slot.cfg.name,\n reason: err instanceof Error ? err.message : 'unknown',\n });\n return;\n }\n const delay = 500 * 2 ** attempt;\n await new Promise((r) => setTimeout(r, delay));\n }\n }\n }\n}\n\nconst MAX_CATALOG_PAGES = 100;\nconst MAX_CATALOG_ITEMS = 10_000;\n\nasync function collectPages<Page extends { nextCursor?: string | undefined }, Item>(\n load: (cursor?: string | undefined) => Promise<Page>,\n select: (page: Page) => Item[],\n): Promise<Item[]> {\n const items: Item[] = [];\n const seenCursors = new Set<string>();\n let cursor: string | undefined;\n for (let pageNumber = 0; pageNumber < MAX_CATALOG_PAGES; pageNumber++) {\n const page = await load(cursor);\n items.push(...select(page));\n if (items.length > MAX_CATALOG_ITEMS) {\n throw new Error(`MCP catalog exceeds ${MAX_CATALOG_ITEMS} items`);\n }\n const next = page.nextCursor;\n if (!next) return items;\n if (seenCursors.has(next)) throw new Error(`MCP catalog repeated cursor \"${next}\"`);\n seenCursors.add(next);\n cursor = next;\n }\n throw new Error(`MCP catalog exceeds ${MAX_CATALOG_PAGES} pages`);\n}\n\nfunction cloneRecords<T>(records: T[]): T[] {\n return structuredClone(records);\n}\n\nfunction catalogSnapshot(slot: ServerSlot): MCPRegistryCatalog {\n return {\n name: slot.cfg.name,\n state: slot.state,\n serverMetadata: slot.serverMetadata ? structuredClone(slot.serverMetadata) : undefined,\n resources: slot.resources ? cloneRecords(slot.resources) : undefined,\n resourceTemplates: slot.resourceTemplates ? cloneRecords(slot.resourceTemplates) : undefined,\n prompts: slot.prompts ? cloneRecords(slot.prompts) : undefined,\n };\n}\n", "import { ToolCapabilities } from '@wrongstack/core/security';\nimport type { Permission, Tool } from '@wrongstack/core/types';\nimport type { MCPClient, MCPTool } from './client.js';\n\n/**\n * Keywords that indicate a mutating operation.\n * Applied to both the tool name and its inputSchema property names.\n */\nconst MUTATING_RE = /create|update|delete|write|send|set|put|post|patch|remove|rename|move/i;\n\nfunction isMutatingTool(mcpTool: MCPTool): boolean {\n if (MUTATING_RE.test(mcpTool.name)) return true;\n // Check property names in the input schema for mutating intent.\n // e.g. { properties: { createTable: {...}, dropIndex: {...} } }\n const schema = mcpTool.inputSchema;\n if (schema && typeof schema === 'object') {\n const props = (schema as { properties?: Record<string, unknown> }).properties;\n if (props) {\n for (const key of Object.keys(props)) {\n if (MUTATING_RE.test(key)) return true;\n }\n }\n }\n return false;\n}\n\n/**\n * Resolves the live client for a tool call. A plain {@link MCPClient} for eager\n * servers, or a thunk that connects-on-demand for lazy/dormant servers (the\n * registry passes `() => this.ensureConnected(name)`).\n */\nexport type MCPClientResolver = MCPClient | (() => Promise<MCPClient>);\n\nexport interface MCPToolCallObserver {\n onStart(): void;\n onFinish(result: { durationMs: number; ok: boolean }): void;\n}\n\nexport function wrapMCPTool(\n serverName: string,\n mcpTool: MCPTool,\n client: MCPClientResolver,\n permission: Permission = 'confirm',\n observer?: MCPToolCallObserver | undefined,\n): Tool {\n const qualifiedName = `mcp__${serverName}__${mcpTool.name}`;\n return {\n name: qualifiedName,\n description: mcpTool.description ?? `${qualifiedName} (MCP tool)`,\n usageHint: `Tool provided by MCP server \"${serverName}\". ${mcpTool.description ?? ''}`,\n permission,\n mutating: isMutatingTool(mcpTool),\n capabilities: [ToolCapabilities.MCP_PROXY],\n inputSchema: mcpTool.inputSchema ?? { type: 'object', properties: {} },\n async execute(input, _ctx, opts) {\n const startedAt = Date.now();\n observer?.onStart();\n let ok = false;\n try {\n // For a dormant lazy server this spawns the process + handshakes before\n // the first call; for an eager server it resolves to the fixed client.\n const live = typeof client === 'function' ? await client() : client;\n // Propagate the run's abort signal: on Ctrl+C the JSON-RPC request is\n // dropped AND the server is told via `notifications/cancelled` to stop\n // the in-flight work, instead of it running to completion server-side.\n const res = await live.callTool(mcpTool.name, input, { signal: opts.signal });\n if (res.isError) {\n throw new Error(stringify(res.content));\n }\n ok = true;\n return stringify(res.content);\n } finally {\n observer?.onFinish({ durationMs: Date.now() - startedAt, ok });\n }\n },\n };\n}\n\nfunction stringify(c: unknown): string {\n if (typeof c === 'string') return c;\n if (Array.isArray(c)) {\n return c\n .map((item) => {\n if (item && typeof item === 'object') {\n const t = (item as { type?: string | undefined; text?: string | undefined }).type;\n if (t === 'text') return (item as { text?: string | undefined }).text ?? '';\n return JSON.stringify(item);\n }\n return String(item);\n })\n .join('\\n');\n }\n if (c && typeof c === 'object') {\n if ('text' in (c as Record<string, unknown>)) {\n return String((c as Record<string, unknown>).text);\n }\n return JSON.stringify(c);\n }\n return String(c ?? '');\n}\n", "import { createServer, type IncomingMessage, type ServerResponse } from 'node:http';\nimport { expectDefined } from '@wrongstack/core/utils';\nimport { toErrorMessage } from '@wrongstack/core/utils';\nimport { MCP_CONSTANTS } from './constants.js';\nimport type { MCPPromptArgument, MCPPromptMessage, MCPResourceContents } from './protocol.js';\n/**\n * Server-side MCP. The mirror image of `MCPClient`: instead of consuming a\n * remote MCP server, this lets WrongStack *be* an MCP server \u2014 exposing its\n * tools to any MCP client (Claude Desktop, another agent, an IDE) over a\n * JSON-RPC 2.0 stream.\n *\n * The protocol core (`MCPServer`) is transport-agnostic: feed it a raw JSON\n * line via `handleMessage`, get back a response string (or `null` for\n * notifications). `serveStdio` wires it to stdin/stdout for the canonical\n * stdio transport.\n */\n\n/** A tool descriptor advertised over `tools/list`. */\nexport interface MCPServerTool {\n name: string;\n description?: string | undefined;\n inputSchema: Record<string, unknown>;\n}\n\n/** The result of a `tools/call`, as the host produces it. */\nexport interface MCPServerCallResult {\n /** Text or pre-built MCP content blocks. Strings are wrapped as a text block. */\n content: unknown;\n isError: boolean;\n}\n\n/**\n * Bridges the MCP server to a tool backend (in the CLI, the `ToolRegistry`).\n * Kept narrow so the protocol core has no dependency on `@wrongstack/core`.\n */\nexport interface MCPServerToolHost {\n listTools(): MCPServerTool[] | Promise<MCPServerTool[]>;\n callTool(name: string, args: Record<string, unknown>): Promise<MCPServerCallResult>;\n}\n\nexport interface MCPServerResource {\n uri: string;\n name: string;\n title?: string | undefined;\n description?: string | undefined;\n mimeType?: string | undefined;\n size?: number | undefined;\n contents: MCPResourceContents[];\n}\n\nexport interface MCPServerPrompt {\n name: string;\n title?: string | undefined;\n description?: string | undefined;\n arguments?: MCPPromptArgument[] | undefined;\n /** Static rich messages, or a text template using {{argument}} placeholders. */\n messages?: MCPPromptMessage[] | undefined;\n template?: string | undefined;\n}\n\nexport interface MCPServerLogger {\n warn?(msg: string): void;\n info?(msg: string): void;\n}\n\nexport interface MCPServerOptions {\n host: MCPServerToolHost;\n /** Advertised in the `initialize` handshake. Defaults to the wrongstack identity. */\n serverInfo?: { name: string; version: string };\n logger?: MCPServerLogger | undefined;\n /** Explicit allowlist only; omitted means this server exposes no resources. */\n resources?: MCPServerResource[] | undefined;\n /** Explicit allowlist only; omitted means this server exposes no prompts. */\n prompts?: MCPServerPrompt[] | undefined;\n}\n\ninterface JsonRpcRequest {\n jsonrpc?: string | undefined;\n id?: number | string | null | undefined;\n method?: string | undefined;\n params?: unknown | undefined;\n}\n\n// JSON-RPC 2.0 reserved error codes.\nconst PARSE_ERROR = -32700;\nconst INVALID_REQUEST = -32600;\nconst METHOD_NOT_FOUND = -32601;\nconst INTERNAL_ERROR = -32603;\n\nexport class MCPServer {\n private readonly host: MCPServerToolHost;\n private readonly serverInfo: { name: string; version: string };\n private readonly logger?: MCPServerLogger | undefined;\n private readonly resources: MCPServerResource[];\n private readonly prompts: MCPServerPrompt[];\n\n constructor(opts: MCPServerOptions) {\n this.host = opts.host;\n this.serverInfo = opts.serverInfo ?? {\n name: MCP_CONSTANTS.CLIENT_INFO.name,\n version: MCP_CONSTANTS.CLIENT_INFO.version,\n };\n this.logger = opts.logger;\n this.resources = structuredClone(opts.resources ?? []);\n this.prompts = structuredClone(opts.prompts ?? []);\n }\n\n /**\n * Handle one raw JSON-RPC line. Returns the response JSON string for\n * requests, or `null` for notifications (no `id`) and for blank input \u2014\n * the caller should write the string to its output stream when non-null.\n */\n async handleMessage(raw: string): Promise<string | null> {\n const line = raw.trim();\n if (!line) return null;\n\n let msg: JsonRpcRequest;\n try {\n msg = JSON.parse(line) as JsonRpcRequest;\n } catch {\n return this.encodeError(null, PARSE_ERROR, 'Parse error');\n }\n\n if (typeof msg !== 'object' || msg === null || typeof msg.method !== 'string') {\n const id = msg && typeof msg === 'object' ? (msg.id ?? null) : null;\n return this.encodeError(id ?? null, INVALID_REQUEST, 'Invalid Request');\n }\n\n const isNotification = msg.id === undefined || msg.id === null;\n\n // Notifications never get a response. We still dispatch known ones for\n // side effects, but `notifications/initialized` is purely a handshake ack.\n if (isNotification) {\n return null;\n }\n\n try {\n const result = await this.dispatch(msg.method, msg.params);\n if (result === METHOD_NOT_FOUND_SENTINEL) {\n return this.encodeError(\n expectDefined(msg.id),\n METHOD_NOT_FOUND,\n `Method not found: ${msg.method}`,\n );\n }\n return JSON.stringify({ jsonrpc: '2.0', id: msg.id, result });\n } catch (err) {\n const message = toErrorMessage(err);\n this.logger?.warn?.(`MCP server: method \"${msg.method}\" threw: ${message}`);\n return this.encodeError(expectDefined(msg.id), INTERNAL_ERROR, message);\n }\n }\n\n private async dispatch(method: string, params: unknown): Promise<unknown> {\n switch (method) {\n case 'initialize':\n return {\n protocolVersion: MCP_CONSTANTS.PROTOCOL_VERSION,\n capabilities: {\n tools: { listChanged: false },\n ...(this.resources.length > 0\n ? { resources: { subscribe: false, listChanged: false } }\n : {}),\n ...(this.prompts.length > 0 ? { prompts: { listChanged: false } } : {}),\n },\n serverInfo: this.serverInfo,\n };\n case 'ping':\n return {};\n case 'tools/list': {\n const tools = await this.host.listTools();\n return { tools };\n }\n case 'tools/call': {\n const p = (params ?? {}) as { name?: unknown | undefined; arguments?: unknown | undefined };\n if (typeof p.name !== 'string') {\n throw new Error('tools/call requires a string \"name\"');\n }\n const args =\n p.arguments && typeof p.arguments === 'object' && !Array.isArray(p.arguments)\n ? (p.arguments as Record<string, unknown>)\n : {};\n const res = await this.host.callTool(p.name, args);\n return { content: toContentBlocks(res.content), isError: res.isError };\n }\n case 'resources/list': {\n if (this.resources.length === 0) return METHOD_NOT_FOUND_SENTINEL;\n const page = paginate(this.resources, params);\n return {\n resources: page.items.map(({ contents: _contents, ...resource }) => resource),\n ...(page.nextCursor ? { nextCursor: page.nextCursor } : {}),\n };\n }\n case 'resources/templates/list':\n if (this.resources.length === 0) return METHOD_NOT_FOUND_SENTINEL;\n return { resourceTemplates: [] };\n case 'resources/read': {\n if (this.resources.length === 0) return METHOD_NOT_FOUND_SENTINEL;\n const uri = requiredParamString(params, 'uri', 'resources/read');\n const resource = this.resources.find((candidate) => candidate.uri === uri);\n if (!resource) throw new Error(`Resource not found: ${uri}`);\n return { contents: structuredClone(resource.contents) };\n }\n case 'prompts/list': {\n if (this.prompts.length === 0) return METHOD_NOT_FOUND_SENTINEL;\n const page = paginate(this.prompts, params);\n return {\n prompts: page.items.map(\n ({ messages: _messages, template: _template, ...prompt }) => prompt,\n ),\n ...(page.nextCursor ? { nextCursor: page.nextCursor } : {}),\n };\n }\n case 'prompts/get': {\n if (this.prompts.length === 0) return METHOD_NOT_FOUND_SENTINEL;\n const name = requiredParamString(params, 'name', 'prompts/get');\n const prompt = this.prompts.find((candidate) => candidate.name === name);\n if (!prompt) throw new Error(`Prompt not found: ${name}`);\n const input = paramsRecord(params);\n const args = stringRecord(input['arguments'], 'prompts/get arguments');\n for (const argument of prompt.arguments ?? []) {\n if (argument.required && args[argument.name] === undefined) {\n throw new Error(`Prompt \"${name}\" requires argument \"${argument.name}\"`);\n }\n }\n const messages = prompt.template\n ? [\n {\n role: 'user' as const,\n content: { type: 'text', text: renderPromptTemplate(prompt.template, args) },\n },\n ]\n : structuredClone(prompt.messages ?? []);\n return { description: prompt.description, messages };\n }\n default:\n return METHOD_NOT_FOUND_SENTINEL;\n }\n }\n\n private encodeError(id: number | string | null, code: number, message: string): string {\n return JSON.stringify({ jsonrpc: '2.0', id, error: { code, message } });\n }\n}\n\nconst SERVER_PAGE_SIZE = 100;\n\nfunction paginate<T>(items: T[], params: unknown): { items: T[]; nextCursor?: string | undefined } {\n const cursor = paramsRecord(params)['cursor'];\n let offset = 0;\n if (cursor !== undefined) {\n if (typeof cursor !== 'string' || !/^\\d+$/.test(cursor)) {\n throw new Error('MCP pagination cursor must be a non-negative integer string');\n }\n offset = Number(cursor);\n if (!Number.isSafeInteger(offset)) throw new Error('MCP pagination cursor is too large');\n }\n const page = items.slice(offset, offset + SERVER_PAGE_SIZE);\n const next = offset + page.length;\n return {\n items: page,\n ...(next < items.length ? { nextCursor: String(next) } : {}),\n };\n}\n\nfunction paramsRecord(params: unknown): Record<string, unknown> {\n return params && typeof params === 'object' && !Array.isArray(params)\n ? (params as Record<string, unknown>)\n : {};\n}\n\nfunction requiredParamString(params: unknown, field: string, method: string): string {\n const value = paramsRecord(params)[field];\n if (typeof value !== 'string' || value.length === 0) {\n throw new Error(`${method} requires a non-empty string \"${field}\"`);\n }\n return value;\n}\n\nfunction stringRecord(value: unknown, label: string): Record<string, string> {\n if (value === undefined) return {};\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error(`${label} must be an object`);\n }\n const result: Record<string, string> = {};\n for (const [key, item] of Object.entries(value as Record<string, unknown>)) {\n if (typeof item !== 'string') throw new Error(`${label}.${key} must be a string`);\n result[key] = item;\n }\n return result;\n}\n\nfunction renderPromptTemplate(template: string, args: Record<string, string>): string {\n return template.replace(/\\{\\{([A-Za-z_][A-Za-z0-9_.-]*)\\}\\}/g, (_match, name: string) => {\n const value = args[name];\n if (value === undefined) throw new Error(`Missing prompt template argument \"${name}\"`);\n return value;\n });\n}\n\nconst METHOD_NOT_FOUND_SENTINEL = Symbol('method-not-found');\n\n/** Normalize a host result's content into MCP content blocks. */\nexport function toContentBlocks(content: unknown): Array<{ type: 'text'; text: string }> {\n if (typeof content === 'string') return [{ type: 'text', text: content }];\n if (Array.isArray(content)) {\n // Already-shaped content blocks pass through; otherwise stringify each item.\n const allBlocks = content.every(\n (c) => c && typeof c === 'object' && (c as { type?: unknown | undefined }).type === 'text',\n );\n if (allBlocks) return content as Array<{ type: 'text'; text: string }>;\n return [{ type: 'text', text: content.map((c) => stringifyItem(c)).join('\\n') }];\n }\n if (content === undefined || content === null) return [{ type: 'text', text: '' }];\n return [{ type: 'text', text: stringifyItem(content) }];\n}\n\nfunction stringifyItem(c: unknown): string {\n if (typeof c === 'string') return c;\n try {\n return JSON.stringify(c);\n } catch {\n return String(c);\n }\n}\n\nexport interface ServeStdioHandle {\n /** Stop reading and detach listeners. Does not exit the process. */\n close(): void;\n /** Resolves when the input stream ends (EOF). */\n done: Promise<void>;\n}\n\nexport interface ServeStdioOptions {\n stdin?: NodeJS.ReadableStream | undefined;\n stdout?: NodeJS.WritableStream | undefined;\n}\n\n/**\n * Run an `MCPServer` over stdio: newline-delimited JSON-RPC in on stdin,\n * responses out on stdout. CRITICAL: nothing else may write to stdout while\n * this runs \u2014 it is the JSON-RPC channel. Route all logging to stderr.\n */\nexport function serveStdio(server: MCPServer, opts: ServeStdioOptions = {}): ServeStdioHandle {\n const stdin: NodeJS.ReadableStream = opts.stdin ?? process.stdin;\n const stdout = opts.stdout ?? process.stdout;\n let buffer = '';\n let closed = false;\n let bufferTooLarge = false;\n // Serialize writes so concurrent async handlers don't interleave lines.\n let writeChain: Promise<void> = Promise.resolve();\n\n const writeLine = (s: string) => {\n writeChain = writeChain\n .then(\n () =>\n new Promise<void>((resolve) => {\n stdout.write(`${s}\\n`, () => resolve());\n }),\n )\n .catch((err) => {\n const msg = toErrorMessage(err);\n console.error(\n JSON.stringify({\n level: 'error',\n event: 'mcp_server.stdout_write_failed',\n message: msg,\n timestamp: new Date().toISOString(),\n }),\n );\n });\n };\n\n const onData = (chunk: Buffer | string) => {\n // A misbehaving peer that streams bytes forever without `\\n` would\n // otherwise balloon `buffer` indefinitely. Mirror the HTTP body cap\n // (`HTTP_BODY_CAP` below) \u2014 once exceeded, abandon the line, drop the\n // unread tail, and shut down so the caller can react.\n if (bufferTooLarge) return;\n buffer += typeof chunk === 'string' ? chunk : chunk.toString('utf8');\n if (buffer.length > HTTP_BODY_CAP) {\n bufferTooLarge = true;\n buffer = '';\n console.error(\n JSON.stringify({\n level: 'error',\n event: 'mcp_server.line_buffer_overflow',\n message: `stdio line exceeded ${HTTP_BODY_CAP} bytes without newline \u2014 aborting stream`,\n timestamp: new Date().toISOString(),\n }),\n );\n // Pause and tear down further reads so the caller sees a clean end.\n // `destroy()` is called WITHOUT an error so the stream's 'error' event\n // isn't emitted (PassThrough/mocked streams would otherwise emit\n // unhandled 'error' that callers must drain).\n try {\n (stdin as { pause?: () => void }).pause?.();\n (stdin as { destroy?: () => void }).destroy?.();\n } catch {\n /* ignore */\n }\n onEnd();\n return;\n }\n let idx = buffer.indexOf('\\n');\n while (idx !== -1) {\n const line = buffer.slice(0, idx);\n buffer = buffer.slice(idx + 1);\n idx = buffer.indexOf('\\n');\n if (!line.trim()) continue;\n void server\n .handleMessage(line)\n .then((res) => {\n // Always flush responses for in-flight requests, even after\n // the stream ended: `done` waits on writeChain, so dropping a\n // late response here would mean `done` resolves without that\n // line ever landing on stdout. Stopping new reads is `onEnd`'s\n // job \u2014 not gating writes.\n if (res !== null) writeLine(res);\n })\n .catch((err) => {\n // Malformed JSON from a peer \u2014 log and continue so one bad line\n // doesn't kill the entire session.\n console.error(\n JSON.stringify({\n level: 'error',\n event: 'mcp_server.handle_message_failed',\n message: toErrorMessage(err),\n timestamp: new Date().toISOString(),\n }),\n );\n });\n }\n };\n\n let resolveDone!: () => void;\n // `done` resolves once the stream has closed AND any in-flight writes have\n // drained. Without the writeChain tail-call, a caller that awaits\n // `handle.done` after stdin ends could see `done` resolve before the last\n // response line lands on stdout \u2014 useful, e.g., for closing a wrapper\n // process and being sure the stdout pipe is fully flushed.\n const done = new Promise<void>((resolve) => {\n resolveDone = () => {\n // Chain onto writeChain so `done` only resolves once writes drain.\n void writeChain.then(() => resolve());\n };\n });\n\n const onEnd = () => {\n if (closed) return;\n closed = true;\n stdin.off('data', onData);\n resolveDone();\n };\n\n stdin.on('data', onData);\n stdin.once('end', onEnd);\n stdin.once('close', onEnd);\n if (typeof (stdin as { resume?: () => void }).resume === 'function') {\n (stdin as { resume: () => void }).resume();\n }\n\n return {\n close: () => {\n onEnd();\n },\n done,\n };\n}\n\n// \u2500\u2500 HTTP transport \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst HTTP_BODY_CAP = 4 * 1024 * 1024; // 4 MiB\n\nexport interface ServeHttpOptions {\n /** TCP port. 0 picks an ephemeral port (resolved in the handle). Default 0. */\n port?: number | undefined;\n /** Bind address. Default '127.0.0.1' (loopback only). */\n host?: string | undefined;\n /**\n * Bearer token required on every request (`Authorization: Bearer <token>`).\n * REQUIRED when binding to a non-loopback host \u2014 `serveHttp` refuses to\n * expose tools to the network without one.\n */\n token?: string | undefined;\n logger?: MCPServerLogger | undefined;\n}\n\nexport interface ServeHttpHandle {\n port: number;\n host: string;\n url: string;\n close(): Promise<void>;\n}\n\nfunction isLoopbackHost(host: string): boolean {\n return host === '127.0.0.1' || host === '::1' || host === 'localhost';\n}\n\n/**\n * Run an `MCPServer` over HTTP: POST a single JSON-RPC request, get the JSON\n * response (notifications \u2192 202 with no body). Reuses `handleMessage`, so the\n * protocol is identical to the stdio transport.\n *\n * Security: binds to loopback by default. Binding to any other host (e.g.\n * `0.0.0.0`) REQUIRES a `token` \u2014 otherwise this rejects, because it would\n * otherwise expose tool execution to the whole network unauthenticated.\n */\nexport function serveHttp(\n server: MCPServer,\n opts: ServeHttpOptions = {},\n): Promise<ServeHttpHandle> {\n const host = opts.host ?? '127.0.0.1';\n const port = opts.port ?? 0;\n const token = opts.token;\n const log = opts.logger;\n\n if (!isLoopbackHost(host) && !token) {\n return Promise.reject(\n new Error(\n `serveHttp: refusing to bind to non-loopback host \"${host}\" without a token \u2014 ` +\n 'pass a token to expose tools to the network, or bind to 127.0.0.1.',\n ),\n );\n }\n\n const httpServer = createServer((req: IncomingMessage, res: ServerResponse) => {\n void handleHttpRequest(server, req, res, token, log);\n });\n\n return new Promise<ServeHttpHandle>((resolve, reject) => {\n httpServer.once('error', reject);\n httpServer.listen(port, host, () => {\n httpServer.removeListener('error', reject);\n const addr = httpServer.address();\n const boundPort = typeof addr === 'object' && addr ? addr.port : port;\n const displayHost = host === '::1' ? '[::1]' : host;\n resolve({\n port: boundPort,\n host,\n url: `http://${displayHost}:${boundPort}/`,\n close: () =>\n new Promise<void>((res2) => {\n httpServer.close(() => res2());\n }),\n });\n });\n });\n}\n\nasync function handleHttpRequest(\n server: MCPServer,\n req: IncomingMessage,\n res: ServerResponse,\n token: string | undefined,\n log: MCPServerLogger | undefined,\n): Promise<void> {\n const send = (status: number, body: string, type = 'application/json') => {\n res.writeHead(status, { 'content-type': type });\n res.end(body);\n };\n\n // Health probe.\n if (req.method === 'GET') {\n return send(200, JSON.stringify({ status: 'ok', server: 'wrongstack-mcp' }));\n }\n if (req.method !== 'POST') {\n return send(405, JSON.stringify({ error: 'method not allowed' }));\n }\n if (token) {\n const auth = req.headers.authorization ?? '';\n const expected = `Bearer ${token}`;\n if (auth !== expected) {\n return send(401, JSON.stringify({ error: 'unauthorized' }));\n }\n }\n\n let body = '';\n let tooLarge = false;\n req.on('data', (chunk: Buffer) => {\n if (tooLarge) return;\n body += chunk.toString('utf8');\n if (body.length > HTTP_BODY_CAP) {\n tooLarge = true;\n send(413, JSON.stringify({ error: 'payload too large' }));\n req.destroy();\n }\n });\n req.on('end', () => {\n if (tooLarge) return;\n void server\n .handleMessage(body)\n .then((out) => {\n // Notifications produce no response body.\n if (out === null) return send(202, '');\n return send(200, out);\n })\n .catch((err) => {\n log?.warn?.(`MCP http handler error: ${toErrorMessage(err)}`);\n send(500, JSON.stringify({ error: 'internal error' }));\n });\n });\n}\n", "import * as fs from 'node:fs/promises';\nimport type { MCPServerConfig, SecretVault } from '@wrongstack/core/types';\nimport { atomicWrite, withFileLock } from '@wrongstack/core/utils';\nimport {\n authorizationHeaderForToken,\n canonicalMcpResource,\n type MCPAuthorizationChallenge,\n type MCPAuthorizationContext,\n type MCPAuthorizationProvider,\n type MCPAuthorizationServerMetadata,\n type MCPTokenSet,\n refreshMcpAccessToken,\n validateMcpAuthorizationServerMetadata,\n} from './authorization.js';\n\nconst TOKEN_STORE_VERSION = 1 as const;\nconst MAX_STORE_BYTES = 1024 * 1024;\nconst MAX_ENTRIES = 256;\nconst DEFAULT_REFRESH_SKEW_MS = 60_000;\n\nexport interface MCPStoredAuthorization {\n serverName: string;\n resource: string;\n clientId: string;\n authorizationServer: MCPAuthorizationServerMetadata;\n tokenSet: MCPTokenSet;\n updatedAt: string;\n}\n\ninterface EncryptedAuthorizationEntry {\n serverName: string;\n resource: string;\n clientId: string;\n authorizationServer: MCPAuthorizationServerMetadata;\n accessToken: string;\n refreshToken?: string | undefined;\n tokenType: string;\n expiresAt?: number | undefined;\n scopes: string[];\n updatedAt: string;\n}\n\ninterface TokenStoreFile {\n version: typeof TOKEN_STORE_VERSION;\n updatedAt: string;\n entries: EncryptedAuthorizationEntry[];\n}\n\nexport interface MCPAuthorizationStateEvent {\n serverName: string;\n state: 'authorized' | 'refreshed' | 'reauth_required' | 'removed';\n resource: string;\n expiresAt?: number | undefined;\n scopes?: string[] | undefined;\n}\n\nexport interface MCPRefreshingAuthorizationProviderOptions {\n serverName: string;\n resource: string;\n store: MCPVaultTokenStore;\n refreshSkewMs?: number | undefined;\n onStateChange?: ((event: MCPAuthorizationStateEvent) => void) | undefined;\n}\n\nexport interface MCPVaultProviderFactoryOptions {\n store: MCPVaultTokenStore;\n refreshSkewMs?: number | undefined;\n onStateChange?: ((event: MCPAuthorizationStateEvent) => void) | undefined;\n}\n\nexport class MCPVaultTokenStore {\n constructor(\n private readonly filePath: string,\n private readonly vault: SecretVault,\n ) {}\n\n async load(serverName: string, resource: string): Promise<MCPStoredAuthorization | undefined> {\n const canonicalResource = canonicalMcpResource(resource);\n return withFileLock(this.filePath, async () => {\n const file = await this.readFile();\n const entry = file.entries.find(\n (candidate) =>\n candidate.serverName === serverName && candidate.resource === canonicalResource,\n );\n return entry ? this.decryptEntry(entry) : undefined;\n });\n }\n\n async save(value: MCPStoredAuthorization): Promise<void> {\n const normalized = normalizeStoredAuthorization(value);\n await withFileLock(this.filePath, async () => {\n const file = await this.readFile();\n const next = file.entries.filter(\n (entry) =>\n !(entry.serverName === normalized.serverName && entry.resource === normalized.resource),\n );\n next.push(this.encryptEntry(normalized));\n if (next.length > MAX_ENTRIES)\n throw new Error(`MCP token store exceeds ${MAX_ENTRIES} entries`);\n await this.writeFile(next);\n });\n }\n\n async remove(serverName: string, resource: string): Promise<boolean> {\n const canonicalResource = canonicalMcpResource(resource);\n return withFileLock(this.filePath, async () => {\n const file = await this.readFile();\n const next = file.entries.filter(\n (entry) => !(entry.serverName === serverName && entry.resource === canonicalResource),\n );\n if (next.length === file.entries.length) return false;\n await this.writeFile(next);\n return true;\n });\n }\n\n private async readFile(): Promise<TokenStoreFile> {\n let raw: string;\n try {\n const stat = await fs.stat(this.filePath);\n if (stat.size > MAX_STORE_BYTES) throw new Error('MCP token store exceeds size limit');\n raw = await fs.readFile(this.filePath, 'utf8');\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return emptyFile();\n throw error;\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw new Error('MCP token store is not valid JSON');\n }\n return validateStoreFile(parsed);\n }\n\n private async writeFile(entries: EncryptedAuthorizationEntry[]): Promise<void> {\n const file: TokenStoreFile = {\n version: TOKEN_STORE_VERSION,\n updatedAt: new Date().toISOString(),\n entries,\n };\n await atomicWrite(this.filePath, `${JSON.stringify(file, null, 2)}\\n`, { mode: 0o600 });\n }\n\n private encryptEntry(value: MCPStoredAuthorization): EncryptedAuthorizationEntry {\n const accessToken = this.vault.encrypt(value.tokenSet.accessToken);\n const refreshToken = value.tokenSet.refreshToken\n ? this.vault.encrypt(value.tokenSet.refreshToken)\n : undefined;\n if (\n !this.vault.isEncrypted(accessToken) ||\n (refreshToken && !this.vault.isEncrypted(refreshToken))\n ) {\n throw new Error('MCP token store requires an encrypting SecretVault');\n }\n return {\n serverName: value.serverName,\n resource: value.resource,\n clientId: value.clientId,\n authorizationServer: value.authorizationServer,\n accessToken,\n refreshToken,\n tokenType: value.tokenSet.tokenType ?? 'Bearer',\n expiresAt: value.tokenSet.expiresAt,\n scopes: [...(value.tokenSet.scopes ?? [])],\n updatedAt: value.updatedAt,\n };\n }\n\n private decryptEntry(entry: EncryptedAuthorizationEntry): MCPStoredAuthorization {\n if (\n !this.vault.isEncrypted(entry.accessToken) ||\n (entry.refreshToken !== undefined && !this.vault.isEncrypted(entry.refreshToken))\n ) {\n throw new Error('MCP token store contains an unencrypted token');\n }\n const value: MCPStoredAuthorization = {\n serverName: entry.serverName,\n resource: entry.resource,\n clientId: entry.clientId,\n authorizationServer: entry.authorizationServer,\n tokenSet: {\n accessToken: this.vault.decrypt(entry.accessToken),\n refreshToken: entry.refreshToken ? this.vault.decrypt(entry.refreshToken) : undefined,\n tokenType: entry.tokenType,\n resource: entry.resource,\n expiresAt: entry.expiresAt,\n scopes: [...entry.scopes],\n },\n updatedAt: entry.updatedAt,\n };\n return normalizeStoredAuthorization(value);\n }\n}\n\nexport class MCPRefreshingAuthorizationProvider implements MCPAuthorizationProvider {\n private refreshPromise?: Promise<MCPStoredAuthorization | undefined> | undefined;\n private readonly resource: string;\n private readonly refreshSkewMs: number;\n\n constructor(private readonly options: MCPRefreshingAuthorizationProviderOptions) {\n this.resource = canonicalMcpResource(options.resource);\n this.refreshSkewMs = options.refreshSkewMs ?? DEFAULT_REFRESH_SKEW_MS;\n }\n\n async getAccessToken(context: MCPAuthorizationContext): Promise<MCPTokenSet | undefined> {\n this.assertContext(context);\n let state = await this.options.store.load(this.options.serverName, this.resource);\n if (!state) return undefined;\n if (\n state.tokenSet.expiresAt !== undefined &&\n state.tokenSet.expiresAt <= Date.now() + this.refreshSkewMs\n ) {\n state = await this.refresh(state, context.signal);\n }\n if (!state) return undefined;\n if (state.tokenSet.expiresAt !== undefined && state.tokenSet.expiresAt <= Date.now()) {\n this.emit('reauth_required', state);\n return undefined;\n }\n authorizationHeaderForToken(state.tokenSet, this.resource);\n return { ...state.tokenSet, scopes: [...(state.tokenSet.scopes ?? [])] };\n }\n\n async handleUnauthorized(\n challenge: MCPAuthorizationChallenge,\n context: MCPAuthorizationContext,\n ): Promise<boolean> {\n this.assertContext(context);\n if (challenge.resource !== this.resource) return false;\n const state = await this.options.store.load(this.options.serverName, this.resource);\n if (!state?.tokenSet.refreshToken) {\n if (state) this.emit('reauth_required', state);\n return false;\n }\n return (await this.refresh(state, context.signal)) !== undefined;\n }\n\n private refresh(\n state: MCPStoredAuthorization,\n signal?: AbortSignal | undefined,\n ): Promise<MCPStoredAuthorization | undefined> {\n if (this.refreshPromise) return this.refreshPromise;\n this.refreshPromise = this.refreshInner(state, signal).finally(() => {\n this.refreshPromise = undefined;\n });\n return this.refreshPromise;\n }\n\n private async refreshInner(\n state: MCPStoredAuthorization,\n signal?: AbortSignal | undefined,\n ): Promise<MCPStoredAuthorization | undefined> {\n const refreshToken = state.tokenSet.refreshToken;\n if (!refreshToken) {\n this.emit('reauth_required', state);\n return undefined;\n }\n const tokenSet = await refreshMcpAccessToken({\n authorizationServer: state.authorizationServer,\n clientId: state.clientId,\n resource: state.resource,\n refreshToken,\n signal,\n });\n const next = normalizeStoredAuthorization({\n ...state,\n tokenSet,\n updatedAt: new Date().toISOString(),\n });\n await this.options.store.save(next);\n this.emit('refreshed', next);\n return next;\n }\n\n private assertContext(context: MCPAuthorizationContext): void {\n if (context.serverName !== this.options.serverName || context.resource !== this.resource) {\n throw new Error('MCP authorization provider context does not match its server/resource');\n }\n }\n\n private emit(state: MCPAuthorizationStateEvent['state'], value: MCPStoredAuthorization): void {\n this.options.onStateChange?.({\n serverName: value.serverName,\n state,\n resource: value.resource,\n expiresAt: value.tokenSet.expiresAt,\n scopes: [...(value.tokenSet.scopes ?? [])],\n });\n }\n}\n\nexport function createVaultBackedMcpAuthorizationProviderFactory(\n options: MCPVaultProviderFactoryOptions,\n): (server: Readonly<MCPServerConfig>) => MCPAuthorizationProvider | undefined {\n const providers = new Map<string, MCPRefreshingAuthorizationProvider>();\n return (server) => {\n if (server.transport === 'stdio' || !server.url) return undefined;\n const resource = canonicalMcpResource(server.url);\n const key = `${server.name}\\0${resource}`;\n let provider = providers.get(key);\n if (!provider) {\n provider = new MCPRefreshingAuthorizationProvider({\n serverName: server.name,\n resource,\n store: options.store,\n refreshSkewMs: options.refreshSkewMs,\n onStateChange: options.onStateChange,\n });\n providers.set(key, provider);\n }\n return provider;\n };\n}\n\nfunction emptyFile(): TokenStoreFile {\n return { version: TOKEN_STORE_VERSION, updatedAt: new Date(0).toISOString(), entries: [] };\n}\n\nfunction validateStoreFile(value: unknown): TokenStoreFile {\n if (\n !isRecord(value) ||\n value['version'] !== TOKEN_STORE_VERSION ||\n !Array.isArray(value['entries'])\n ) {\n throw new Error('MCP token store has an unsupported or malformed structure');\n }\n if (value['entries'].length > MAX_ENTRIES)\n throw new Error('MCP token store has too many entries');\n return {\n version: TOKEN_STORE_VERSION,\n updatedAt: boundedString(value['updatedAt'], 'updatedAt', 128),\n entries: value['entries'].map(validateEncryptedEntry),\n };\n}\n\nfunction validateEncryptedEntry(value: unknown): EncryptedAuthorizationEntry {\n if (!isRecord(value)) throw new Error('MCP token store entry must be an object');\n const resource = canonicalMcpResource(boundedString(value['resource'], 'resource', 4_096));\n const authorizationServer = validateMcpAuthorizationServerMetadata(value['authorizationServer']);\n const scopes = stringArray(value['scopes'], 'scopes', 128);\n const expiresAt = value['expiresAt'];\n if (expiresAt !== undefined && (typeof expiresAt !== 'number' || !Number.isFinite(expiresAt))) {\n throw new Error('MCP token store expiresAt must be a finite number');\n }\n return {\n serverName: boundedString(value['serverName'], 'serverName', 256),\n resource,\n clientId: boundedString(value['clientId'], 'clientId', 4_096),\n authorizationServer,\n accessToken: boundedString(value['accessToken'], 'accessToken', 32_768),\n refreshToken:\n value['refreshToken'] === undefined\n ? undefined\n : boundedString(value['refreshToken'], 'refreshToken', 32_768),\n tokenType: boundedString(value['tokenType'], 'tokenType', 64),\n expiresAt: expiresAt as number | undefined,\n scopes,\n updatedAt: boundedString(value['updatedAt'], 'updatedAt', 128),\n };\n}\n\nfunction normalizeStoredAuthorization(value: MCPStoredAuthorization): MCPStoredAuthorization {\n const serverName = boundedString(value.serverName, 'serverName', 256);\n const resource = canonicalMcpResource(value.resource);\n const authorizationServer = validateMcpAuthorizationServerMetadata(value.authorizationServer);\n if (canonicalMcpResource(value.tokenSet.resource) !== resource) {\n throw new Error('MCP token resource mismatch');\n }\n const tokenSet: MCPTokenSet = {\n ...value.tokenSet,\n resource,\n scopes: stringArray(value.tokenSet.scopes ?? [], 'scopes', 128),\n };\n authorizationHeaderForToken({ ...tokenSet, expiresAt: undefined }, resource);\n return {\n serverName,\n resource,\n clientId: boundedString(value.clientId, 'clientId', 4_096),\n authorizationServer,\n tokenSet,\n updatedAt: boundedString(value.updatedAt, 'updatedAt', 128),\n };\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction boundedString(value: unknown, field: string, maxLength: number): string {\n if (\n typeof value !== 'string' ||\n value.length === 0 ||\n value.length > maxLength ||\n /[\\r\\n]/.test(value)\n ) {\n throw new Error(`MCP token store field \"${field}\" is invalid`);\n }\n return value;\n}\n\nfunction stringArray(value: unknown, field: string, maxItems: number): string[] {\n if (!Array.isArray(value) || value.length > maxItems) {\n throw new Error(`MCP token store field \"${field}\" must be a bounded array`);\n }\n return [...new Set(value.map((entry) => boundedString(entry, field, 256)))];\n}\n"],
5
- "mappings": ";AAAA,SAAS,YAAY,aAAa,uBAAuB;AACzD,YAAY,SAAS;AACrB,YAAY,UAAU;AACtB,YAAY,WAAW;AACvB,YAAY,SAAS;AACrB,SAAS,eAAe,qBAAqB;AA2HtC,SAAS,qBAAqB,QAAwB;AAC3D,MAAI;AACJ,MAAI;AACF,UAAM,IAAI,IAAI,MAAM;AAAA,EACtB,QAAQ;AACN,UAAM,IAAI,MAAM,oDAAoD;AAAA,EACtE;AACA,MAAI,IAAI,aAAa,YAAY,CAAC,eAAe,GAAG,GAAG;AACrD,UAAM,IAAI,MAAM,yEAAyE;AAAA,EAC3F;AACA,MAAI,IAAI,YAAY,IAAI,YAAY,IAAI,MAAM;AAC5C,UAAM,IAAI,MAAM,uEAAuE;AAAA,EACzF;AACA,MAAI,IAAI,aAAa,OAAO,CAAC,IAAI,OAAQ,QAAO,IAAI;AACpD,SAAO,IAAI,SAAS;AACtB;AAEO,SAAS,4BACd,OACA,kBACA,MAAM,KAAK,IAAI,GACP;AACR,MAAI,qBAAqB,MAAM,QAAQ,MAAM,kBAAkB;AAC7D,UAAM,IAAI,MAAM,4DAA4D;AAAA,EAC9E;AACA,MAAI,MAAM,cAAc,UAAa,MAAM,aAAa,KAAK;AAC3D,UAAM,IAAI,MAAM,6BAA6B;AAAA,EAC/C;AACA,QAAM,YAAY,MAAM,aAAa;AACrC,MAAI,UAAU,YAAY,MAAM,UAAU;AACxC,UAAM,IAAI,MAAM,qCAAqC,SAAS,GAAG;AAAA,EACnE;AACA,MAAI,CAAC,MAAM,eAAe,MAAM,YAAY,SAAS,SAAU,SAAS,KAAK,MAAM,WAAW,GAAG;AAC/F,UAAM,IAAI,MAAM,sEAAsE;AAAA,EACxF;AACA,SAAO,UAAU,MAAM,WAAW;AACpC;AAEO,SAAS,wBACd,QACA,UAC2B;AAC3B,QAAM,YAAuC;AAAA,IAC3C,QAAQ;AAAA,IACR;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,WAAW;AAAA,EACb;AACA,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,SAAS,6BAA6B,KAAK,MAAM;AACvD,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,aAAa,OAAO,OAAO,OAAO,SAAS,KAAK,OAAO,CAAC,EAAE,MAAM;AACtE,QAAM,mBAAmB,mBAAmB,YAAY,mBAAmB;AAC3E,MAAI,kBAAkB;AACpB,UAAM,cAAc,oBAAoB,gBAAgB;AACxD,QAAI,YAAa,WAAU,sBAAsB;AAAA,EACnD;AACA,QAAM,QAAQ,mBAAmB,YAAY,OAAO;AACpD,MAAI,OAAO;AACT,cAAU,SAAS,CAAC,GAAG,IAAI,IAAI,MAAM,MAAM,KAAK,EAAE,OAAO,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG,EAAE;AAAA,EACjF;AACA,SAAO;AACT;AAGO,SAAS,8BAA8B,UAA4B;AACxE,QAAM,MAAM,IAAI,IAAI,qBAAqB,QAAQ,CAAC;AAClD,QAAM,SAAS,IAAI,aAAa,MAAM,KAAK,IAAI;AAC/C,QAAM,aAAa;AAAA,IACjB,IAAI,IAAI,wCAAwC,MAAM,IAAI,IAAI,MAAM,EAAE,SAAS;AAAA,IAC/E,IAAI,IAAI,yCAAyC,IAAI,MAAM,EAAE,SAAS;AAAA,EACxE;AACA,SAAO,CAAC,GAAG,IAAI,IAAI,UAAU,CAAC;AAChC;AAGO,SAAS,gCAAgC,QAA0B;AACxE,QAAM,MAAM,eAAe,QAAQ,6BAA6B;AAChE,QAAM,SAAS,IAAI,aAAa,MAAM,KAAK,IAAI;AAC/C,QAAM,aAAa;AAAA,IACjB,IAAI,IAAI,0CAA0C,MAAM,IAAI,IAAI,MAAM,EAAE,SAAS;AAAA,IACjF,IAAI,IAAI,oCAAoC,MAAM,IAAI,IAAI,MAAM,EAAE,SAAS;AAAA,EAC7E;AACA,MAAI,QAAQ;AACV,eAAW;AAAA,MACT,IAAI;AAAA,QACF,GAAG,OAAO,QAAQ,OAAO,EAAE,CAAC;AAAA,QAC5B,IAAI;AAAA,MACN,EAAE,SAAS;AAAA,IACb;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,+BACd,OACA,kBAC8B;AAC9B,QAAM,WAAW,OAAO,OAAO,6BAA6B;AAC5D,QAAM,WAAW,qBAAqB,eAAe,SAAS,UAAU,GAAG,UAAU,CAAC;AACtF,MAAI,aAAa,qBAAqB,gBAAgB,GAAG;AACvD,UAAM,IAAI,MAAM,2EAA2E;AAAA,EAC7F;AACA,QAAM,uBAAuB;AAAA,IAC3B,SAAS,uBAAuB;AAAA,IAChC;AAAA,IACA;AAAA,EACF,EAAE,IAAI,CAAC,WAAW,eAAe,QAAQ,6BAA6B,EAAE,SAAS,CAAC;AAClF,MAAI,qBAAqB,WAAW,GAAG;AACrC,UAAM,IAAI,MAAM,sEAAsE;AAAA,EACxF;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,iBAAiB,oBAAoB,SAAS,kBAAkB,GAAG,oBAAoB,GAAG;AAAA,EAC5F;AACF;AAEO,SAAS,iCACd,OACA,gBACgC;AAChC,QAAM,WAAW,OAAO,OAAO,+BAA+B;AAC9D,QAAM,SAAS,eAAe,eAAe,SAAS,QAAQ,GAAG,QAAQ,GAAG,QAAQ,EAAE,SAAS;AAC/F,MAAI,WAAW,eAAe,gBAAgB,iBAAiB,EAAE,SAAS,GAAG;AAC3E,UAAM,IAAI,MAAM,4CAA4C;AAAA,EAC9D;AACA,QAAM,UAAU;AAAA,IACd,SAAS,kCAAkC;AAAA,IAC3C;AAAA,IACA;AAAA,EACF;AACA,MAAI,CAAC,QAAQ,SAAS,MAAM,GAAG;AAC7B,UAAM,IAAI,MAAM,wEAAwE;AAAA,EAC1F;AACA,QAAM,eAAe,eAAe,SAAS,uBAAuB,GAAG,uBAAuB;AAC9F,SAAO;AAAA,IACL;AAAA,IACA,uBAAuB;AAAA,MACrB,eAAe,SAAS,wBAAwB,GAAG,wBAAwB;AAAA,MAC3E;AAAA,IACF,EAAE,SAAS;AAAA,IACX,eAAe;AAAA,MACb,eAAe,SAAS,gBAAgB,GAAG,gBAAgB;AAAA,MAC3D;AAAA,IACF,EAAE,SAAS;AAAA,IACX,sBAAsB,eAClB,eAAe,cAAc,uBAAuB,EAAE,SAAS,IAC/D;AAAA,IACJ,iBAAiB,oBAAoB,SAAS,kBAAkB,GAAG,oBAAoB,GAAG;AAAA,EAC5F;AACF;AAOO,SAAS,uCACd,OACgC;AAChC,QAAM,WAAW,OAAO,OAAO,sCAAsC;AACrE,QAAM,eAAe,eAAe,SAAS,sBAAsB,GAAG,sBAAsB;AAC5F,SAAO;AAAA,IACL,QAAQ,eAAe,eAAe,SAAS,QAAQ,GAAG,QAAQ,GAAG,QAAQ,EAAE,SAAS;AAAA,IACxF,uBAAuB;AAAA,MACrB,eAAe,SAAS,uBAAuB,GAAG,uBAAuB;AAAA,MACzE;AAAA,IACF,EAAE,SAAS;AAAA,IACX,eAAe;AAAA,MACb,eAAe,SAAS,eAAe,GAAG,eAAe;AAAA,MACzD;AAAA,IACF,EAAE,SAAS;AAAA,IACX,sBAAsB,eAClB,eAAe,cAAc,uBAAuB,EAAE,SAAS,IAC/D;AAAA,IACJ,iBAAiB,oBAAoB,SAAS,iBAAiB,GAAG,mBAAmB,GAAG;AAAA,EAC1F;AACF;AAOA,eAAsB,yBACpB,UACA,UAA4C,CAAC,GACH;AAC1C,QAAM,oBAAoB,qBAAqB,QAAQ;AACvD,QAAM,cAAc,IAAI,IAAI,iBAAiB;AAC7C,QAAM,0BAA0B,eAAe,WAAW,IACtD,UAAU,YAAY,QAAQ,EAAE,YAAY,IAC5C;AACJ,QAAM,YACJ,QAAQ,cACP,CAAC,KAAK,WACL,kBAAkB,KAAK;AAAA,IACrB;AAAA,IACA,WAAW,QAAQ;AAAA,IACnB,kBAAkB,QAAQ;AAAA,IAC1B,QAAQ,QAAQ;AAAA,IAChB;AAAA,EACF,CAAC;AAEL,QAAM,YAAY,wBAAwB,QAAQ,mBAAmB,MAAM,iBAAiB;AAC5F,QAAM,qBAAqB,UAAU,sBACjC,CAAC,UAAU,mBAAmB,IAC9B,8BAA8B,iBAAiB;AACnD,QAAM,oBAAoB,MAAM;AAAA,IAC9B;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR,CAAC,UAAU,+BAA+B,OAAO,iBAAiB;AAAA,IAClE;AAAA,EACF;AACA,QAAM,SAAS,kBAAkB,MAAM,qBAAqB,CAAC;AAC7D,QAAM,yBAAyB,MAAM;AAAA,IACnC,gCAAgC,MAAM;AAAA,IACtC;AAAA,IACA,QAAQ;AAAA,IACR,CAAC,UAAU,iCAAiC,OAAO,MAAM;AAAA,IACzD;AAAA,EACF;AACA,SAAO;AAAA,IACL,qBAAqB,kBAAkB;AAAA,IACvC,gCAAgC,uBAAuB;AAAA,IACvD,mBAAmB,kBAAkB;AAAA,IACrC,qBAAqB,uBAAuB;AAAA,EAC9C;AACF;AAEO,SAAS,8BACd,SACyB;AACzB,QAAM,WAAW,qBAAqB,QAAQ,QAAQ;AACtD,QAAM,WAAW,kBAAkB,QAAQ,UAAU,WAAW;AAChE,QAAM,cAAc,oBAAoB,QAAQ,WAAW;AAC3D,QAAM,SAAS,eAAe,QAAQ,UAAU,CAAC,CAAC;AAClD,QAAM,eAAe,UAAU,YAAY,EAAE,CAAC;AAC9C,QAAM,gBAAgB,UAAU,WAAW,QAAQ,EAAE,OAAO,YAAY,EAAE,OAAO,CAAC;AAClF,QAAM,QAAQ,UAAU,YAAY,EAAE,CAAC;AACvC,QAAM,mBAAmB;AAAA,IACvB,QAAQ,oBAAoB;AAAA,IAC5B;AAAA,EACF;AACA,mBAAiB,aAAa,IAAI,iBAAiB,MAAM;AACzD,mBAAiB,aAAa,IAAI,aAAa,QAAQ;AACvD,mBAAiB,aAAa,IAAI,gBAAgB,WAAW;AAC7D,mBAAiB,aAAa,IAAI,SAAS,KAAK;AAChD,mBAAiB,aAAa,IAAI,kBAAkB,aAAa;AACjE,mBAAiB,aAAa,IAAI,yBAAyB,MAAM;AACjE,mBAAiB,aAAa,IAAI,YAAY,QAAQ;AACtD,MAAI,OAAO,SAAS,EAAG,kBAAiB,aAAa,IAAI,SAAS,OAAO,KAAK,GAAG,CAAC;AAClF,SAAO;AAAA,IACL,kBAAkB,iBAAiB,SAAS;AAAA,IAC5C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEO,SAAS,8BACd,aACA,SACQ;AACR,MAAI;AACJ,MAAI;AACF,eAAW,IAAI,IAAI,WAAW;AAAA,EAChC,QAAQ;AACN,UAAM,IAAI,MAAM,4CAA4C;AAAA,EAC9D;AACA,QAAM,WAAW,IAAI,IAAI,oBAAoB,QAAQ,WAAW,CAAC;AACjE,MACE,SAAS,aAAa,SAAS,YAC/B,SAAS,aAAa,SAAS,YAC/B,SAAS,SAAS,SAAS,QAC3B,SAAS,aAAa,SAAS,UAC/B;AACA,UAAM,IAAI,MAAM,0EAA0E;AAAA,EAC5F;AACA,QAAM,gBAAgB,SAAS,aAAa,IAAI,OAAO,KAAK;AAC5D,MAAI,CAAC,kBAAkB,eAAe,QAAQ,KAAK,GAAG;AACpD,UAAM,IAAI,MAAM,mCAAmC;AAAA,EACrD;AACA,QAAM,aAAa,SAAS,aAAa,IAAI,OAAO;AACpD,MAAI;AACF,UAAM,IAAI,MAAM,mCAAmC,iBAAiB,UAAU,CAAC,EAAE;AACnF,SAAO,kBAAkB,SAAS,aAAa,IAAI,MAAM,KAAK,IAAI,oBAAoB;AACxF;AAEA,eAAsB,6BACpB,SACsB;AACtB,QAAM,WAAW,qBAAqB,QAAQ,QAAQ;AACtD,QAAM,OAAO,IAAI,gBAAgB;AAAA,IAC/B,YAAY;AAAA,IACZ,MAAM,kBAAkB,QAAQ,MAAM,oBAAoB;AAAA,IAC1D,WAAW,kBAAkB,QAAQ,UAAU,WAAW;AAAA,IAC1D,cAAc,oBAAoB,QAAQ,WAAW;AAAA,IACrD,eAAe,qBAAqB,QAAQ,YAAY;AAAA,IACxD;AAAA,EACF,CAAC,EAAE,SAAS;AACZ,QAAM,WAAW,MAAM,kBAAkB,QAAQ,oBAAoB,eAAe;AAAA,IAClF,QAAQ;AAAA,IACR;AAAA,IACA,SAAS,EAAE,gBAAgB,oCAAoC;AAAA,IAC/D,QAAQ,QAAQ;AAAA,IAChB,WAAW,QAAQ;AAAA,IACnB,kBAAkB,QAAQ;AAAA,IAC1B,QAAQ,QAAQ;AAAA,IAChB,yBAAyB,4BAA4B,QAAQ;AAAA,EAC/D,CAAC;AACD,MAAI,aAAa,OAAW,OAAM,IAAI,MAAM,+CAA+C;AAC3F,SAAO,mBAAmB,UAAU,QAAQ;AAC9C;AAEA,eAAsB,sBAAsB,SAAuD;AACjG,QAAM,WAAW,qBAAqB,QAAQ,QAAQ;AACtD,QAAM,uBAAuB,kBAAkB,QAAQ,cAAc,eAAe;AACpF,QAAM,OAAO,IAAI,gBAAgB;AAAA,IAC/B,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,WAAW,kBAAkB,QAAQ,UAAU,WAAW;AAAA,IAC1D;AAAA,EACF,CAAC,EAAE,SAAS;AACZ,QAAM,WAAW,MAAM,kBAAkB,QAAQ,oBAAoB,eAAe;AAAA,IAClF,QAAQ;AAAA,IACR;AAAA,IACA,SAAS,EAAE,gBAAgB,oCAAoC;AAAA,IAC/D,QAAQ,QAAQ;AAAA,IAChB,WAAW,QAAQ;AAAA,IACnB,kBAAkB,QAAQ;AAAA,IAC1B,QAAQ,QAAQ;AAAA,IAChB,yBAAyB,4BAA4B,QAAQ;AAAA,EAC/D,CAAC;AACD,MAAI,aAAa,OAAW,OAAM,IAAI,MAAM,+CAA+C;AAC3F,QAAM,SAAS,mBAAmB,UAAU,QAAQ;AACpD,SAAO,EAAE,GAAG,QAAQ,cAAc,OAAO,gBAAgB,qBAAqB;AAChF;AAEA,SAAS,mBAAmB,YAAoB,MAAkC;AAChF,QAAM,UAAU,IAAI;AAAA,IAClB,cAAc,IAAI;AAAA,IAClB;AAAA,EACF;AACA,QAAM,QAAQ,QAAQ,KAAK,UAAU;AACrC,QAAM,QAAQ,QAAQ,CAAC,KAAK,QAAQ,CAAC;AACrC,SAAO,OAAO,QAAQ,cAAc,IAAI;AAC1C;AAEA,SAAS,oBAAoB,OAAmC;AAC9D,MAAI;AACF,UAAM,MAAM,IAAI,IAAI,KAAK;AACzB,QAAI,IAAI,YAAY,IAAI,YAAY,IAAI,KAAM,QAAO;AACrD,QAAI,IAAI,aAAa,YAAY,CAAC,eAAe,GAAG,EAAG,QAAO;AAC9D,WAAO,IAAI,SAAS;AAAA,EACtB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,OAAO,OAAgB,OAAwC;AACtE,MAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAAG;AAC/D,UAAM,IAAI,MAAM,OAAO,KAAK,oBAAoB;AAAA,EAClD;AACA,SAAO;AACT;AAEA,SAAS,eAAe,OAAgB,OAAuB;AAC7D,MAAI,OAAO,UAAU,YAAY,MAAM,WAAW,KAAK,MAAM,SAAS,MAAO;AAC3E,UAAM,IAAI,MAAM,4BAA4B,KAAK,sCAAsC;AAAA,EACzF;AACA,SAAO;AACT;AAEA,SAAS,eAAe,OAAgB,OAAmC;AACzE,SAAO,UAAU,SAAY,SAAY,eAAe,OAAO,KAAK;AACtE;AAEA,SAAS,mBAAmB,OAAgB,OAAe,UAA4B;AACrF,MAAI,CAAC,MAAM,QAAQ,KAAK,KAAK,MAAM,SAAS,UAAU;AACpD,UAAM,IAAI,MAAM,4BAA4B,KAAK,iCAAiC,QAAQ,EAAE;AAAA,EAC9F;AACA,SAAO,CAAC,GAAG,IAAI,IAAI,MAAM,IAAI,CAAC,UAAU,eAAe,OAAO,KAAK,CAAC,CAAC,CAAC;AACxE;AAEA,SAAS,oBAAoB,OAAgB,OAAe,UAA4B;AACtF,SAAO,UAAU,SAAY,CAAC,IAAI,mBAAmB,OAAO,OAAO,QAAQ;AAC7E;AAEA,SAAS,eAAe,OAAe,OAAoB;AACzD,MAAI;AACJ,MAAI;AACF,UAAM,IAAI,IAAI,KAAK;AAAA,EACrB,QAAQ;AACN,UAAM,IAAI,MAAM,OAAO,KAAK,0BAA0B;AAAA,EACxD;AACA,MAAI,IAAI,aAAa,YAAY,CAAC,eAAe,GAAG,GAAG;AACrD,UAAM,IAAI,MAAM,OAAO,KAAK,+CAA+C;AAAA,EAC7E;AACA,MAAI,IAAI,YAAY,IAAI,YAAY,IAAI,UAAU,IAAI,MAAM;AAC1D,UAAM,IAAI,MAAM,OAAO,KAAK,8DAA8D;AAAA,EAC5F;AACA,MAAI,IAAI,aAAa,IAAK,QAAO,IAAI,IAAI,IAAI,MAAM;AACnD,SAAO;AACT;AAEA,eAAe,cACb,YACA,WACA,QACA,OACA,OACoC;AACpC,QAAM,WAAqB,CAAC;AAC5B,aAAW,aAAa,YAAY;AAClC,YAAQ,eAAe;AACvB,QAAI;AACF,YAAM,QAAQ,MAAM,UAAU,WAAW,MAAM;AAC/C,UAAI,UAAU,QAAW;AACvB,iBAAS,KAAK,GAAG,SAAS,aAAa;AACvC;AAAA,MACF;AACA,aAAO,EAAE,KAAK,WAAW,OAAO,MAAM,KAAK,EAAE;AAAA,IAC/C,SAAS,OAAO;AACd,cAAQ,eAAe;AACvB,eAAS,KAAK,GAAG,SAAS,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAAA,IACzF;AAAA,EACF;AACA,QAAM,IAAI,MAAM,OAAO,KAAK,sBAAsB,SAAS,KAAK,IAAI,CAAC,GAAG;AAC1E;AAEA,eAAe,kBACb,QACA,SAU8B;AAC9B,QAAM,MAAM,eAAe,QAAQ,eAAe;AAClD,QAAM,SAAS,MAAM,qBAAqB,KAAK,OAAO;AACtD,QAAM,YAAY,QAAQ,aAAa;AACvC,QAAM,WAAW,QAAQ,oBAAoB,KAAK;AAClD,UAAQ,QAAQ,eAAe;AAE/B,SAAO,IAAI,QAA6B,CAAC,SAAS,WAAW;AAC3D,QAAI,UAAU;AACd,UAAM,SAAS,CAAC,OAAe,UAAoB;AACjD,UAAI,QAAS;AACb,gBAAU;AACV,cAAQ,QAAQ,oBAAoB,SAAS,OAAO;AACpD,UAAI,MAAO,QAAO,KAAK;AAAA,UAClB,SAAQ,KAAK;AAAA,IACpB;AACA,UAAM,UAAU,MAAM;AACpB,MAAAA,SAAQ,QAAQ,QAAQ,QAAQ,kBAAkB,QAAQ,QAAQ,OAAO,SAAS,MAAS;AAAA,IAC7F;AACA,UAAM,UAA2C;AAAA,MAC/C,QAAQ;AAAA,MACR,MAAM,IAAI;AAAA,MACV,GAAG,QAAQ;AAAA,IACb;AACA,QAAI,QAAQ,SAAS,QAAW;AAC9B,cAAQ,gBAAgB,IAAI,OAAO,WAAW,QAAQ,IAAI;AAAA,IAC5D;AACA,UAAM,iBAAsC;AAAA,MAC1C,MAAM,OAAO;AAAA,MACb,QAAQ,OAAO;AAAA,MACf,MAAM,OAAO,IAAI,SAAS,IAAI,aAAa,WAAW,MAAM,GAAG;AAAA,MAC/D,QAAQ,QAAQ,UAAU;AAAA,MAC1B,MAAM,GAAG,IAAI,QAAQ,GAAG,IAAI,MAAM;AAAA,MAClC;AAAA,MACA,GAAI,IAAI,aAAa,YAAgB,SAAK,UAAU,IAAI,QAAQ,CAAC,MAAM,IACnE,EAAE,YAAY,UAAU,IAAI,QAAQ,EAAE,IACtC,CAAC;AAAA,IACP;AACA,UAAM,YAAY,IAAI,aAAa,WAAiB,gBAAe;AACnE,UAAMA,WAAU,UAAU,gBAAgB,CAAC,aAAa;AACtD,YAAM,SAAS,SAAS,cAAc;AACtC,UAAI,WAAW,OAAO,WAAW,KAAK;AACpC,iBAAS,OAAO;AAChB,eAAO,QAAW,MAAS;AAC3B;AAAA,MACF;AACA,UAAI,UAAU,OAAO,SAAS,KAAK;AACjC,iBAAS,OAAO;AAChB,eAAO,IAAI,MAAM,+CAA+C,CAAC;AACjE;AAAA,MACF;AACA,UAAI,SAAS,OAAO,UAAU,KAAK;AACjC,iBAAS,OAAO;AAChB,eAAO,IAAI,MAAM,4BAA4B,MAAM,EAAE,CAAC;AACtD;AAAA,MACF;AACA,YAAM,cAAc,SAAS,QAAQ,cAAc,KAAK;AACxD,UAAI,CAAC,6CAA6C,KAAK,WAAW,GAAG;AACnE,iBAAS,OAAO;AAChB,eAAO,IAAI,MAAM,2CAA2C,CAAC;AAC7D;AAAA,MACF;AACA,YAAM,iBAAiB,OAAO,SAAS,QAAQ,gBAAgB,KAAK,CAAC;AACrE,UAAI,OAAO,SAAS,cAAc,KAAK,iBAAiB,UAAU;AAChE,iBAAS,QAAQ;AACjB,eAAO,IAAI,MAAM,wCAAwC,QAAQ,QAAQ,CAAC;AAC1E;AAAA,MACF;AACA,YAAM,SAAmB,CAAC;AAC1B,UAAI,OAAO;AACX,eAAS,GAAG,QAAQ,CAAC,UAAkB;AACrC,gBAAQ,MAAM;AACd,YAAI,OAAO,UAAU;AACnB,mBAAS,QAAQ;AACjB,iBAAO,IAAI,MAAM,wCAAwC,QAAQ,QAAQ,CAAC;AAC1E;AAAA,QACF;AACA,eAAO,KAAK,KAAK;AAAA,MACnB,CAAC;AACD,eAAS,KAAK,OAAO,MAAM;AACzB,YAAI;AACF,iBAAO,QAAW,KAAK,MAAM,OAAO,OAAO,MAAM,EAAE,SAAS,MAAM,CAAC,CAAC;AAAA,QACtE,QAAQ;AACN,iBAAO,IAAI,MAAM,gDAAgD,CAAC;AAAA,QACpE;AAAA,MACF,CAAC;AACD,eAAS,KAAK,SAAS,CAAC,UAAU,OAAO,KAAK,CAAC;AAAA,IACjD,CAAC;AACD,IAAAA,SAAQ,WAAW,WAAW,MAAM;AAClC,MAAAA,SAAQ,QAAQ,IAAI,MAAM,uCAAuC,SAAS,IAAI,CAAC;AAAA,IACjF,CAAC;AACD,IAAAA,SAAQ,KAAK,SAAS,CAAC,UAAU,OAAO,KAAK,CAAC;AAC9C,YAAQ,QAAQ,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;AACjE,IAAAA,SAAQ,IAAI,QAAQ,IAAI;AAAA,EAC1B,CAAC;AACH;AAEA,eAAe,qBACb,KACA,SAI6C;AAC7C,QAAM,WAAW,UAAU,IAAI,QAAQ,EAAE,YAAY;AACrD,QAAM,gBAAoB,SAAK,QAAQ;AACvC,MAAI,kBAAkB,KAAK,kBAAkB,GAAG;AAC9C;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,IACV;AACA,WAAO,EAAE,SAAS,UAAU,QAAQ,cAAc;AAAA,EACpD;AACA,QAAMC,UAAS,QAAQ,WAAW,CAAC,SAAa,WAAO,MAAM,EAAE,KAAK,KAAK,CAAC;AAC1E,QAAM,UAAU,MAAMA,QAAO,QAAQ;AACrC,MAAI,QAAQ,WAAW;AACrB,UAAM,IAAI,MAAM,qDAAqD,QAAQ,EAAE;AACjF,aAAWC,WAAU,SAAS;AAC5B,QAAIA,QAAO,WAAW,KAAKA,QAAO,WAAW,GAAG;AAC9C,YAAM,IAAI,MAAM,gEAAgE;AAAA,IAClF;AACA;AAAA,MACEA,QAAO;AAAA,MACPA,QAAO;AAAA,MACP;AAAA,MACA,QAAQ;AAAA,IACV;AAAA,EACF;AACA,QAAM,WAAW,QAAQ,CAAC;AAC1B,SAAO,EAAE,SAAS,SAAS,SAAS,QAAQ,SAAS,OAAgB;AACvE;AAEA,SAAS,8BACP,SACA,QACA,UACA,yBACM;AACN,QAAM,YAAY,WAAW,IAAI,cAAc,OAAO,IAAI,cAAc,OAAO;AAC/E,MAAI,CAAC,UAAW;AAChB,QAAM,WAAW,WAAW,IAAI,QAAQ,WAAW,MAAM,IAAI,YAAY;AACzE,MAAI,YAAY,aAAa,wBAAyB;AACtD,QAAM,IAAI,MAAM,+CAA+C,OAAO,EAAE;AAC1E;AAEA,SAAS,UAAU,UAA0B;AAC3C,SAAO,SAAS,WAAW,GAAG,KAAK,SAAS,SAAS,GAAG,IAAI,SAAS,MAAM,GAAG,EAAE,IAAI;AACtF;AAEA,SAAS,oBAAoB,OAAuB;AAClD,MAAI;AACJ,MAAI;AACF,UAAM,IAAI,IAAI,KAAK;AAAA,EACrB,QAAQ;AACN,UAAM,IAAI,MAAM,gDAAgD;AAAA,EAClE;AACA,MAAI,IAAI,aAAa,YAAY,CAAC,eAAe,GAAG,GAAG;AACrD,UAAM,IAAI,MAAM,wDAAwD;AAAA,EAC1E;AACA,MAAI,IAAI,YAAY,IAAI,YAAY,IAAI,UAAU,IAAI,MAAM;AAC1D,UAAM,IAAI,MAAM,yEAAyE;AAAA,EAC3F;AACA,SAAO,IAAI,SAAS;AACtB;AAEA,SAAS,eAAe,QAAqC;AAC3D,MAAI,OAAO,SAAS,IAAK,OAAM,IAAI,MAAM,0CAA0C;AACnF,QAAM,aAAa,OAAO,IAAI,CAAC,UAAU;AACvC,QAAI,CAAC,SAAS,MAAM,SAAS,OAAO,KAAK,KAAK,KAAK,GAAG;AACpD,YAAM,IAAI,MAAM,mDAAmD;AAAA,IACrE;AACA,WAAO;AAAA,EACT,CAAC;AACD,SAAO,CAAC,GAAG,IAAI,IAAI,UAAU,CAAC;AAChC;AAEA,SAAS,qBAAqB,OAAuB;AACnD,MAAI,MAAM,SAAS,MAAM,MAAM,SAAS,OAAO,CAAC,qBAAqB,KAAK,KAAK,GAAG;AAChF,UAAM,IAAI,MAAM,yCAAyC;AAAA,EAC3D;AACA,SAAO;AACT;AAEA,SAAS,kBAAkB,OAAe,OAAuB;AAC/D,MAAI,CAAC,SAAS,MAAM,SAAS,SAAU,SAAS,KAAK,KAAK,GAAG;AAC3D,UAAM,IAAI,MAAM,aAAa,KAAK,kCAAkC;AAAA,EACtE;AACA,SAAO;AACT;AAEA,SAAS,iBAAiB,OAAuB;AAC/C,SAAO,0BAA0B,KAAK,KAAK,IAAI,QAAQ;AACzD;AAEA,SAAS,UAAU,OAA2B;AAC5C,SAAO,OAAO,KAAK,KAAK,EAAE,SAAS,WAAW;AAChD;AAEA,SAAS,kBAAkB,MAAc,OAAwB;AAC/D,QAAM,WAAW,WAAW,QAAQ,EAAE,OAAO,IAAI,EAAE,OAAO;AAC1D,QAAM,YAAY,WAAW,QAAQ,EAAE,OAAO,KAAK,EAAE,OAAO;AAC5D,SAAO,gBAAgB,UAAU,SAAS;AAC5C;AAEA,SAAS,mBAAmB,OAAgB,UAA+B;AACzE,QAAM,WAAW,OAAO,OAAO,gBAAgB;AAC/C,QAAM,cAAc;AAAA,IAClB,eAAe,SAAS,cAAc,GAAG,cAAc;AAAA,IACvD;AAAA,EACF;AACA,QAAM,YAAY,eAAe,SAAS,YAAY,GAAG,YAAY,KAAK;AAC1E,MAAI,UAAU,YAAY,MAAM,UAAU;AACxC,UAAM,IAAI,MAAM,qCAAqC,SAAS,GAAG;AAAA,EACnE;AACA,QAAM,YAAY,SAAS,YAAY;AACvC,MAAI;AACJ,MAAI,cAAc,QAAW;AAC3B,QACE,OAAO,cAAc,YACrB,CAAC,OAAO,SAAS,SAAS,KAC1B,aAAa,KACb,YAAY,SACZ;AACA,YAAM,IAAI,MAAM,0DAA0D;AAAA,IAC5E;AACA,gBAAY,KAAK,IAAI,IAAI,KAAK,MAAM,YAAY,GAAK;AAAA,EACvD;AACA,QAAM,UAAU,eAAe,SAAS,eAAe,GAAG,eAAe;AACzE,QAAM,QAAQ,eAAe,SAAS,OAAO,GAAG,OAAO;AACvD,QAAM,QAAqB;AAAA,IACzB;AAAA,IACA,WAAW;AAAA,IACX;AAAA,IACA,QAAQ,QAAQ,eAAe,MAAM,MAAM,KAAK,EAAE,OAAO,OAAO,CAAC,IAAI,CAAC;AAAA,IACtE,GAAI,cAAc,SAAY,EAAE,UAAU,IAAI,CAAC;AAAA,IAC/C,GAAI,UAAU,EAAE,cAAc,kBAAkB,SAAS,eAAe,EAAE,IAAI,CAAC;AAAA,EACjF;AACA,8BAA4B,OAAO,QAAQ;AAC3C,SAAO;AACT;AAEA,SAAS,4BAA4B,UAAsC;AACzE,QAAM,MAAM,IAAI,IAAI,QAAQ;AAC5B,SAAO,eAAe,GAAG,IAAI,UAAU,IAAI,QAAQ,EAAE,YAAY,IAAI;AACvE;AAEA,SAAS,eAAe,KAAmB;AACzC,MAAI,IAAI,aAAa,QAAS,QAAO;AACrC,SACE,IAAI,aAAa,eACjB,IAAI,aAAa,eACjB,IAAI,aAAa,WACjB,IAAI,aAAa;AAErB;;;AC5yBA,IAAM,yBAAyB,KAAK;AACpC,IAAM,6BAA6B;AAiE5B,IAAM,0BAAN,MAA8B;AAAA,EAOnC,YAA6B,SAAyC;AAAzC;AAC3B,SAAK,eAAe,QAAQ,gBAAgB;AAC5C,QAAI,CAAC,OAAO,SAAS,KAAK,YAAY,KAAK,KAAK,gBAAgB,GAAG;AACjE,YAAM,IAAI,MAAM,gEAAgE;AAAA,IAClF;AACA,SAAK,WAAW,QAAQ,YAAY;AACpC,SAAK,WAAW,QAAQ,YAAY;AACpC,SAAK,MAAM,QAAQ,OAAO,KAAK;AAAA,EACjC;AAAA,EAR6B;AAAA,EANZ,UAAU,oBAAI,IAAkC;AAAA,EAChD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAYjB,MAAM,MAAM,OAAyE;AACnF,UAAM,WAAW,qBAAqB,MAAM,QAAQ;AACpD,UAAM,MAAM,iBAAiB,MAAM,YAAY,QAAQ;AACvD,SAAK,aAAa;AAClB,QAAI,CAAC,KAAK,QAAQ,IAAI,GAAG,KAAK,KAAK,QAAQ,QAAQ,4BAA4B;AAC7E,YAAM,IAAI,MAAM,6CAA6C;AAAA,IAC/D;AACA,UAAM,YAAY,MAAM,KAAK,SAAS,UAAU;AAAA,MAC9C,iBAAiB,MAAM;AAAA,MACvB,QAAQ,MAAM;AAAA,IAChB,CAAC;AACD,UAAM,kBAAkB,wBAAwB,MAAM,mBAAmB,MAAM,QAAQ,EAAE;AACzF,UAAM,SAAS,MAAM,SAAS,CAAC,GAAG,MAAM,MAAM,IAAI;AAClD,UAAM,UAAU,8BAA8B;AAAA,MAC5C,qBAAqB,UAAU;AAAA,MAC/B,UAAU,MAAM;AAAA,MAChB,aAAa,MAAM;AAAA,MACnB;AAAA,MACA;AAAA,IACF,CAAC;AACD,UAAM,mBACJ,IAAI,IAAI,QAAQ,gBAAgB,EAAE,aAAa,IAAI,OAAO,GAAG,MAAM,GAAG,EAAE,OAAO,OAAO,KAAK,CAAC;AAC9F,UAAM,YAAY,KAAK,IAAI,IAAI,KAAK;AACpC,SAAK,QAAQ,IAAI,KAAK,EAAE,SAAS,WAAW,QAAQ,kBAAkB,UAAU,CAAC;AACjF,WAAO;AAAA,MACL,YAAY,kBAAkB,MAAM,UAAU;AAAA,MAC9C;AAAA,MACA,kBAAkB,QAAQ;AAAA,MAC1B,aAAa,QAAQ;AAAA,MACrB,QAAQ,CAAC,GAAG,gBAAgB;AAAA,MAC5B;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,SAAS,OAAuE;AACpF,UAAM,aAAa,kBAAkB,MAAM,UAAU;AACrD,UAAM,WAAW,qBAAqB,MAAM,QAAQ;AACpD,UAAM,MAAM,iBAAiB,YAAY,QAAQ;AACjD,SAAK,aAAa;AAClB,UAAM,UAAU,KAAK,QAAQ,IAAI,GAAG;AACpC,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,MAAM,0DAA0D;AAAA,IAC5E;AACA,UAAM,OAAO,8BAA8B,MAAM,aAAa,QAAQ,OAAO;AAG7E,SAAK,QAAQ,OAAO,GAAG;AACvB,UAAM,WAAW,MAAM,KAAK,SAAS;AAAA,MACnC,qBAAqB,QAAQ,UAAU;AAAA,MACvC,UAAU,QAAQ,QAAQ;AAAA,MAC1B,aAAa,QAAQ,QAAQ;AAAA,MAC7B;AAAA,MACA;AAAA,MACA,cAAc,QAAQ,QAAQ;AAAA,MAC9B,QAAQ,MAAM;AAAA,IAChB,CAAC;AACD,UAAM,SAAiC;AAAA,MACrC;AAAA,MACA;AAAA,MACA,UAAU,QAAQ,QAAQ;AAAA,MAC1B,qBAAqB,QAAQ,UAAU;AAAA,MACvC;AAAA,MACA,WAAW,IAAI,KAAK,KAAK,IAAI,CAAC,EAAE,YAAY;AAAA,IAC9C;AACA,UAAM,KAAK,QAAQ,MAAM,KAAK,MAAM;AACpC,SAAK,KAAK,cAAc,MAAM;AAC9B,WAAO,iBAAiB,QAAQ,KAAK,IAAI,CAAC;AAAA,EAC5C;AAAA,EAEA,MAAM,OAAO,YAAoB,UAAmD;AAClF,UAAM,iBAAiB,kBAAkB,UAAU;AACnD,UAAM,qBAAqB,qBAAqB,QAAQ;AACxD,SAAK,aAAa;AAClB,UAAM,UAAU,KAAK,QAAQ,IAAI,iBAAiB,gBAAgB,kBAAkB,CAAC;AACrF,QAAI,SAAS;AACX,aAAO;AAAA,QACL,YAAY;AAAA,QACZ,UAAU;AAAA,QACV,OAAO;AAAA,QACP,WAAW,QAAQ;AAAA,QACnB,QAAQ,CAAC,GAAG,QAAQ,MAAM;AAAA,QAC1B,YAAY;AAAA,MACd;AAAA,IACF;AACA,UAAM,SAAS,MAAM,KAAK,QAAQ,MAAM,KAAK,gBAAgB,kBAAkB;AAC/E,WAAO,SACH,iBAAiB,QAAQ,KAAK,IAAI,CAAC,IACnC;AAAA,MACE,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,OAAO;AAAA,MACP,QAAQ,CAAC;AAAA,MACT,YAAY;AAAA,IACd;AAAA,EACN;AAAA,EAEA,MAAM,WAAW,YAAoB,UAAoC;AACvE,UAAM,iBAAiB,kBAAkB,UAAU;AACnD,UAAM,qBAAqB,qBAAqB,QAAQ;AACxD,SAAK,QAAQ,OAAO,iBAAiB,gBAAgB,kBAAkB,CAAC;AACxE,UAAM,UAAU,MAAM,KAAK,QAAQ,MAAM,OAAO,gBAAgB,kBAAkB;AAClF,QAAI,SAAS;AACX,WAAK,QAAQ,gBAAgB;AAAA,QAC3B,YAAY;AAAA,QACZ,OAAO;AAAA,QACP,UAAU;AAAA,MACZ,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,eAAqB;AAC3B,UAAM,MAAM,KAAK,IAAI;AACrB,eAAW,CAAC,KAAK,KAAK,KAAK,KAAK,SAAS;AACvC,UAAI,MAAM,aAAa,IAAK,MAAK,QAAQ,OAAO,GAAG;AAAA,IACrD;AAAA,EACF;AAAA,EAEQ,KAAK,OAA4C,OAAqC;AAC5F,SAAK,QAAQ,gBAAgB;AAAA,MAC3B,YAAY,MAAM;AAAA,MAClB;AAAA,MACA,UAAU,MAAM;AAAA,MAChB,WAAW,MAAM,SAAS;AAAA,MAC1B,QAAQ,CAAC,GAAI,MAAM,SAAS,UAAU,CAAC,CAAE;AAAA,IAC3C,CAAC;AAAA,EACH;AACF;AAEA,SAAS,iBAAiB,OAA+B,KAAqC;AAC5F,SAAO;AAAA,IACL,YAAY,MAAM;AAAA,IAClB,UAAU,MAAM;AAAA,IAChB,OACE,MAAM,SAAS,cAAc,UAAa,MAAM,SAAS,aAAa,MAClE,YACA;AAAA,IACN,WAAW,MAAM,SAAS;AAAA,IAC1B,QAAQ,CAAC,GAAI,MAAM,SAAS,UAAU,CAAC,CAAE;AAAA,IACzC,YAAY,CAAC,CAAC,MAAM,SAAS;AAAA,EAC/B;AACF;AAEA,SAAS,iBAAiB,YAAoB,UAA0B;AACtE,SAAO,GAAG,kBAAkB,UAAU,CAAC,KAAK,QAAQ;AACtD;AAEA,SAAS,kBAAkB,OAAuB;AAChD,MAAI,CAAC,SAAS,MAAM,SAAS,OAAO,WAAW,KAAK,KAAK,GAAG;AAC1D,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AACA,SAAO;AACT;;;AC9PA,SAA4B,aAAa;AACzC,SAAS,qBAAqB;AAC9B,SAAS,sBAAsB;;;ACMxB,IAAM,gBAAgB,OAAO,OAAO;AAAA;AAAA,EAEzC,kBAAkB;AAAA;AAAA,EAGlB,aAAa,OAAO,OAAO;AAAA,IACzB,MAAM;AAAA,IACN,SAAS;AAAA,EACX,CAAC;AAAA;AAAA,EAGD,WAAW,OAAO,OAAO;AAAA;AAAA,IAEvB,YAAY;AAAA;AAAA,IAEZ,eAAe;AAAA;AAAA,IAEf,eAAe;AAAA;AAAA,IAEf,cAAc;AAAA;AAAA,IAEd,oBAAoB;AAAA,EACtB,CAAC;AAAA;AAAA,EAGD,YAAY,OAAO,OAAO;AAAA;AAAA,IAExB,aAAa;AAAA;AAAA,IAEb,kBAAkB;AAAA,EACpB,CAAC;AAAA;AAAA,EAGD,MAAM,OAAO,OAAO;AAAA;AAAA,IAElB,oBAAoB;AAAA;AAAA,IAEpB,mBAAmB;AAAA,EACrB,CAAC;AAAA;AAAA,EAGD,qBAAqB;AAAA;AAAA,EAGrB,uBAAuB,MAAM;AAAA;AAAA,EAG7B,iBAAiB;AACnB,CAAU;;;ACoCV,SAASC,QAAO,OAAgB,OAAwC;AACtE,MAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAAG;AAC/D,UAAM,IAAI,MAAM,iBAAiB,KAAK,mBAAmB;AAAA,EAC3D;AACA,SAAO;AACT;AAEA,SAASC,gBAAe,OAAgB,OAAuB;AAC7D,MAAI,OAAO,UAAU,YAAY,MAAM,WAAW,GAAG;AACnD,UAAM,IAAI,MAAM,iBAAiB,KAAK,6BAA6B;AAAA,EACrE;AACA,SAAO;AACT;AAEA,SAASC,gBAAe,OAAgB,OAAmC;AACzE,MAAI,UAAU,OAAW,QAAO;AAChC,MAAI,OAAO,UAAU,SAAU,OAAM,IAAI,MAAM,iBAAiB,KAAK,mBAAmB;AACxF,SAAO;AACT;AAEA,SAAS,eAAe,OAAgB,OAAoD;AAC1F,MAAI,UAAU,OAAW,QAAO;AAChC,SAAOF,QAAO,OAAO,KAAK;AAC5B;AAEA,SAAS,eAAe,OAAgB,OAAmC;AACzE,SAAOE,gBAAe,OAAO,GAAG,KAAK,aAAa;AACpD;AAEO,SAAS,oBAAoB,OAAmC;AACrE,QAAM,QAAQF,QAAO,OAAO,mBAAmB;AAC/C,QAAM,aAAaA,QAAO,MAAM,YAAY,GAAG,uBAAuB;AACtE,QAAM,eAAeA,QAAO,MAAM,cAAc,GAAG,yBAAyB;AAC5E,SAAO;AAAA,IACL,iBAAiBC,gBAAe,MAAM,iBAAiB,GAAG,4BAA4B;AAAA,IACtF;AAAA,IACA,YAAY;AAAA,MACV,MAAMA,gBAAe,WAAW,MAAM,GAAG,4BAA4B;AAAA,MACrE,SAASA,gBAAe,WAAW,SAAS,GAAG,+BAA+B;AAAA,MAC9E,OAAOC,gBAAe,WAAW,OAAO,GAAG,6BAA6B;AAAA,IAC1E;AAAA,IACA,cAAcA,gBAAe,MAAM,cAAc,GAAG,yBAAyB;AAAA,EAC/E;AACF;AAEA,SAAS,cAAc,OAAgB,OAA4B;AACjE,QAAM,QAAQF,QAAO,OAAO,4BAA4B,KAAK,GAAG;AAChE,QAAM,OAAO,MAAM,MAAM;AACzB,MAAI,SAAS,WAAc,OAAO,SAAS,YAAY,CAAC,OAAO,SAAS,IAAI,KAAK,OAAO,IAAI;AAC1F,UAAM,IAAI,MAAM,0CAA0C,KAAK,QAAQ;AAAA,EACzE;AACA,SAAO;AAAA,IACL,KAAKC,gBAAe,MAAM,KAAK,GAAG,4BAA4B,KAAK,OAAO;AAAA,IAC1E,MAAMA,gBAAe,MAAM,MAAM,GAAG,4BAA4B,KAAK,QAAQ;AAAA,IAC7E,OAAOC,gBAAe,MAAM,OAAO,GAAG,4BAA4B,KAAK,SAAS;AAAA,IAChF,aAAaA;AAAA,MACX,MAAM,aAAa;AAAA,MACnB,4BAA4B,KAAK;AAAA,IACnC;AAAA,IACA,UAAUA,gBAAe,MAAM,UAAU,GAAG,4BAA4B,KAAK,YAAY;AAAA,IACzF;AAAA,IACA,aAAa;AAAA,MACX,MAAM,aAAa;AAAA,MACnB,4BAA4B,KAAK;AAAA,IACnC;AAAA,EACF;AACF;AAEO,SAAS,yBAAyB,OAAwC;AAC/E,QAAM,QAAQF,QAAO,OAAO,uBAAuB;AACnD,MAAI,CAAC,MAAM,QAAQ,MAAM,WAAW,CAAC,GAAG;AACtC,UAAM,IAAI,MAAM,iEAAiE;AAAA,EACnF;AACA,SAAO;AAAA,IACL,WAAW,MAAM,WAAW,EAAE,IAAI,aAAa;AAAA,IAC/C,YAAY,eAAe,MAAM,YAAY,GAAG,gBAAgB;AAAA,EAClE;AACF;AAEO,SAAS,iCAAiC,OAAgD;AAC/F,QAAM,QAAQA,QAAO,OAAO,iCAAiC;AAC7D,QAAM,YAAY,MAAM,mBAAmB;AAC3C,MAAI,CAAC,MAAM,QAAQ,SAAS,GAAG;AAC7B,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO;AAAA,IACL,mBAAmB,UAAU,IAAI,CAACG,QAAO,UAAU;AACjD,YAAM,WAAWH,QAAOG,QAAO,8CAA8C,KAAK,GAAG;AACrF,aAAO;AAAA,QACL,aAAaF;AAAA,UACX,SAAS,aAAa;AAAA,UACtB,8CAA8C,KAAK;AAAA,QACrD;AAAA,QACA,MAAMA;AAAA,UACJ,SAAS,MAAM;AAAA,UACf,8CAA8C,KAAK;AAAA,QACrD;AAAA,QACA,OAAOC;AAAA,UACL,SAAS,OAAO;AAAA,UAChB,8CAA8C,KAAK;AAAA,QACrD;AAAA,QACA,aAAaA;AAAA,UACX,SAAS,aAAa;AAAA,UACtB,8CAA8C,KAAK;AAAA,QACrD;AAAA,QACA,UAAUA;AAAA,UACR,SAAS,UAAU;AAAA,UACnB,8CAA8C,KAAK;AAAA,QACrD;AAAA,QACA,aAAa;AAAA,UACX,SAAS,aAAa;AAAA,UACtB,8CAA8C,KAAK;AAAA,QACrD;AAAA,MACF;AAAA,IACF,CAAC;AAAA,IACD,YAAY,eAAe,MAAM,YAAY,GAAG,0BAA0B;AAAA,EAC5E;AACF;AAEO,SAAS,wBAAwB,OAAuC;AAC7E,QAAM,QAAQF,QAAO,OAAO,uBAAuB;AACnD,MAAI,CAAC,MAAM,QAAQ,MAAM,UAAU,CAAC,GAAG;AACrC,UAAM,IAAI,MAAM,gEAAgE;AAAA,EAClF;AACA,SAAO;AAAA,IACL,UAAU,MAAM,UAAU,EAAE,IAAI,CAACG,QAAO,UAAU;AAChD,YAAM,UAAUH,QAAOG,QAAO,2BAA2B,KAAK,GAAG;AACjE,YAAM,OAAOD,gBAAe,QAAQ,MAAM,GAAG,2BAA2B,KAAK,QAAQ;AACrF,YAAM,OAAOA,gBAAe,QAAQ,MAAM,GAAG,2BAA2B,KAAK,QAAQ;AACrF,UAAI,SAAS,UAAa,SAAS,QAAW;AAC5C,cAAM,IAAI,MAAM,yCAAyC,KAAK,0BAA0B;AAAA,MAC1F;AACA,aAAO;AAAA,QACL,KAAKD,gBAAe,QAAQ,KAAK,GAAG,2BAA2B,KAAK,OAAO;AAAA,QAC3E,UAAUC,gBAAe,QAAQ,UAAU,GAAG,2BAA2B,KAAK,YAAY;AAAA,QAC1F;AAAA,QACA;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAEA,SAAS,oBACP,OACA,aACA,UACmB;AACnB,QAAM,QAAQF,QAAO,OAAO,wBAAwB,WAAW,eAAe,QAAQ,GAAG;AACzF,QAAM,WAAW,MAAM,UAAU;AACjC,MAAI,aAAa,UAAa,OAAO,aAAa,WAAW;AAC3D,UAAM,IAAI;AAAA,MACR,sCAAsC,WAAW,eAAe,QAAQ;AAAA,IAC1E;AAAA,EACF;AACA,SAAO;AAAA,IACL,MAAMC;AAAA,MACJ,MAAM,MAAM;AAAA,MACZ,wBAAwB,WAAW,eAAe,QAAQ;AAAA,IAC5D;AAAA,IACA,aAAaC;AAAA,MACX,MAAM,aAAa;AAAA,MACnB,wBAAwB,WAAW,eAAe,QAAQ;AAAA,IAC5D;AAAA,IACA;AAAA,EACF;AACF;AAEO,SAAS,uBAAuB,OAAsC;AAC3E,QAAM,QAAQF,QAAO,OAAO,qBAAqB;AACjD,MAAI,CAAC,MAAM,QAAQ,MAAM,SAAS,CAAC,GAAG;AACpC,UAAM,IAAI,MAAM,6DAA6D;AAAA,EAC/E;AACA,SAAO;AAAA,IACL,SAAS,MAAM,SAAS,EAAE,IAAI,CAACG,QAAO,UAAU;AAC9C,YAAM,SAASH,QAAOG,QAAO,wBAAwB,KAAK,GAAG;AAC7D,YAAM,OAAO,OAAO,WAAW;AAC/B,UAAI,SAAS,UAAa,CAAC,MAAM,QAAQ,IAAI,GAAG;AAC9C,cAAM,IAAI,MAAM,sCAAsC,KAAK,aAAa;AAAA,MAC1E;AACA,aAAO;AAAA,QACL,MAAMF,gBAAe,OAAO,MAAM,GAAG,wBAAwB,KAAK,QAAQ;AAAA,QAC1E,OAAOC,gBAAe,OAAO,OAAO,GAAG,wBAAwB,KAAK,SAAS;AAAA,QAC7E,aAAaA;AAAA,UACX,OAAO,aAAa;AAAA,UACpB,wBAAwB,KAAK;AAAA,QAC/B;AAAA,QACA,WAAW,MAAM,IAAI,CAAC,KAAK,aAAa,oBAAoB,KAAK,OAAO,QAAQ,CAAC;AAAA,MACnF;AAAA,IACF,CAAC;AAAA,IACD,YAAY,eAAe,MAAM,YAAY,GAAG,cAAc;AAAA,EAChE;AACF;AAEO,SAAS,qBAAqB,OAAoC;AACvE,QAAM,QAAQF,QAAO,OAAO,oBAAoB;AAChD,MAAI,CAAC,MAAM,QAAQ,MAAM,UAAU,CAAC,GAAG;AACrC,UAAM,IAAI,MAAM,6DAA6D;AAAA,EAC/E;AACA,SAAO;AAAA,IACL,aAAaE,gBAAe,MAAM,aAAa,GAAG,yBAAyB;AAAA,IAC3E,UAAU,MAAM,UAAU,EAAE,IAAI,CAACC,QAAO,UAAU;AAChD,YAAM,UAAUH,QAAOG,QAAO,wBAAwB,KAAK,GAAG;AAC9D,YAAM,OAAO,QAAQ,MAAM;AAC3B,UAAI,SAAS,UAAU,SAAS,aAAa;AAC3C,cAAM,IAAI,MAAM,sCAAsC,KAAK,QAAQ;AAAA,MACrE;AACA,UAAI,QAAQ,SAAS,MAAM,QAAW;AACpC,cAAM,IAAI,MAAM,sCAAsC,KAAK,WAAW;AAAA,MACxE;AACA,aAAO,EAAE,MAAM,SAAS,QAAQ,SAAS,EAAE;AAAA,IAC7C,CAAC;AAAA,EACH;AACF;;;AChTO,SAAS,kBAAkB,OAA2B;AAC3D,MAAI,CAAC,MAAM,QAAQ,KAAK,EAAG,QAAO,CAAC;AACnC,QAAM,QAAmB,CAAC;AAC1B,aAAW,OAAO,OAAO;AACvB,QAAI,CAAC,OAAO,OAAO,QAAQ,SAAU;AACrC,UAAM,IAAI;AACV,QAAI,OAAO,EAAE,SAAS,YAAY,EAAE,KAAK,KAAK,EAAE,WAAW,EAAG;AAC9D,UAAM,cACJ,EAAE,eAAe,OAAO,EAAE,gBAAgB,YAAY,CAAC,MAAM,QAAQ,EAAE,WAAW,IAC7E,EAAE,cACH,EAAE,MAAM,UAAU,YAAY,CAAC,EAAE;AAIvC,QAAI,CAAC,EAAE,eAAe,OAAO,EAAE,gBAAgB,YAAY,MAAM,QAAQ,EAAE,WAAW,GAAG;AACvF,cAAQ,KAAK,KAAK,UAAU;AAAA,QAC1B,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM,EAAE;AAAA,QACR,SAAS;AAAA,QACT,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MACpC,CAAC,CAAC;AAAA,IACJ;AACA,UAAM,KAAK;AAAA,MACT,MAAM,EAAE;AAAA,MACR,GAAI,OAAO,EAAE,gBAAgB,WAAW,EAAE,aAAa,EAAE,YAAY,IAAI,CAAC;AAAA,MAC1E;AAAA,IACF,CAAC;AAAA,EACH;AACA,SAAO;AACT;;;AChCA,SAAS,iBAAiB;AAkBnB,SAAS,gBAAgB,GAAgC;AAC9D,MAAI,OAAO,MAAM,YAAY,MAAM,KAAM,QAAO;AAChD,QAAM,IAAI;AACV,MAAI,EAAE,SAAS,MAAM,SAAS,OAAO,EAAE,IAAI,MAAM,SAAU,QAAO;AAClE,MAAI,OAAO,OAAO,GAAG,QAAQ,EAAG,QAAO;AAEvC,QAAM,YAAY,OAAO,OAAO,GAAG,QAAQ;AAC3C,QAAM,WAAW,OAAO,OAAO,GAAG,OAAO;AACzC,MAAI,cAAc,SAAU,QAAO;AACnC,MAAI,UAAU;AACZ,UAAM,QAAQ,EAAE,OAAO;AACvB,WACE,OAAO,UAAU,YACjB,UAAU,QACV,OAAQ,MAAkC,MAAM,MAAM,YACtD,OAAQ,MAAkC,SAAS,MAAM;AAAA,EAE7D;AACA,SAAO;AACT;AAEA,SAAS,wBAAwB,GAAwC;AACvE,MAAI,OAAO,MAAM,YAAY,MAAM,KAAM,QAAO;AAChD,QAAM,WAAW;AACjB,MAAI,SAAS,SAAS,MAAM,SAAS,OAAO,SAAS,QAAQ,MAAM,SAAU,QAAO;AACpF,QAAM,KAAK,SAAS,IAAI;AACxB,SAAO,OAAO,UAAa,OAAO,OAAO,YAAY,OAAO,OAAO;AACrE;AAUO,SAAS,wBAAwB,MAAiC;AACvE,QAAM,MAAyB,CAAC;AAChC,MAAI,UAAoB,CAAC;AACzB,QAAM,QAAQ,MAAM;AAClB,QAAI,QAAQ,WAAW,EAAG;AAC1B,UAAM,SAAS,QAAQ,KAAK,IAAI,EAAE,KAAK;AACvC,cAAU,CAAC;AACX,QAAI,CAAC,OAAQ;AACb,QAAI;AACF,YAAM,SAAS,KAAK,MAAM,MAAM;AAChC,UAAI,gBAAgB,MAAM,KAAK,wBAAwB,MAAM,EAAG,KAAI,KAAK,MAAM;AAAA,IACjF,QAAQ;AAAA,IAER;AAAA,EACF;AACA,aAAW,OAAO,KAAK,MAAM,IAAI,GAAG;AAClC,UAAM,OAAO,IAAI,QAAQ,OAAO,EAAE;AAClC,QAAI,SAAS,IAAI;AACf,YAAM;AACN;AAAA,IACF;AACA,QAAI,KAAK,WAAW,GAAG,EAAG;AAC1B,QAAI,KAAK,WAAW,OAAO,GAAG;AAC5B,UAAI,IAAI,KAAK,MAAM,CAAC;AACpB,UAAI,EAAE,WAAW,GAAG,EAAG,KAAI,EAAE,MAAM,CAAC;AACpC,cAAQ,KAAK,CAAC;AACd;AAAA,IACF;AACA,QAAI,KAAK,WAAW,QAAQ,KAAK,KAAK,WAAW,KAAK,KAAK,KAAK,WAAW,QAAQ,GAAG;AACpF;AAAA,IACF;AAEA,UAAM,UAAU,KAAK,KAAK;AAC1B,QAAI,QAAQ,WAAW,GAAG,KAAK,QAAQ,WAAW,GAAG,GAAG;AACtD,UAAI;AACF,cAAM,SAAS,KAAK,MAAM,OAAO;AACjC,YAAI,gBAAgB,MAAM,KAAK,wBAAwB,MAAM,EAAG,KAAI,KAAK,MAAM;AAAA,MACjF,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AACA,QAAM;AACN,SAAO;AACT;AAGO,SAAS,sBAAsB,MAA+B;AACnE,SAAO,wBAAwB,IAAI,EAAE,OAAO,eAAe;AAC7D;AAEO,SAAS,4BACd,MACA,YACA,QACe;AACf,MAAI,CAAC,gBAAgB,IAAI,GAAG;AAC1B,UAAM,IAAI,UAAU;AAAA,MAClB,SAAS;AAAA,MACT,MAAM;AAAA,MACN,UAAU;AAAA,MACV,SAAS,EAAE,QAAQ,YAAY,QAAQ,uBAAuB;AAAA,IAChE,CAAC;AAAA,EACH;AACA,MAAI,KAAK,OAAO,YAAY;AAC1B,UAAM,IAAI,UAAU;AAAA,MAClB,SAAS,8CAA8C,MAAM,cAAc,UAAU,SAAS,KAAK,EAAE;AAAA,MACrG,MAAM;AAAA,MACN,UAAU;AAAA,MACV,SAAS,EAAE,QAAQ,YAAY,UAAU,KAAK,IAAI,QAAQ,cAAc;AAAA,IAC1E,CAAC;AAAA,EACH;AACA,SAAO;AACT;;;AChIA,SAAS,aAAAC,kBAAiB;AAkB1B,IAAM,wBAAwB,MAAM;AAIpC,IAAM,4BAA4B;AAE3B,IAAM,YAAN,MAAgB;AAAA,EACb,SAAS;AAAA,EACT,YAAsB,CAAC;AAAA,EACvB,YAOJ,CAAC;AAAA,EAEL,UACE,IAMY;AACZ,SAAK,UAAU,KAAK,EAAE;AACtB,WAAO,MAAM;AACX,YAAM,MAAM,KAAK,UAAU,QAAQ,EAAE;AACrC,UAAI,OAAO,EAAG,MAAK,UAAU,OAAO,KAAK,CAAC;AAAA,IAC5C;AAAA,EACF;AAAA,EAEA,KAAK,OAAqB;AAExB,QAAI,MAAM,SAAS,uBAAuB;AACxC,YAAM,IAAIA,WAAU;AAAA,QAClB,SAAS,mBAAmB,MAAM,MAAM,uBAAuB,qBAAqB;AAAA,QACpF,MAAM;AAAA,QACN,UAAU;AAAA,QACV,SAAS,EAAE,OAAO,QAAQ,aAAa,MAAM,QAAQ,WAAW,sBAAsB;AAAA,MACxF,CAAC;AAAA,IACH;AACA,SAAK,UAAU;AACf,QAAI,KAAK,OAAO,SAAS,uBAAuB;AAC9C,YAAM,IAAIA,WAAU;AAAA,QAClB,SAAS,6BAA6B,qBAAqB;AAAA,QAC3D,MAAM;AAAA,QACN,UAAU;AAAA,QACV,SAAS;AAAA,UACP,OAAO;AAAA,UACP,cAAc,KAAK,OAAO;AAAA,UAC1B,WAAW;AAAA,QACb;AAAA,MACF,CAAC;AAAA,IACH;AAIA,QAAI,QAAQ;AACZ,QAAI,MAAM,KAAK,OAAO,QAAQ,MAAM,KAAK;AACzC,WAAO,QAAQ,IAAI;AACjB,UAAI,MAAM;AACV,UAAI,MAAM,SAAS,KAAK,OAAO,WAAW,MAAM,CAAC,MAAM,GAAa;AACpE,WAAK,YAAY,KAAK,OAAO,MAAM,OAAO,GAAG,CAAC;AAC9C,cAAQ,MAAM;AACd,YAAM,KAAK,OAAO,QAAQ,MAAM,KAAK;AAAA,IACvC;AACA,QAAI,QAAQ,EAAG,MAAK,SAAS,KAAK,OAAO,MAAM,KAAK;AAAA,EACtD;AAAA,EAEQ,YAAY,MAAoB;AACtC,QAAI,SAAS,IAAI;AACf,WAAK,MAAM;AACX;AAAA,IACF;AACA,QAAI,KAAK,WAAW,GAAG,EAAG;AAE1B,UAAM,WAAW,KAAK,QAAQ,GAAG;AACjC,UAAM,QAAQ,aAAa,KAAK,OAAO,KAAK,MAAM,GAAG,QAAQ;AAC7D,QAAI,QAAQ,aAAa,KAAK,KAAK,KAAK,MAAM,WAAW,CAAC;AAC1D,QAAI,MAAM,WAAW,GAAG,EAAG,SAAQ,MAAM,MAAM,CAAC;AAEhD,QAAI,UAAU,SAAS;AAAA,IAGvB,WAAW,UAAU,QAAQ;AAC3B,UAAI,KAAK,UAAU,UAAU,2BAA2B;AACtD,cAAM,IAAIA,WAAU;AAAA,UAClB,SAAS,iBAAiB,yBAAyB;AAAA,UACnD,MAAM;AAAA,UACN,UAAU;AAAA,UACV,SAAS;AAAA,YACP,OAAO;AAAA,YACP,eAAe,KAAK,UAAU;AAAA,YAC9B,cAAc;AAAA,UAChB;AAAA,QACF,CAAC;AAAA,MACH;AACA,WAAK,UAAU,KAAK,KAAK;AAAA,IAC3B;AAAA,EACF;AAAA,EAEQ,QAAc;AACpB,QAAI,KAAK,UAAU,WAAW,GAAG;AAC/B;AAAA,IACF;AACA,UAAM,OAAO,KAAK,UAAU,KAAK,IAAI,EAAE,KAAK;AAC5C,SAAK,YAAY,CAAC;AAClB,QAAI,CAAC,KAAM;AACX,QAAI;AACF,YAAM,SAAS,KAAK,MAAM,IAAI;AAM9B,WAAK,SAAS,MAAM;AAAA,IACtB,QAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEQ,SAAS,KAKR;AACP,eAAW,MAAM,KAAK,WAAW;AAC/B,UAAI;AACF,WAAG,GAAG;AAAA,MACR,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AAAA,EAEA,QAAc;AACZ,SAAK,SAAS;AACd,SAAK,YAAY,CAAC;AAClB,SAAK,YAAY,CAAC;AAAA,EACpB;AACF;;;ACjKA,YAAYC,YAAW;AACvB,SAAS,eAAAC,oBAAmB;;;ACD5B,YAAYC,UAAS;AACrB,SAAS,mBAAmB;AAErB,SAAS,qBAA8B;AAC5C,SAAO,QAAQ,IAAI,2BAA2B,MAAM;AACtD;AAYO,SAAS,qBAAqB,QAAsB;AACzD,MAAI;AACJ,MAAI;AACF,UAAM,IAAI,IAAI,MAAM;AAAA,EACtB,QAAQ;AACN,UAAM,IAAI,YAAY;AAAA,MACpB,SAAS,+BAA+B,MAAM;AAAA,MAC9C,MAAM;AAAA,MACN,SAAS,EAAE,OAAO,OAAO,OAAO;AAAA,IAClC,CAAC;AAAA,EACH;AAEA,MAAI,IAAI,aAAa,WAAW,IAAI,aAAa,UAAU;AACzD,UAAM,IAAI,YAAY;AAAA,MACpB,SAAS,wCAAwC,IAAI,QAAQ;AAAA,MAC7D,MAAM;AAAA,MACN,SAAS,EAAE,OAAO,OAAO,QAAQ,UAAU,IAAI,SAAS;AAAA,IAC1D,CAAC;AAAA,EACH;AAEA,QAAM,WAAW,IAAI;AAGrB,QAAM,OACJ,SAAS,WAAW,GAAG,KAAK,SAAS,SAAS,GAAG,IAAI,SAAS,MAAM,GAAG,EAAE,IAAI;AAG/E,QAAM,YAAgB,UAAK,IAAI;AAC/B,MAAI,cAAc,GAAG;AACnB,UAAM,QAAQ,KAAK,MAAM,GAAG,EAAE,IAAI,MAAM;AAExC,QAAI,MAAM,CAAC,MAAM,OAAO,MAAM,CAAC,MAAM,KAAK;AACxC,YAAM,IAAI,YAAY;AAAA,QACpB,SAAS,mDAAmD,QAAQ;AAAA,QACpE,MAAM;AAAA,QACN,SAAS,EAAE,OAAO,OAAO,QAAQ,SAAS;AAAA,MAC5C,CAAC;AAAA,IACH;AAAA,EACF,WAAW,cAAc,GAAG;AAC1B,UAAM,QAAQ,KAAK,YAAY;AAG/B,UAAM,YAAY,YAAY,KAAK,KAAK;AACxC,QAAI,aAAa,UAAU,iBAAiB;AAC1C,YAAM,IAAI,YAAY;AAAA,QACpB,SAAS,mDAAmD,QAAQ;AAAA,QACpE,MAAM;AAAA,QACN,SAAS,EAAE,OAAO,OAAO,QAAQ,SAAS;AAAA,MAC5C,CAAC;AAAA,IACH;AAAA,EACF;AAMA,MAAI,IAAI,aAAa,SAAS;AAC5B,UAAM,aACJ,aAAa,eACb,aAAa,eACb,aAAa,SACb,aAAa;AACf,QAAI,CAAC,YAAY;AACf,YAAM,IAAI,YAAY;AAAA,QACpB,SAAS,oFAAoF,QAAQ;AAAA,QACrG,MAAM;AAAA,QACN,SAAS,EAAE,OAAO,OAAO,QAAQ,UAAU,UAAU,IAAI,SAAS;AAAA,MACpE,CAAC;AAAA,IACH;AAAA,EACF;AACF;;;AD9CO,SAAS,eAAe,QAAuB;AACpD,QAAM,MAAM,IAAI,MAAM,gBAAgB,MAAM,qBAAqB;AACjE,MAAI,OAAO;AACX,SAAO;AACT;AAEO,SAAS,oBACd,QACA,WAC8C;AAC9C,QAAM,OAAO,IAAI,gBAAgB;AACjC,QAAM,UAAU,MAAM,KAAK,MAAM,QAAQ,MAAM;AAC/C,MAAI,QAAQ,SAAS;AACnB,SAAK,MAAM,OAAO,MAAM;AAAA,EAC1B,OAAO;AACL,YAAQ,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;AAAA,EAC3D;AACA,QAAM,QAAQ;AAAA,IACZ,MAAM,KAAK,MAAM,IAAI,MAAM,oCAAoC,SAAS,IAAI,CAAC;AAAA,IAC7E;AAAA,EACF;AACA,SAAO;AAAA,IACL,QAAQ,KAAK;AAAA,IACb,SAAS,MAAM;AACb,mBAAa,KAAK;AAClB,cAAQ,oBAAoB,SAAS,OAAO;AAAA,IAC9C;AAAA,EACF;AACF;AAYO,IAAe,oBAAf,MAAiC;AAAA,EAC5B,QAAyB;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA,QAAmB,CAAC;AAAA,EAC7B;AAAA,EACA;AAAA,EACS,qBAAwC,CAAC;AAAA,EACzC,wBAAwB,oBAAI,IAAgC;AAAA,EAC5D,4BAA4B,oBAAI,IAAgB;AAAA,EAChD,0BAA0B,oBAAI,IAAgB;AAAA,EACvD;AAAA,EAEV,YAAY,MAA4B,eAAuB;AAC7D,yBAAqB,KAAK,GAAG;AAC7B,SAAK,OAAO,KAAK;AACjB,SAAK,MAAM,KAAK;AAChB,SAAK,UAAU,EAAE,GAAG,KAAK,QAAQ;AACjC,SAAK,wBAAwB,KAAK;AAClC,SAAK,wBAAwB,qBAAqB,KAAK,GAAG;AAC1D,SAAK,UAAU,KAAK,oBAAoB;AACxC,SAAK,iBAAiB,KAAK,oBAAoB;AAC/C,QAAI,KAAK,KAAK;AACZ,UAAI,KAAK,IAAI,uBAAuB,OAAO;AACzC,YAAI,CAAC,mBAAmB,GAAG;AACzB,gBAAM,IAAIC,aAAY;AAAA,YACpB,SACE,QAAQ,aAAa,qHAC6B,KAAK,GAAG;AAAA,YAC5D,MAAM;AAAA,YACN,SAAS,EAAE,OAAO,0BAA0B,eAAe,KAAK,KAAK,IAAI;AAAA,UAC3E,CAAC;AAAA,QACH;AACA,gBAAQ;AAAA,UACN,QAAQ,aAAa,gDAAsC,KAAK,GAAG;AAAA,QAErE;AAAA,MACF;AACA,WAAK,WAAW,IAAU,aAAM;AAAA,QAC9B,IAAI,KAAK,IAAI;AAAA,QACb,oBAAoB,KAAK,IAAI;AAAA,MAC/B,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,WAA4B;AAC1B,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAgB,uBACd,OACA,MACA,QACmB;AACnB,UAAM,UAAU;AAAA,MACd,YAAY,KAAK;AAAA,MACjB,UAAU,KAAK;AAAA,MACf;AAAA,IACF;AACA,UAAM,OAAO,YAA+B;AAC1C,cAAQ,eAAe;AACvB,YAAM,UAAU,IAAI,QAAQ,KAAK,OAAO;AACxC,UAAI,KAAK,gBAAiB,SAAQ,IAAI,wBAAwB,KAAK,eAAe;AAClF,YAAM,QAAQ,MAAM,KAAK,uBAAuB,eAAe,OAAO;AACtE,cAAQ,eAAe;AACvB,UAAI,OAAO;AACT,gBAAQ;AAAA,UACN;AAAA,UACA,4BAA4B,OAAO,KAAK,qBAAqB;AAAA,QAC/D;AAAA,MACF;AACA,aAAO,MAAM,OAAO,EAAE,GAAG,MAAM,QAAQ,CAAC;AAAA,IAC1C;AAEA,QAAI,WAAW,MAAM,KAAK;AAC1B,QAAI,SAAS,WAAW,OAAO,CAAC,KAAK,uBAAuB,oBAAoB;AAC9E,aAAO;AAAA,IACT;AACA,UAAM,YAAY;AAAA,MAChB,SAAS,QAAQ,IAAI,kBAAkB;AAAA,MACvC,KAAK;AAAA,IACP;AACA,UAAM,QAAQ,MAAM,KAAK,sBAAsB,mBAAmB,WAAW,OAAO;AACpF,QAAI,CAAC,MAAO,QAAO;AACnB,UAAM,SAAS,MAAM,OAAO,EAAE,MAAM,MAAM,MAAS;AACnD,eAAW,MAAM,KAAK;AACtB,WAAO;AAAA,EACT;AAAA,EAEA,YAAuB;AACrB,WAAO,CAAC,GAAG,KAAK,KAAK;AAAA,EACvB;AAAA,EAEA,oBAAmD;AACjD,UAAM,WAAW,KAAK;AACtB,QAAI,CAAC,SAAU,QAAO;AACtB,WAAO;AAAA,MACL,GAAG;AAAA,MACH,cAAc,EAAE,GAAG,SAAS,aAAa;AAAA,MACzC,YAAY,EAAE,GAAG,SAAS,WAAW;AAAA,IACvC;AAAA,EACF;AAAA,EAEA,aAAa,IAA4B;AACvC,SAAK,mBAAmB,KAAK,EAAE;AAC/B,WAAO,MAAM;AACX,YAAM,MAAM,KAAK,mBAAmB,QAAQ,EAAE;AAC9C,UAAI,OAAO,EAAG,MAAK,mBAAmB,OAAO,KAAK,CAAC;AAAA,IACrD;AAAA,EACF;AAAA,EAEA,eAAe,IAA4C;AACzD,SAAK,sBAAsB,IAAI,EAAE;AACjC,WAAO,MAAM;AACX,WAAK,sBAAsB,OAAO,EAAE;AAAA,IACtC;AAAA,EACF;AAAA,EAEA,mBAAmB,IAA4B;AAC7C,SAAK,0BAA0B,IAAI,EAAE;AACrC,WAAO,MAAM,KAAK,0BAA0B,OAAO,EAAE;AAAA,EACvD;AAAA,EAEA,iBAAiB,IAA4B;AAC3C,SAAK,wBAAwB,IAAI,EAAE;AACnC,WAAO,MAAM,KAAK,wBAAwB,OAAO,EAAE;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMU,mBAAyB;AACjC,eAAW,MAAM,KAAK,oBAAoB;AACxC,UAAI;AACF,WAAG;AAAA,MACL,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AAAA,EAEU,yBAA+B;AACvC,eAAW,MAAM,KAAK,2BAA2B;AAC/C,UAAI;AACF,WAAG;AAAA,MACL,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AAAA,EAEU,uBAA6B;AACrC,eAAW,MAAM,KAAK,yBAAyB;AAC7C,UAAI;AACF,WAAG;AAAA,MACL,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASU,cAAc,WAA8B;AACpD,QAAI,KAAK,UAAU;AAIjB,gBAAU,aAAa,KAAK;AAAA,IAC9B;AAAA,EACF;AAIF;;;AE5QA,SAAS,eAAAC,oBAAmB;AAC5B,SAAS,aAAAC,kBAAiB;AAwBnB,IAAM,eAAN,cAA2B,kBAAkB;AAAA,EAC1C,UAAU;AAAA,EACV,aAAa;AAAA,EACb;AAAA,EACA;AAAA,EAER,YAAY,MAA4B;AACtC,UAAM,MAAM,cAAc;AAAA,EAC5B;AAAA,EAEmB,QAAgB;AACjC,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,MAAc,yBAAwC;AACpD,QAAI;AACF,YAAM,MAAM,MAAM,KAAK,SAAS,cAAc,CAAC,CAAC;AAChD,UAAI,CAAC,IAAI,OAAO;AACd,aAAK,MAAM;AAAA,UACT;AAAA,UACA,KAAK,MAAM;AAAA,UACX,GAAG,kBAAmB,IAAI,QAAwD,KAAK;AAAA,QACzF;AACA,mBAAW,MAAM,KAAK,uBAAuB;AAC3C,cAAI;AACF,eAAG,CAAC,GAAG,KAAK,KAAK,CAAC;AAAA,UACpB,QAAQ;AAAA,UAER;AAAA,QACF;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEA,MAAM,UAAyB;AAC7B,SAAK,QAAQ;AACb,SAAK,iBAAiB;AACtB,SAAK,kBAAkB,IAAI,gBAAgB;AAC3C,UAAM,SAAS,KAAK,gBAAgB;AACpC,UAAM,eAAe,WAAW,MAAM,KAAK,iBAAiB,MAAM,GAAG,KAAK,OAAO;AAEjF,QAAI;AACF,YAAM,SAAS,KAAK,YAAY;AAChC,YAAM,YAAyB;AAAA,QAC7B,SAAS,KAAK;AAAA,QACd;AAAA,MACF;AACA,WAAK,cAAc,SAAS;AAC5B,YAAM,WAAW,MAAM,KAAK,uBAAuB,QAAQ,WAAW,MAAM;AAE5E,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,IAAIC,WAAU;AAAA,UAClB,SAAS,oBAAoB,SAAS,MAAM,KAAK,SAAS,UAAU;AAAA,UACpE,MAAM;AAAA,UACN,UAAU;AAAA,UACV,SAAS,EAAE,KAAK,QAAQ,QAAQ,SAAS,QAAQ,YAAY,SAAS,WAAW;AAAA,QACnF,CAAC;AAAA,MACH;AAEA,UAAI,CAAC,SAAS,MAAM;AAClB,cAAM,IAAIA,WAAU;AAAA,UAClB,SAAS;AAAA,UACT,MAAM;AAAA,UACN,UAAU;AAAA,UACV,SAAS,EAAE,KAAK,QAAQ,QAAQ,eAAe;AAAA,QACjD,CAAC;AAAA,MACH;AAEA,YAAM,cAAc,IAAI,YAAY;AACpC,YAAM,YAAY,IAAI,UAAU;AAChC,WAAK,gBAAgB,IAAI,gBAAgB;AAEzC,gBAAU,UAAU,CAAC,QAAQ;AAE3B,YAAI,IAAI,UAAU,CAAC,IAAI,IAAI;AACzB,cAAI,IAAI,WAAW,oCAAoC;AACrD,iBAAK,KAAK,uBAAuB;AAAA,UACnC,WAAW,IAAI,WAAW,wCAAwC;AAChE,iBAAK,uBAAuB;AAAA,UAC9B,WAAW,IAAI,WAAW,sCAAsC;AAC9D,iBAAK,qBAAqB;AAAA,UAC5B;AAAA,QACF;AAAA,MACF,CAAC;AAED,YAAM,SAAS,SAAS,KAAK,UAAU;AACvC,WAAK,SAAS;AAAA,QACZ,QAAQ,MAAM,OAAO,OAAO;AAAA,QAC5B,aAAa,MAAM,OAAO,YAAY;AAAA,MACxC;AAEA,WAAK,YAAY,QAAQ,aAAa,SAAS;AAE/C,YAAM,UAAU,MAAM,KAAK,SAAS,cAAc;AAAA,QAChD,iBAAiB,cAAc;AAAA,QAC/B,cAAc,EAAE,OAAO,CAAC,EAAE;AAAA,QAC1B,YAAY,cAAc;AAAA,MAC5B,CAAC;AAED,UAAI,QAAQ,OAAO;AACjB,cAAM,IAAIA,WAAU;AAAA,UAClB,SAAS,sBAAsB,QAAQ,MAAM,OAAO;AAAA,UACpD,MAAM;AAAA,UACN,UAAU;AAAA,UACV,SAAS,EAAE,WAAW,OAAO,KAAK,KAAK,IAAI;AAAA,QAC7C,CAAC;AAAA,MACH;AACA,WAAK,iBAAiB,oBAAoB,QAAQ,MAAM;AACxD,WAAK,kBAAkB,KAAK,eAAe;AAE3C,UAAI;AACF,cAAM,KAAK,SAAS,6BAA6B,CAAC,CAAC;AAAA,MACrD,QAAQ;AAAA,MAER;AAEA,YAAM,WAAW,MAAM,KAAK,SAAS,cAAc,CAAC,CAAC;AACrD,UAAI,SAAS,OAAO;AAClB,aAAK,MAAM,OAAO,GAAG,KAAK,MAAM,MAAM;AAAA,MACxC,OAAO;AACL,cAAM,SAAS,SAAS;AACxB,aAAK,MAAM,OAAO,GAAG,KAAK,MAAM,QAAQ,GAAG,kBAAkB,QAAQ,KAAK,CAAC;AAAA,MAC7E;AAEA,WAAK,QAAQ;AACb,mBAAa,YAAY;AAAA,IAC3B,SAAS,KAAK;AACZ,mBAAa,YAAY;AACzB,WAAK,QAAQ;AACb,WAAK,gBAAgB,MAAM;AAC3B,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAc,YACZ,QACA,SACA,WACe;AACf,QAAI;AACF,aAAO,CAAC,KAAK,YAAY;AACvB,cAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,YAAI,KAAM;AACV,cAAM,QAAQ,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AACpD,kBAAU,KAAK,KAAK;AAAA,MACtB;AAAA,IACF,QAAQ;AAIN,UAAI,KAAK,UAAU,kBAAkB,KAAK,UAAU,UAAU;AAC5D,aAAK,QAAQ;AACb,aAAK,iBAAiB;AAAA,MACxB;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,cAAsB;AAC5B,QAAI;AACF,YAAM,MAAM,IAAI,IAAI,KAAK,GAAG;AAI5B,UAAI,aAAa,IAAI,WAAWC,aAAY,EAAE,EAAE,SAAS,KAAK,CAAC;AAC/D,aAAO,IAAI,SAAS;AAAA,IACtB,QAAQ;AACN,aAAO,KAAK;AAAA,IACd;AAAA,EACF;AAAA,EAEA,MAAc,SACZ,QACA,QACA,MACwB;AACxB,UAAM,KAAK,KAAK,MAAM;AACtB,UAAM,OAAO,KAAK,UAAU,EAAE,SAAS,OAAO,IAAI,QAAQ,OAAO,CAAC;AAElE,UAAM,WAAW,MAAM;AACvB,UAAM,SACJ,YAAY,KAAK,kBACb,YAAY,IAAI,CAAC,KAAK,gBAAgB,QAAQ,QAAQ,CAAC,IACtD,YAAY,KAAK,iBAAiB;AACzC,UAAM,gBAAgB,oBAAoB,QAAQ,KAAK,cAAc;AACrE,UAAM,YAAyB;AAAA,MAC7B,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,GAAG,KAAK;AAAA,MACV;AAAA,MACA;AAAA,MACA,QAAQ,cAAc;AAAA,IACxB;AACA,SAAK,cAAc,SAAS;AAG5B,QAAI;AACF,YAAM,MAAM,MAAM,KAAK,uBAAuB,KAAK,KAAK,WAAW,cAAc,MAAM;AACvF,UAAI,CAAC,IAAI,IAAI;AAGX,cAAMC,QAAO,MAAM,IAAI,KAAK;AAC5B,cAAM,MAAM,cAAc;AAC1B,cAAM,UACJA,MAAK,SAAS,MAAM,GAAGA,MAAK,MAAM,GAAG,GAAG,CAAC,WAAMA,MAAK,MAAM,kBAAkBA;AAC9E,cAAM,IAAIF,WAAU;AAAA,UAClB,SAAS,QAAQ,IAAI,MAAM,KAAK,OAAO;AAAA,UACvC,MAAM;AAAA,UACN,UAAU;AAAA,UACV,SAAS,EAAE,WAAW,OAAO,KAAK,KAAK,KAAK,QAAQ,IAAI,OAAO;AAAA,QACjE,CAAC;AAAA,MACH;AAEA,UAAI;AACJ,UAAI;AACF,eAAO,MAAM,IAAI,KAAK;AAAA,MACxB,SAAS,KAAK;AACZ,cAAM,IAAIA,WAAU;AAAA,UAClB,SAAS,8BAA8B,eAAe,QAAQ,IAAI,UAAU,cAAc;AAAA,UAC1F,MAAM;AAAA,UACN,UAAU;AAAA,UACV,SAAS,EAAE,WAAW,OAAO,KAAK,KAAK,KAAK,OAAO,aAAa;AAAA,UAChE,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AACA,aAAO,4BAA4B,MAAM,IAAI,MAAM;AAAA,IACrD,SAAS,KAAK;AACZ,UAAI,UAAU,WAAW,CAAC,OAAO,WAAW,gBAAgB,GAAG;AAI7D,aAAK,KAAK,SAAS,2BAA2B;AAAA,UAC5C,WAAW;AAAA,UACX,QAAQ;AAAA,QACV,CAAC,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AACjB,cAAM,eAAe,MAAM;AAAA,MAC7B;AACA,YAAM;AAAA,IACR,UAAE;AACA,oBAAc,QAAQ;AAAA,IACxB;AAAA,EACF;AAAA,EAEA,MAAM,SACJ,MACA,OACA,MACyB;AACzB,QAAI,KAAK,UAAU,aAAa;AAC9B,YAAM,IAAIA,WAAU;AAAA,QAClB,SAAS,sCAAsC,KAAK,KAAK;AAAA,QACzD,MAAM;AAAA,QACN,UAAU;AAAA,QACV,SAAS,EAAE,WAAW,OAAO,OAAO,KAAK,MAAM;AAAA,MACjD,CAAC;AAAA,IACH;AACA,UAAM,MAAM,MAAM,KAAK,SAAS,cAAc,EAAE,MAAM,WAAW,MAAM,GAAG,IAAI;AAC9E,QAAI,IAAI,OAAO;AACb,aAAO,EAAE,SAAS,IAAI,MAAM,SAAS,SAAS,KAAK;AAAA,IACrD;AACA,UAAM,SAAS,IAAI;AAGnB,WAAO;AAAA,MACL,SAAS,QAAQ,WAAW;AAAA,MAC5B,SAAS,QAAQ,QAAQ,OAAO;AAAA,IAClC;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,QACJ,QACA,QACA,WACA,MAC0B;AAC1B,UAAM,KAAK,KAAK,MAAM;AACtB,UAAM,OAAO,KAAK,UAAU,EAAE,SAAS,OAAO,IAAI,QAAQ,OAAO,CAAC;AAElE,UAAM,WAAW,MAAM;AACvB,UAAM,SACJ,YAAY,KAAK,kBACb,YAAY,IAAI,CAAC,KAAK,gBAAgB,QAAQ,QAAQ,CAAC,IACtD,YAAY,KAAK,iBAAiB;AACzC,UAAM,gBAAgB,oBAAoB,QAAQ,aAAa,KAAK,cAAc;AAClF,UAAM,YAAyB;AAAA,MAC7B,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,GAAG,KAAK;AAAA,MACV;AAAA,MACA;AAAA,MACA,QAAQ,cAAc;AAAA,IACxB;AACA,SAAK,cAAc,SAAS;AAK5B,QAAI;AACF,YAAM,MAAM,MAAM,KAAK,uBAAuB,KAAK,KAAK,WAAW,cAAc,MAAM;AAEvF,UAAI,CAAC,IAAI,IAAI;AACX,cAAM,IAAIA,WAAU;AAAA,UAClB,SAAS,QAAQ,IAAI,MAAM,KAAK,IAAI,UAAU;AAAA,UAC9C,MAAM;AAAA,UACN,UAAU;AAAA,UACV,SAAS;AAAA,YACP,WAAW;AAAA,YACX,KAAK,KAAK;AAAA,YACV,QAAQ,IAAI;AAAA,YACZ,YAAY,IAAI;AAAA,UAClB;AAAA,QACF,CAAC;AAAA,MACH;AAEA,UAAI;AACJ,UAAI;AACF,eAAO,MAAM,IAAI,KAAK;AAAA,MACxB,SAAS,KAAK;AACZ,cAAM,IAAIA,WAAU;AAAA,UAClB,SAAS,8BAA8B,eAAe,QAAQ,IAAI,UAAU,cAAc;AAAA,UAC1F,MAAM;AAAA,UACN,UAAU;AAAA,UACV,SAAS,EAAE,WAAW,OAAO,KAAK,KAAK,KAAK,OAAO,aAAa;AAAA,UAChE,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AACA,YAAM,SAAS,4BAA4B,MAAM,IAAI,MAAM;AAC3D,aAAO,EAAE,SAAS,OAAO,IAAI,QAAQ,OAAO,QAAQ,OAAO,OAAO,MAAM;AAAA,IAC1E,SAAS,KAAK;AACZ,UAAI,UAAU,WAAW,CAAC,OAAO,WAAW,gBAAgB,GAAG;AAC7D,aAAK,KAAK,SAAS,2BAA2B;AAAA,UAC5C,WAAW;AAAA,UACX,QAAQ;AAAA,QACV,CAAC,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AACjB,cAAM,eAAe,MAAM;AAAA,MAC7B;AACA,YAAM;AAAA,IACR,UAAE;AACA,oBAAc,QAAQ;AAAA,IACxB;AAAA,EACF;AAAA,EAEA,MAAM,QAAuB;AAE3B,QAAI,KAAK,UAAU,eAAgB;AACnC,SAAK,aAAa;AAClB,SAAK,eAAe,MAAM;AAC1B,QAAI;AACF,WAAK,QAAQ,OAAO;AAAA,IACtB,QAAQ;AAAA,IAER;AACA,QAAI;AACF,WAAK,QAAQ,YAAY;AAAA,IAC3B,QAAQ;AAAA,IAER;AACA,SAAK,iBAAiB,MAAM;AAC5B,SAAK,mBAAmB,OAAO,GAAG,KAAK,mBAAmB,MAAM;AAChE,SAAK,QAAQ;AAAA,EACf;AACF;;;AC5WO,IAAM,0BAAN,cAAsC,kBAAkB;AAAA,EACrD,UAAU;AAAA,EACV;AAAA,EAER,YAAY,MAA4B;AACtC,UAAM,MAAM,gBAAgB;AAAA,EAC9B;AAAA,EAEmB,QAAgB;AACjC,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,oBAAoB,MAAc,WAA8C;AACtF,UAAM,YAAY,wBAAwB,IAAI;AAC9C,eAAW,YAAY,WAAW;AAChC,UAAI,YAAY,YAAY,SAAS,OAAO,QAAW;AACrD,aAAK,mBAAmB,SAAS,MAAM;AAAA,MACzC;AAAA,IACF;AACA,UAAM,YAAY,UAAU,OAAO,eAAe;AAClD,WACE,UAAU,KAAK,CAAC,aAAa,SAAS,OAAO,SAAS,KACtD,UAAU,KAAK,CAAC,aAAa,SAAS,OAAO,MAAS,KACtD,UAAU,CAAC;AAAA,EAEf;AAAA,EAEQ,mBAAmB,QAAsB;AAC/C,QAAI,WAAW,wCAAwC;AACrD,WAAK,uBAAuB;AAAA,IAC9B,WAAW,WAAW,sCAAsC;AAC1D,WAAK,qBAAqB;AAAA,IAC5B,WAAW,WAAW,oCAAoC;AACxD,WAAK,KAAK,aAAa;AAAA,IACzB;AAAA,EACF;AAAA,EAEA,MAAc,eAA8B;AAC1C,QAAI;AACF,YAAM,WAAW,MAAM,KAAK,QAAQ,cAAc,CAAC,CAAC;AACpD,UAAI,SAAS,MAAO;AACpB,YAAM,QAAQ;AAAA,QACX,SAAS,QAAwD;AAAA,MACpE;AACA,WAAK,MAAM,OAAO,GAAG,KAAK,MAAM,QAAQ,GAAG,KAAK;AAChD,iBAAW,YAAY,KAAK,uBAAuB;AACjD,YAAI;AACF,mBAAS,CAAC,GAAG,KAAK,CAAC;AAAA,QACrB,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEA,MAAM,UAAyB;AAC7B,SAAK,QAAQ;AACb,SAAK,iBAAiB;AACtB,SAAK,kBAAkB,IAAI,gBAAgB;AAC3C,UAAM,SAAS,KAAK,gBAAgB;AACpC,UAAM,eAAe,WAAW,MAAM,KAAK,iBAAiB,MAAM,GAAG,KAAK,OAAO;AAEjF,QAAI;AACF,YAAM,gBAA6B;AAAA,QACjC,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,QAAQ;AAAA,UACR,GAAG,KAAK;AAAA,QACV;AAAA,QACA,MAAM,KAAK,UAAU;AAAA,UACnB,SAAS;AAAA,UACT,IAAI,KAAK,MAAM;AAAA,UACf,QAAQ;AAAA,UACR,QAAQ;AAAA,YACN,iBAAiB,cAAc;AAAA,YAC/B,cAAc,EAAE,OAAO,CAAC,EAAE;AAAA,YAC1B,YAAY,cAAc;AAAA,UAC5B;AAAA,QACF,CAAC;AAAA,QACD;AAAA,MACF;AACA,WAAK,cAAc,aAAa;AAChC,YAAM,UAAU,MAAM,KAAK,uBAAuB,KAAK,KAAK,eAAe,MAAM;AAEjF,UAAI,CAAC,QAAQ,IAAI;AACf,cAAM,IAAI,MAAM,mBAAmB,QAAQ,MAAM,KAAK,QAAQ,UAAU,EAAE;AAAA,MAC5E;AAEA,YAAM,cAAc,QAAQ,QAAQ,IAAI,cAAc,KAAK;AAC3D,UAAI;AAEJ,UAAI,YAAY,SAAS,kBAAkB,GAAG;AAC5C,cAAM,SAAS,MAAM,QAAQ,KAAK;AAClC,YAAI,gBAAgB,MAAM,EAAG,QAAO;AAAA,MACtC,OAAO;AAEL,eAAO,sBAAsB,MAAM,QAAQ,KAAK,CAAC,EAAE,CAAC;AAAA,MACtD;AAEA,UAAI,CAAC,MAAM;AACT,cAAM,IAAI,MAAM,qCAAqC;AAAA,MACvD;AACA,aAAO,4BAA4B,MAAM,KAAK,UAAU,GAAG,YAAY;AAEvE,UAAI,KAAK,OAAO;AACd,cAAM,IAAI,MAAM,sBAAsB,KAAK,MAAM,OAAO,EAAE;AAAA,MAC5D;AACA,WAAK,iBAAiB,oBAAoB,KAAK,MAAM;AACrD,WAAK,kBAAkB,KAAK,eAAe;AAK3C,WAAK,YAAY,QAAQ,QAAQ,IAAI,gBAAgB,KAAK;AAC1D,YAAM,KAAK,QAAQ,6BAA6B,CAAC,CAAC;AAElD,YAAM,WAAW,MAAM,KAAK,QAAQ,cAAc,CAAC,CAAC;AACpD,UAAI,SAAS,OAAO;AAClB,aAAK,MAAM,OAAO,GAAG,KAAK,MAAM,MAAM;AAAA,MACxC,OAAO;AACL,cAAM,SAAS,SAAS;AACxB,aAAK,MAAM,OAAO,GAAG,KAAK,MAAM,QAAQ,GAAG,kBAAkB,QAAQ,KAAK,CAAC;AAAA,MAC7E;AAEA,WAAK,QAAQ;AACb,mBAAa,YAAY;AAAA,IAC3B,SAAS,KAAK;AACZ,mBAAa,YAAY;AACzB,WAAK,QAAQ;AACb,WAAK,gBAAgB,MAAM;AAC3B,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAc,QACZ,QACA,QACA,MACwB;AACxB,UAAM,KAAK,KAAK,MAAM;AACtB,UAAM,OAAO,KAAK,UAAU,EAAE,SAAS,OAAO,IAAI,QAAQ,OAAO,CAAC;AAElE,UAAM,WAAW,MAAM;AACvB,UAAM,SACJ,YAAY,KAAK,kBACb,YAAY,IAAI,CAAC,KAAK,gBAAgB,QAAQ,QAAQ,CAAC,IACtD,YAAY,KAAK,iBAAiB;AACzC,UAAM,gBAAgB,oBAAoB,QAAQ,KAAK,cAAc;AACrE,UAAM,YAAyB;AAAA,MAC7B,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,QAAQ;AAAA,QACR,GAAI,KAAK,YAAY,EAAE,kBAAkB,KAAK,UAAU,IAAI,CAAC;AAAA,QAC7D,GAAG,KAAK;AAAA,MACV;AAAA,MACA;AAAA,MACA,QAAQ,cAAc;AAAA,IACxB;AACA,SAAK,cAAc,SAAS;AAG5B,QAAI;AACF,YAAM,MAAM,MAAM,KAAK,uBAAuB,KAAK,KAAK,WAAW,cAAc,MAAM;AACvF,UAAI,CAAC,IAAI,IAAI;AACX,cAAM,IAAI,MAAM,QAAQ,IAAI,MAAM,KAAK,IAAI,UAAU,EAAE;AAAA,MACzD;AAGA,UAAI,OAAO,WAAW,gBAAgB,GAAG;AACvC,cAAM,IAAI,KAAK,EAAE,MAAM,MAAM,MAAS;AACtC,eAAO,EAAE,SAAS,MAAM;AAAA,MAC1B;AAEA,YAAM,QAAQ,KAAK,oBAAoB,MAAM,IAAI,KAAK,GAAG,EAAE;AAC3D,UAAI,OAAO;AACT,eAAO,4BAA4B,OAAO,IAAI,MAAM;AAAA,MACtD;AACA,YAAM,IAAI,MAAM,sCAAsC;AAAA,IACxD,SAAS,KAAK;AACZ,UAAI,UAAU,WAAW,CAAC,OAAO,WAAW,gBAAgB,GAAG;AAG7D,aAAK,KAAK,QAAQ,2BAA2B;AAAA,UAC3C,WAAW;AAAA,UACX,QAAQ;AAAA,QACV,CAAC,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AACjB,cAAM,eAAe,MAAM;AAAA,MAC7B;AACA,YAAM;AAAA,IACR,UAAE;AACA,oBAAc,QAAQ;AAAA,IACxB;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,QACJ,QACA,QACA,WACA,MAC0B;AAC1B,UAAM,KAAK,KAAK,MAAM;AACtB,UAAM,OAAO,KAAK,UAAU,EAAE,SAAS,OAAO,IAAI,QAAQ,OAAO,CAAC;AAElE,UAAM,WAAW,MAAM;AACvB,UAAM,SACJ,YAAY,KAAK,kBACb,YAAY,IAAI,CAAC,KAAK,gBAAgB,QAAQ,QAAQ,CAAC,IACtD,YAAY,KAAK,iBAAiB;AACzC,UAAM,gBAAgB,oBAAoB,QAAQ,aAAa,KAAK,cAAc;AAClF,UAAM,YAAyB;AAAA,MAC7B,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,QAAQ;AAAA,QACR,GAAI,KAAK,YAAY,EAAE,kBAAkB,KAAK,UAAU,IAAI,CAAC;AAAA,QAC7D,GAAG,KAAK;AAAA,MACV;AAAA,MACA;AAAA,MACA,QAAQ,cAAc;AAAA,IACxB;AACA,SAAK,cAAc,SAAS;AAC5B,QAAI;AACF,YAAM,MAAM,MAAM,KAAK,uBAAuB,KAAK,KAAK,WAAW,cAAc,MAAM;AACvF,UAAI,CAAC,IAAI,IAAI;AACX,cAAM,IAAI,MAAM,QAAQ,IAAI,MAAM,KAAK,IAAI,UAAU,EAAE;AAAA,MACzD;AAEA,UAAI,OAAO,WAAW,gBAAgB,GAAG;AACvC,cAAM,IAAI,KAAK,EAAE,MAAM,MAAM,MAAS;AACtC,eAAO,EAAE,SAAS,OAAO,GAAG;AAAA,MAC9B;AAEA,YAAM,SAAS,KAAK,oBAAoB,MAAM,IAAI,KAAK,GAAG,EAAE;AAC5D,UAAI,QAAQ;AAEV,eAAO;AAAA,UACL,SAAS;AAAA,UACT;AAAA,UACA,QAAQ,OAAO;AAAA,UACf,OAAO,OAAO;AAAA,QAChB;AAAA,MACF;AACA,YAAM,IAAI,MAAM,sCAAsC;AAAA,IACxD,SAAS,KAAK;AACZ,UAAI,UAAU,WAAW,CAAC,OAAO,WAAW,gBAAgB,GAAG;AAC7D,aAAK,KAAK,QAAQ,2BAA2B;AAAA,UAC3C,WAAW;AAAA,UACX,QAAQ;AAAA,QACV,CAAC,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AACjB,cAAM,eAAe,MAAM;AAAA,MAC7B;AACA,YAAM;AAAA,IACR,UAAE;AACA,oBAAc,QAAQ;AAAA,IACxB;AAAA,EACF;AAAA,EAEA,MAAM,SACJ,MACA,OACA,MACyB;AACzB,QAAI,KAAK,UAAU,aAAa;AAC9B,YAAM,IAAI,MAAM,kDAAkD,KAAK,KAAK,GAAG;AAAA,IACjF;AACA,UAAM,MAAM,MAAM,KAAK,QAAQ,cAAc,EAAE,MAAM,WAAW,MAAM,GAAG,IAAI;AAC7E,QAAI,IAAI,OAAO;AACb,aAAO,EAAE,SAAS,IAAI,MAAM,SAAS,SAAS,KAAK;AAAA,IACrD;AACA,UAAM,SAAS,IAAI;AAGnB,WAAO;AAAA,MACL,SAAS,QAAQ,WAAW;AAAA,MAC5B,SAAS,QAAQ,QAAQ,OAAO;AAAA,IAClC;AAAA,EACF;AAAA,EAEA,MAAM,QAAuB;AAC3B,QAAI,KAAK,UAAU,eAAgB;AACnC,SAAK,QAAQ;AACb,SAAK,iBAAiB,MAAM;AAG5B,SAAK,mBAAmB,OAAO,GAAG,KAAK,mBAAmB,MAAM;AAAA,EAClE;AACF;;;AT9NA,SAAS,kBAAkB,OAA0C;AACnE,MAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AACxD,QAAM,WAAW;AACjB,MAAI,SAAS,SAAS,MAAM,SAAS,OAAO,SAAS,IAAI,MAAM,SAAU,QAAO;AAChF,MAAI,OAAO,OAAO,UAAU,QAAQ,EAAG,QAAO;AAE9C,QAAM,YAAY,OAAO,OAAO,UAAU,QAAQ;AAClD,QAAM,WAAW,OAAO,OAAO,UAAU,OAAO;AAChD,MAAI,cAAc,SAAU,QAAO;AACnC,MAAI,CAAC,SAAU,QAAO;AAEtB,QAAM,QAAQ,SAAS,OAAO;AAC9B,SACE,OAAO,UAAU,YACjB,UAAU,QACV,OAAQ,MAAkC,MAAM,MAAM,YACtD,OAAQ,MAAkC,SAAS,MAAM;AAE7D;AAiBO,IAAM,YAAN,MAAM,WAAU;AAAA,EA2CrB,YAA4B,MAAwB;AAAxB;AAAA,EAAyB;AAAA,EAAzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAlC5B,OAAwB,sBAAsB,KAAK,OAAO;AAAA,EAElD,QAAyB;AAAA,EACzB;AAAA,EACA,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,UAAU,oBAAI,IAG7B;AAAA,EACM,WAAW;AAAA,EACX,SAAoB,CAAC;AAAA;AAAA,EAErB;AAAA;AAAA,EAEA;AAAA,EACA,gBAAgB;AAAA,EAChB,qBAAqB;AAAA;AAAA,EAErB;AAAA,EACA;AAAA;AAAA,EAES,gBAAgB,oBAAI,IAAkB;AAAA;AAAA,EAEtC,wBAAwB,oBAAI,IAA0B;AAAA,EACtD,4BAA4B,oBAAI,IAA4B;AAAA,EAC5D,0BAA0B,oBAAI,IAA4B;AAAA;AAAA,EAE1D,sBAAsB,oBAAI,IAAgB;AAAA,EAI3D,WAA4B;AAC1B,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,oBAAmD;AACjD,UAAM,WAAW,KAAK;AACtB,QAAI,CAAC,SAAU,QAAO;AACtB,WAAO;AAAA,MACL,GAAG;AAAA,MACH,cAAc,EAAE,GAAG,SAAS,aAAa;AAAA,MACzC,YAAY,EAAE,GAAG,SAAS,WAAW;AAAA,IACvC;AAAA,EACF;AAAA,EAEA,YAAuB;AACrB,WAAO,KAAK,OAAO,SAAS,IACxB,CAAC,GAAG,KAAK,MAAM,IACf,KAAK,cACH,CAAC,GAAG,KAAK,WAAW,IACpB,CAAC;AAAA,EACT;AAAA;AAAA,EAGA,mBAA4B;AAC1B,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,gBAAgB,UAA8B;AAC5C,SAAK,cAAc,IAAI,QAAQ;AAAA,EACjC;AAAA,EAEA,mBAAmB,UAA8B;AAC/C,SAAK,cAAc,OAAO,QAAQ;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,sBAAsB,UAA4B;AAChD,SAAK,oBAAoB,IAAI,QAAQ;AAAA,EACvC;AAAA,EAEA,yBAAyB,UAA4B;AACnD,SAAK,oBAAoB,OAAO,QAAQ;AAAA,EAC1C;AAAA,EAEA,MAAM,UAAyB;AAC7B,SAAK,QAAQ;AACb,SAAK,kBAAkB;AAEvB,QAAI,KAAK,KAAK,cAAc,SAAS;AACnC,YAAM,KAAK,aAAa;AAAA,IAC1B,WAAW,KAAK,KAAK,cAAc,OAAO;AACxC,YAAM,KAAK,WAAW;AAAA,IACxB,WAAW,KAAK,KAAK,cAAc,mBAAmB;AACpD,YAAM,KAAK,sBAAsB;AAAA,IACnC,OAAO;AACL,WAAK,QAAQ;AACb,YAAM,IAAI,MAAM,sBAAsB,KAAK,KAAK,SAAS,GAAG;AAAA,IAC9D;AAAA,EACF;AAAA,EAEA,MAAc,eAA8B;AAC1C,QAAI,CAAC,KAAK,KAAK,SAAS;AACtB,WAAK,QAAQ;AACb,YAAM,IAAI,MAAM,wCAAwC;AAAA,IAC1D;AAMA,SAAK,WAAW;AAehB,UAAM,WAAmC,EAAE,GAAG,KAAK,KAAK,IAAI;AAC5D,QAAI,KAAK,KAAK,gBAAgB;AAC5B,iBAAW,QAAQ,KAAK,KAAK,gBAAgB;AAC3C,cAAM,MAAM,QAAQ,IAAI,IAAI;AAC5B,YAAI,QAAQ,QAAW;AACrB,mBAAS,IAAI,IAAI;AAAA,QACnB;AAAA,MACF;AAAA,IACF;AACA,UAAM,QAAQ,QAAQ,aAAa;AACnC,UAAM,UAAU,KAAK,KAAK,QAAQ,CAAC;AACnC,UAAM,WAAW,cAAc,EAAE,OAAO,SAAS,CAAC;AAClD,UAAM,QAAkC,CAAC,QAAQ,QAAQ,MAAM;AAC/D,UAAM,QAAQ,QACV,MAAM,CAAC,KAAK,KAAK,SAAS,GAAG,OAAO,EAAE,IAAI,eAAe,EAAE,KAAK,GAAG,GAAG;AAAA,MACpE,KAAK;AAAA,MACL;AAAA,MACA,OAAO;AAAA;AAAA;AAAA,MAGP,aAAa;AAAA,IACf,CAAC,IACD,MAAM,KAAK,KAAK,SAAS,SAAS,EAAE,KAAK,UAAU,OAAO,aAAa,KAAK,CAAC;AACjF,SAAK,QAAQ;AAEb,UAAM,QAAQ,GAAG,QAAQ,CAAC,UAAkB,KAAK,OAAO,MAAM,SAAS,CAAC,CAAC;AACzE,UAAM,QAAQ,GAAG,QAAQ,MAAM;AAAA,IAE/B,CAAC;AACD,UAAM,OAAO,GAAG,SAAS,CAAC,QAAe;AAKvC,WAAK,YAAY,QAAQ,KAAK,KAAK,IAAI,kBAAkB,eAAe,GAAG,CAAC,EAAE;AAAA,IAChF,CAAC;AACD,UAAM,GAAG,QAAQ,CAAC,MAAM,WAAW;AACjC,WAAK,QAAQ;AAIb,WAAK;AAAA,QACH,QAAQ,KAAK,KAAK,IAAI,wBAAwB,QAAQ,MAAM,WAAW,UAAU,MAAM;AAAA,MACzF;AACA,iBAAW,YAAY,KAAK,eAAe;AACzC,YAAI;AACF,mBAAS,KAAK,KAAK,MAAM,MAAM,MAAM;AAAA,QACvC,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF,CAAC;AACD,UAAM,GAAG,SAAS,CAAC,QAAe;AAChC,WAAK,QAAQ;AAMb,WAAK,YAAY,QAAQ,KAAK,KAAK,IAAI,kBAAkB,eAAe,GAAG,CAAC,EAAE;AAAA,IAChF,CAAC;AAED,UAAM,aAAa,MAAM,KAAK;AAAA,MAC5B;AAAA,MACA;AAAA,QACE,iBAAiB,cAAc;AAAA,QAC/B,cAAc,EAAE,OAAO,CAAC,EAAE;AAAA,QAC1B,YAAY,cAAc;AAAA,MAC5B;AAAA,MACA,KAAK,KAAK,oBAAoB;AAAA,IAChC;AACA,QAAI,WAAW,OAAO;AACpB,WAAK,QAAQ;AACb,YAAM,IAAI,MAAM,0BAA0B,WAAW,MAAM,OAAO,EAAE;AAAA,IACtE;AACA,QAAI;AACF,WAAK,kBAAkB,oBAAoB,WAAW,MAAM;AAAA,IAC9D,SAAS,KAAK;AACZ,WAAK,QAAQ;AACb,YAAM,IAAI,MAAM,sDAAsD,eAAe,GAAG,CAAC,EAAE;AAAA,IAC7F;AACA,QAAI;AACF,YAAM,KAAK,OAAO,6BAA6B,CAAC,CAAC;AAAA,IACnD,SAAS,KAAK;AACZ,cAAQ;AAAA,QACN,2DACE,KAAK,KAAK,OACV,QACA,eAAe,GAAG;AAAA,MACtB;AAAA,IACF;AACA,UAAM,WAAW,MAAM,KAAK,QAAQ,cAAc,CAAC,CAAC;AACpD,QAAI,SAAS,OAAO;AAClB,WAAK,SAAS,CAAC;AAAA,IACjB,OAAO;AACL,YAAM,SAAS,SAAS;AACxB,WAAK,SAAS,kBAAkB,QAAQ,KAAK;AAAA,IAC/C;AAEA,SAAK,cAAc,KAAK;AACxB,SAAK,QAAQ;AAAA,EACf;AAAA,EAEA,MAAc,aAA4B;AACxC,QAAI,CAAC,KAAK,KAAK,KAAK;AAClB,WAAK,QAAQ;AACb,YAAM,IAAI,MAAM,kCAAkC;AAAA,IACpD;AACA,UAAM,WAAiC;AAAA,MACrC,MAAM,KAAK,KAAK;AAAA,MAChB,KAAK,KAAK,KAAK;AAAA,MACf,SAAS,KAAK,KAAK;AAAA,MACnB,kBAAkB,KAAK,KAAK;AAAA,MAC5B,kBAAkB,KAAK,KAAK;AAAA,MAC5B,uBAAuB,KAAK,KAAK;AAAA,IACnC;AACA,SAAK,eAAe,IAAI,aAAa,QAAQ;AAC7C,SAAK,aAAa,aAAa,MAAM;AACnC,WAAK,QAAQ;AACb,iBAAW,MAAM,KAAK,qBAAqB;AACzC,YAAI;AACF,aAAG;AAAA,QACL,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF,CAAC;AACD,SAAK,aAAa,eAAe,CAAC,UAAU;AAC1C,WAAK,SAAS;AAKd,WAAK,cAAc;AACnB,iBAAW,MAAM,KAAK,uBAAuB;AAC3C,YAAI;AACF,aAAG,KAAK,KAAK,MAAM,KAAK;AAAA,QAC1B,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF,CAAC;AACD,SAAK,aAAa,mBAAmB,MAAM,KAAK,sBAAsB,WAAW,CAAC;AAClF,SAAK,aAAa,iBAAiB,MAAM,KAAK,sBAAsB,SAAS,CAAC;AAC9E,QAAI;AACF,YAAM,KAAK,aAAa,QAAQ;AAAA,IAClC,SAAS,KAAK;AAOZ,YAAM,IAAI,KAAK;AACf,WAAK,eAAe;AACpB,YAAM,EAAE,MAAM,EAAE,MAAM,MAAM;AAAA,MAE5B,CAAC;AACD,WAAK,QAAQ;AACb,YAAM;AAAA,IACR;AACA,SAAK,SAAS,KAAK,aAAa,UAAU;AAC1C,SAAK,cAAc,KAAK;AACxB,SAAK,kBAAkB,KAAK,aAAa,kBAAkB;AAC3D,SAAK,QAAQ;AAAA,EACf;AAAA,EAEA,MAAc,wBAAuC;AACnD,QAAI,CAAC,KAAK,KAAK,KAAK;AAClB,WAAK,QAAQ;AACb,YAAM,IAAI,MAAM,8CAA8C;AAAA,IAChE;AACA,UAAM,WAAiC;AAAA,MACrC,MAAM,KAAK,KAAK;AAAA,MAChB,KAAK,KAAK,KAAK;AAAA,MACf,SAAS,KAAK,KAAK;AAAA,MACnB,kBAAkB,KAAK,KAAK;AAAA,MAC5B,kBAAkB,KAAK,KAAK;AAAA,MAC5B,uBAAuB,KAAK,KAAK;AAAA,IACnC;AACA,SAAK,gBAAgB,IAAI,wBAAwB,QAAQ;AACzD,SAAK,cAAc,aAAa,MAAM;AACpC,WAAK,QAAQ;AACb,iBAAW,MAAM,KAAK,qBAAqB;AACzC,YAAI;AACF,aAAG;AAAA,QACL,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF,CAAC;AACD,SAAK,cAAc,eAAe,CAAC,UAAU;AAC3C,WAAK,SAAS;AAKd,WAAK,cAAc;AACnB,iBAAW,MAAM,KAAK,uBAAuB;AAC3C,YAAI;AACF,aAAG,KAAK,KAAK,MAAM,KAAK;AAAA,QAC1B,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF,CAAC;AACD,SAAK,cAAc,mBAAmB,MAAM,KAAK,sBAAsB,WAAW,CAAC;AACnF,SAAK,cAAc,iBAAiB,MAAM,KAAK,sBAAsB,SAAS,CAAC;AAC/E,QAAI;AACF,YAAM,KAAK,cAAc,QAAQ;AAAA,IACnC,SAAS,KAAK;AAIZ,YAAM,IAAI,KAAK;AACf,WAAK,gBAAgB;AACrB,YAAM,EAAE,MAAM,EAAE,MAAM,MAAM;AAAA,MAE5B,CAAC;AACD,WAAK,QAAQ;AACb,YAAM;AAAA,IACR;AACA,SAAK,SAAS,KAAK,cAAc,UAAU;AAC3C,SAAK,cAAc,KAAK;AACxB,SAAK,kBAAkB,KAAK,cAAc,kBAAkB;AAC5D,SAAK,QAAQ;AAAA,EACf;AAAA,EAEA,MAAM,SACJ,MACA,OACA,MACyB;AACzB,QAAI,KAAK,UAAU,aAAa;AAC9B,YAAM,IAAI,MAAM,eAAe,KAAK,KAAK,IAAI,0BAA0B,KAAK,KAAK,GAAG;AAAA,IACtF;AAEA,QAAI,KAAK,cAAc;AACrB,aAAO,KAAK,aAAa,SAAS,MAAM,OAAO,IAAI;AAAA,IACrD;AACA,QAAI,KAAK,eAAe;AACtB,aAAO,KAAK,cAAc,SAAS,MAAM,OAAO,IAAI;AAAA,IACtD;AAEA,UAAM,MAAM,MAAM,KAAK,QAAQ,cAAc,EAAE,MAAM,WAAW,MAAM,GAAG,QAAW,IAAI;AACxF,QAAI,IAAI,OAAO;AACb,aAAO,EAAE,SAAS,IAAI,MAAM,SAAS,SAAS,KAAK;AAAA,IACrD;AACA,UAAM,SAAS,IAAI;AAGnB,WAAO;AAAA,MACL,SAAS,QAAQ,WAAW;AAAA,MAC5B,SAAS,QAAQ,QAAQ,OAAO;AAAA,IAClC;AAAA,EACF;AAAA,EAEA,MAAM,cAAc,OAAuB,CAAC,GAAoC;AAC9E,UAAM,SAAS,WAAW,KAAK,QAAQ,uBAAuB;AAC9D,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,sBAAsB,OAAuB,CAAC,GAA4C;AAC9F,UAAM,SAAS,WAAW,KAAK,QAAQ,iCAAiC;AACxE,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,aAAa,KAAa,OAA0B,CAAC,GAAmC;AAC5F,2BAAuB,KAAK,cAAc;AAC1C,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,MACA,EAAE,IAAI;AAAA,MACN;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,kBAAkB,KAAa,OAA0B,CAAC,GAAkB;AAChF,2BAAuB,KAAK,cAAc;AAC1C,SAAK,6BAA6B,qBAAqB;AACvD,UAAM,KAAK;AAAA,MACT;AAAA,MACA;AAAA,MACA,EAAE,IAAI;AAAA,MACN;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,oBAAoB,KAAa,OAA0B,CAAC,GAAkB;AAClF,2BAAuB,KAAK,cAAc;AAC1C,SAAK,6BAA6B,uBAAuB;AACzD,UAAM,KAAK;AAAA,MACT;AAAA,MACA;AAAA,MACA,EAAE,IAAI;AAAA,MACN;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,YAAY,OAAuB,CAAC,GAAkC;AAC1E,UAAM,SAAS,WAAW,KAAK,QAAQ,qBAAqB;AAC5D,WAAO,KAAK,kBAAkB,WAAW,gBAAgB,QAAQ,wBAAwB,IAAI;AAAA,EAC/F;AAAA,EAEA,MAAM,UACJ,MACA,MACA,OAA0B,CAAC,GACE;AAC7B,2BAAuB,MAAM,aAAa;AAC1C,QAAI,QAAQ,OAAO,KAAK,IAAI,EAAE,SAAS,IAAI;AACzC,YAAM,IAAI,MAAM,6CAA6C;AAAA,IAC/D;AACA,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,QAAQ,CAAC,CAAC,GAAG;AACrD,6BAAuB,KAAK,sBAAsB;AAClD,6BAAuB,OAAO,oBAAoB,GAAG,KAAK,IAAI;AAAA,IAChE;AACA,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,MACA,SAAS,SAAY,EAAE,KAAK,IAAI,EAAE,MAAM,WAAW,KAAK;AAAA,MACxD;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,QAAuB;AAC3B,QAAI,KAAK,OAAO;AACd,YAAM,QAAQ,KAAK;AAMnB,YAAM,cAAc,IAAI,QAAc,CAAC,YAAY;AACjD,cAAM,KAAK,QAAQ,MAAM,QAAQ,CAAC;AAClC,YAAI,MAAM,aAAa,QAAQ,MAAM,eAAe,KAAM,SAAQ;AAAA,MACpE,CAAC;AACD,UAAI;AAEF,cAAM,KAAK;AAAA,MACb,QAAQ;AAAA,MAER;AAIA,YAAM,cAAc;AACpB,YAAM,mBAAmB;AACzB,YAAM,eAAe,MAAM,QAAQ,KAAK;AAAA,QACtC,YAAY,KAAK,MAAM,QAAiB;AAAA,QACxC,IAAI,QAAmB,CAAC,YAAY,WAAW,MAAM,QAAQ,SAAS,GAAG,WAAW,CAAC;AAAA,MACvF,CAAC;AACD,UAAI,iBAAiB,WAAW;AAC9B,YAAI;AAKF,gBAAM,KAAK,SAAS;AAAA,QACtB,QAAQ;AAAA,QAER;AACA,cAAM,QAAQ,KAAK;AAAA,UACjB;AAAA,UACA,IAAI,QAAc,CAAC,YAAY,WAAW,SAAS,gBAAgB,CAAC;AAAA,QACtE,CAAC;AAAA,MACH;AAAA,IACF;AAQA,SAAK,YAAY,QAAQ,KAAK,KAAK,IAAI,UAAU;AACjD,SAAK,cAAc,MAAM;AACzB,SAAK,eAAe,MAAM;AAC1B,SAAK,QAAQ;AAAA,EACf;AAAA,EAEQ,QACN,QACA,QACA,YAAY,KAAK,KAAK,oBAAoB,KAC1C,MAC0B;AAI1B,QAAI,KAAK,aAAc,QAAO,KAAK,aAAa,QAAQ,QAAQ,QAAQ,WAAW,IAAI;AACvF,QAAI,KAAK,cAAe,QAAO,KAAK,cAAc,QAAQ,QAAQ,QAAQ,WAAW,IAAI;AAGzF,UAAM,SAAS,MAAM;AACrB,QAAI,QAAQ,SAAS;AACnB,YAAM,MAAM,IAAI,MAAM,QAAQ,KAAK,KAAK,IAAI,cAAc,MAAM,uBAAuB;AACvF,UAAI,OAAO;AACX,aAAO,QAAQ,OAAO,GAAG;AAAA,IAC3B;AACA,UAAM,KAAK,KAAK;AAChB,UAAM,MAAsB,EAAE,SAAS,OAAO,IAAI,QAAQ,OAAO;AACjE,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAKtC,YAAM,UAAU,SACZ,MAAM;AACJ,cAAM,UAAU,KAAK,QAAQ,IAAI,EAAE;AACnC,aAAK,QAAQ,OAAO,EAAE;AACtB,YAAI,QAAS,cAAa,QAAQ,KAAK;AACvC,aAAK,KAAK,OAAO,2BAA2B;AAAA,UAC1C,WAAW;AAAA,UACX,QAAQ;AAAA,QACV,CAAC,EAAE,MAAM,MAAM;AAAA,QAEf,CAAC;AACD,cAAM,MAAM,IAAI,MAAM,QAAQ,KAAK,KAAK,IAAI,cAAc,MAAM,qBAAqB;AACrF,YAAI,OAAO;AACX,eAAO,GAAG;AAAA,MACZ,IACA;AACJ,UAAI,UAAU,QAAS,QAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;AAC/E,YAAM,SAAS,MAAM;AACnB,YAAI,UAAU,QAAS,QAAO,oBAAoB,SAAS,OAAO;AAAA,MACpE;AACA,YAAM,QAAQ,WAAW,MAAM;AAC7B,aAAK,QAAQ,OAAO,EAAE;AACtB,eAAO;AACP;AAAA,UACE,IAAI,MAAM,QAAQ,KAAK,KAAK,IAAI,cAAc,MAAM,qBAAqB,SAAS,IAAI;AAAA,QACxF;AAAA,MACF,GAAG,SAAS;AACZ,WAAK,QAAQ,IAAI,IAAI;AAAA,QACnB,SAAS,CAAC,QAAQ;AAChB,uBAAa,KAAK;AAClB,iBAAO;AACP,kBAAQ,GAAG;AAAA,QACb;AAAA,QACA,QAAQ,CAAC,QAAQ;AACf,uBAAa,KAAK;AAClB,iBAAO;AACP,iBAAO,GAAG;AAAA,QACZ;AAAA,QACA;AAAA,MACF,CAAC;AACD,YAAM,QAAQ,KAAK,OAAO;AAC1B,UAAI,CAAC,SAAS,MAAM,WAAW;AAI7B,cAAM,UAAU,KAAK,QAAQ,IAAI,EAAE;AACnC,aAAK,QAAQ,OAAO,EAAE;AACtB,YAAI,QAAS,cAAa,QAAQ,KAAK;AACvC,eAAO;AACP,eAAO,IAAI,MAAM,QAAQ,KAAK,KAAK,IAAI,cAAc,MAAM,uBAAuB,CAAC;AACnF;AAAA,MACF;AACA,UAAI;AACF,cAAM,MAAM,KAAK,UAAU,GAAG,IAAI,IAAI;AAAA,MACxC,SAAS,KAAK;AACZ,cAAM,UAAU,KAAK,QAAQ,IAAI,EAAE;AACnC,aAAK,QAAQ,OAAO,EAAE;AACtB,YAAI,QAAS,cAAa,QAAQ,KAAK;AACvC,eAAO;AACP,eAAO,GAAG;AAAA,MACZ;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAc,kBACZ,YACA,QACA,QACA,OACA,MACY;AACZ,QAAI,KAAK,UAAU,aAAa;AAC9B,YAAM,IAAI,MAAM,eAAe,KAAK,KAAK,IAAI,0BAA0B,KAAK,KAAK,GAAG;AAAA,IACtF;AACA,UAAM,WAAW,KAAK;AACtB,QAAI,CAAC,UAAU;AACb,YAAM,IAAI;AAAA,QACR,eAAe,KAAK,KAAK,IAAI,4CAA4C,MAAM;AAAA,MACjF;AAAA,IACF;AACA,QAAI,CAAC,SAAS,aAAa,UAAU,GAAG;AACtC,YAAM,IAAI;AAAA,QACR,eAAe,KAAK,KAAK,IAAI,4BAA4B,UAAU;AAAA,MACrE;AAAA,IACF;AACA,UAAM,WAAW,MAAM,KAAK,QAAQ,QAAQ,QAAQ,QAAW,IAAI;AACnE,QAAI,SAAS,OAAO;AAClB,YAAM,IAAI,MAAM,OAAO,MAAM,YAAY,SAAS,MAAM,OAAO,EAAE;AAAA,IACnE;AACA,WAAO,MAAM,SAAS,MAAM;AAAA,EAC9B;AAAA,EAEQ,6BAA6B,QAAsB;AACzD,QAAI,KAAK,UAAU,aAAa;AAC9B,YAAM,IAAI,MAAM,eAAe,KAAK,KAAK,IAAI,0BAA0B,KAAK,KAAK,GAAG;AAAA,IACtF;AACA,QAAI,KAAK,iBAAiB,aAAa,WAAW,cAAc,MAAM;AACpE,YAAM,IAAI;AAAA,QACR,eAAe,KAAK,KAAK,IAAI,mDAAmD,MAAM;AAAA,MACxF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,YAAY,QAAsB;AACxC,QAAI,KAAK,QAAQ,SAAS,EAAG;AAC7B,UAAM,MAAM,IAAI,MAAM,MAAM;AAC5B,eAAW,CAAC,EAAE,KAAK,KAAK,KAAK,SAAS;AACpC,UAAI;AACF,qBAAa,MAAM,KAAK;AACxB,cAAM,OAAO,GAAG;AAAA,MAClB,QAAQ;AAAA,MAER;AAAA,IACF;AACA,SAAK,QAAQ,MAAM;AAAA,EACrB;AAAA,EAEA,MAAc,OAAO,QAAgB,QAAgC;AACnE,UAAM,MAAM,EAAE,SAAS,OAAO,QAAQ,OAAO;AAC7C,UAAM,UAAU,KAAK,UAAU,GAAG,IAAI;AACtC,QAAI;AACF,YAAM,KAAK,KAAK,OAAO,OAAO,MAAM,OAAO;AAC3C,UAAI,CAAC,IAAI;AAIP,YAAI,KAAK,eAAe;AACtB,eAAK,qBAAqB;AAC1B,kBAAQ;AAAA,YACN,KAAK,UAAU;AAAA,cACb,OAAO;AAAA,cACP,OAAO;AAAA,cACP,QAAQ,KAAK,KAAK;AAAA,cAClB;AAAA,cACA,SAAS;AAAA,cACT,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,YACpC,CAAC;AAAA,UACH;AACA;AAAA,QACF;AACA,aAAK,gBAAgB;AACrB,cAAM,IAAI,QAAc,CAAC,SAAS,WAAW;AAC3C,gBAAM,UAAU,WAAW,MAAM;AAC/B,iBAAK,OAAO,OAAO,iBAAiB,SAAS,OAAO;AACpD,iBAAK,OAAO,OAAO,iBAAiB,SAAS,OAAO;AACpD,iBAAK,gBAAgB;AACrB,mBAAO,IAAI,MAAM,eAAe,MAAM,kBAAkB,CAAC;AAAA,UAC3D,GAAG,GAAG;AACN,gBAAM,UAAU,MAAM;AACpB,yBAAa,OAAO;AACpB,iBAAK,OAAO,OAAO,iBAAiB,SAAS,OAAO;AACpD,iBAAK,OAAO,OAAO,iBAAiB,SAAS,OAAO;AACpD,iBAAK,gBAAgB;AACrB,oBAAQ;AAAA,UACV;AACA,gBAAM,UAAU,CAAC,QAAe;AAC9B,yBAAa,OAAO;AACpB,iBAAK,OAAO,OAAO,iBAAiB,SAAS,OAAO;AACpD,iBAAK,OAAO,OAAO,iBAAiB,SAAS,OAAO;AACpD,iBAAK,gBAAgB;AACrB,mBAAO,GAAG;AAAA,UACZ;AACA,eAAK,OAAO,OAAO,KAAK,SAAS,OAAO;AACxC,eAAK,OAAO,OAAO,KAAK,SAAS,OAAO;AAAA,QAC1C,CAAC;AAAA,MACH;AAAA,IACF,SAAS,KAAK;AACZ,YAAM,IAAI,MAAM,iBAAiB,MAAM,cAAc,eAAe,GAAG,CAAC,EAAE;AAAA,IAC5E;AAAA,EACF;AAAA,EAEQ,OAAO,GAAiB;AAC9B,SAAK,YAAY;AAIjB,QAAI,KAAK,SAAS,SAAS,WAAU,qBAAqB;AACxD,YAAM,YAAY,KAAK,SAAS;AAChC,WAAK,WAAW;AAChB,WAAK;AAAA,QACH,QAAQ,KAAK,KAAK,IAAI,yBAAyB,SAAS;AAAA,MAC1D;AACA,WAAK,KAAK,MAAM;AAChB;AAAA,IACF;AAEA,QAAI,MAAM,KAAK,SAAS,QAAQ,IAAI;AACpC,WAAO,QAAQ,IAAI;AACjB,YAAM,OAAO,KAAK,SAAS,MAAM,GAAG,GAAG,EAAE,KAAK;AAC9C,WAAK,WAAW,KAAK,SAAS,MAAM,MAAM,CAAC;AAC3C,UAAI,KAAM,MAAK,OAAO,IAAI;AAC1B,YAAM,KAAK,SAAS,QAAQ,IAAI;AAAA,IAClC;AAAA,EACF;AAAA,EAEQ,OAAO,MAAoB;AACjC,QAAI;AACJ,QAAI;AACF,YAAM,KAAK,MAAM,IAAI;AAAA,IACvB,QAAQ;AACN;AAAA,IACF;AAEA,QAAI,OAAO,QAAQ,YAAY,QAAQ,KAAM;AAC7C,UAAM,WAAW;AACjB,QAAI,SAAS,SAAS,MAAM,MAAO;AAKnC,QAAI,OAAO,SAAS,QAAQ,MAAM,UAAU;AAC1C,YAAM,KAAK,SAAS,IAAI;AACxB,UAAI,OAAO,OAAO,YAAY,OAAO,OAAO,UAAU;AACpD,aAAK,oBAAoB;AAAA,UACvB,SAAS;AAAA,UACT;AAAA,UACA,QAAQ,SAAS,QAAQ;AAAA,UACzB,QAAQ,SAAS,QAAQ;AAAA,QAC3B,CAAC;AACD;AAAA,MACF;AAIA,UAAI,OAAO,OAAO,UAAU,IAAI,EAAG;AACnC,UAAI,SAAS,QAAQ,MAAM,oCAAoC;AAC7D,aAAK,KAAK,uBAAuB;AAAA,MACnC,WAAW,SAAS,QAAQ,MAAM,wCAAwC;AACxE,aAAK,sBAAsB,WAAW;AAAA,MACxC,WAAW,SAAS,QAAQ,MAAM,sCAAsC;AACtE,aAAK,sBAAsB,SAAS;AAAA,MACtC;AACA;AAAA,IACF;AAEA,QAAI,CAAC,kBAAkB,GAAG,EAAG;AAC7B,QAAI,KAAK,QAAQ,IAAI,IAAI,EAAE,GAAG;AAC5B,YAAM,QAAQ,KAAK,QAAQ,IAAI,IAAI,EAAE;AACrC,WAAK,QAAQ,OAAO,IAAI,EAAE;AAC1B,aAAO,QAAQ,GAAG;AAAA,IACpB;AAAA,EACF;AAAA,EAEQ,oBAAoBG,UAAqC;AAC/D,UAAM,UACJA,SAAQ,WAAW,2BACf,0CACA,qBAAqBA,SAAQ,MAAM;AACzC,UAAM,WAAW;AAAA,MACf,SAAS;AAAA,MACT,IAAIA,SAAQ;AAAA,MACZ,OAAO,EAAE,MAAM,QAAQ,QAAQ;AAAA,IACjC;AAEA,QAAI;AACF,WAAK,OAAO,OAAO,MAAM,GAAG,KAAK,UAAU,QAAQ,CAAC;AAAA,CAAI;AAAA,IAC1D,QAAQ;AAAA,IAGR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAc,yBAAwC;AACpD,QAAI;AACF,YAAM,WAAW,MAAM,KAAK,QAAQ,cAAc,CAAC,CAAC;AACpD,YAAM,QAAQ;AAAA,QACX,SAAS,QAAwD;AAAA,MACpE;AACA,WAAK,SAAS;AACd,WAAK,cAAc;AACnB,iBAAW,YAAY,KAAK,uBAAuB;AACjD,YAAI;AACF,mBAAS,KAAK,KAAK,MAAM,CAAC,GAAG,KAAK,CAAC;AAAA,QACrC,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEA,wBAAwB,UAAsC;AAC5D,SAAK,sBAAsB,IAAI,QAAQ;AAAA,EACzC;AAAA,EAEA,2BAA2B,UAAsC;AAC/D,SAAK,sBAAsB,OAAO,QAAQ;AAAA,EAC5C;AAAA,EAEA,4BAA4B,UAAwC;AAClE,SAAK,0BAA0B,IAAI,QAAQ;AAAA,EAC7C;AAAA,EAEA,+BAA+B,UAAwC;AACrE,SAAK,0BAA0B,OAAO,QAAQ;AAAA,EAChD;AAAA,EAEA,0BAA0B,UAAwC;AAChE,SAAK,wBAAwB,IAAI,QAAQ;AAAA,EAC3C;AAAA,EAEA,6BAA6B,UAAwC;AACnE,SAAK,wBAAwB,OAAO,QAAQ;AAAA,EAC9C;AAAA,EAEQ,sBAAsB,YAA2C;AACvE,UAAM,YACJ,eAAe,cAAc,KAAK,4BAA4B,KAAK;AACrE,eAAW,YAAY,WAAW;AAChC,UAAI;AACF,iBAAS,KAAK,KAAK,IAAI;AAAA,MACzB,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AACF;AAQO,SAAS,gBAAgB,KAAqB;AACnD,MAAI,CAAC,QAAQ,KAAK,GAAG,EAAG,QAAO;AAC/B,SAAO,IAAI,IAAI,QAAQ,MAAM,IAAI,CAAC;AACpC;AAEA,IAAM,2BAA2B;AAEjC,SAAS,uBACP,OACA,OACA,aAAa,OACY;AACzB,MAAI,OAAO,UAAU,YAAa,CAAC,cAAc,MAAM,WAAW,GAAI;AACpE,UAAM,IAAI,MAAM,OAAO,KAAK,YAAY,aAAa,aAAa,oBAAoB,EAAE;AAAA,EAC1F;AACA,MAAI,MAAM,SAAS,0BAA0B;AAC3C,UAAM,IAAI,MAAM,OAAO,KAAK,YAAY,wBAAwB,aAAa;AAAA,EAC/E;AACF;AAEA,SAAS,WAAW,QAA4B,OAAuC;AACrF,MAAI,WAAW,OAAW,QAAO,CAAC;AAClC,yBAAuB,QAAQ,KAAK;AACpC,SAAO,EAAE,OAAO;AAClB;AAEA,SAAS,iBAAiB,OAAsB;AAC9C,MAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAAG;AAC/D,UAAM,IAAI,MAAM,6CAA6C;AAAA,EAC/D;AACF;;;AU1hCO,IAAM,kCAAkC,MAAM;AAC9C,IAAM,+BAA+B;AAAA,EAC1C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAiCO,SAAS,yBACd,YACA,cACA,QACA,SAA6B,CAAC,GACR;AACtB,kBAAgB,YAAY,aAAa;AACzC,cAAY,cAAc,MAAM;AAChC,MAAI,OAAO,SAAS,SAAS,IAAI;AAC/B,UAAM,IAAI,MAAM,+DAA+D;AAAA,EACjF;AACA,MAAI,WAAW;AACf,aAAW,WAAW,OAAO,UAAU;AACrC,gBAAY,QAAQ,KAAK,MAAM;AAC/B,QAAI,QAAQ,SAAS,OAAW,aAAY,UAAU,QAAQ,IAAI;AAClE,QAAI,QAAQ,SAAS,OAAW,aAAY,mBAAmB,QAAQ,IAAI;AAC3E,gBAAY,UAAU,MAAM;AAAA,EAC9B;AACA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,WAAW;AAAA,IACX;AAAA,IACA,YAAY;AAAA,MACV,QAAQ;AAAA,MACR;AAAA,MACA,YAAY;AAAA,MACZ,aAAa;AAAA,IACf;AAAA,IACA,UAAU,gBAAgB,OAAO,QAAQ;AAAA,EAC3C;AACF;AAEO,SAAS,uBACd,YACA,YACA,MACA,QACA,SAA6B,CAAC,GACV;AACpB,kBAAgB,YAAY,aAAa;AACzC,kBAAgB,YAAY,aAAa;AACzC,MAAI,OAAO,SAAS,SAAS,KAAK;AAChC,UAAM,IAAI,MAAM,wDAAwD;AAAA,EAC1E;AACA,aAAW,WAAW,OAAO,SAAU,sBAAqB,QAAQ,SAAS,QAAQ,CAAC;AACtF,MAAI;AACJ,MAAI;AACF,iBAAa,KAAK,UAAU,OAAO,QAAQ;AAAA,EAC7C,QAAQ;AACN,UAAM,IAAI,MAAM,wDAAwD;AAAA,EAC1E;AACA,QAAM,WAAW,UAAU,UAAU;AACrC,cAAY,UAAU,MAAM;AAC5B,SAAO;AAAA,IACL,MAAM;AAAA,IACN,WAAW;AAAA,IACX;AAAA,IACA,YAAY;AAAA,MACV,QAAQ;AAAA,MACR;AAAA,MACA,YAAY;AAAA,MACZ;AAAA,MACA,qBAAqB,OAAO,KAAK,QAAQ,CAAC,CAAC,EAAE,KAAK;AAAA,IACpD;AAAA,IACA,aAAa,OAAO;AAAA,IACpB,UAAU,gBAAgB,OAAO,QAAQ;AAAA,EAC3C;AACF;AAEA,SAAS,qBAAqB,OAAgB,QAA4B,OAAqB;AAC7F,MAAI,QAAQ,GAAI,OAAM,IAAI,MAAM,sDAAsD;AACtF,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,eAAW,QAAQ,MAAO,sBAAqB,MAAM,QAAQ,QAAQ,CAAC;AACtE;AAAA,EACF;AACA,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU;AACzC,aAAW,CAAC,KAAK,MAAM,KAAK,OAAO,QAAQ,KAAgC,GAAG;AAC5E,QAAI,QAAQ,SAAS,OAAO,WAAW,SAAU,aAAY,QAAQ,MAAM;AAC3E,yBAAqB,QAAQ,QAAQ,QAAQ,CAAC;AAAA,EAChD;AACF;AAEA,SAAS,YAAY,KAAa,QAAkC;AAClE,MAAI,IAAI,WAAW,KAAK,IAAI,SAAS,MAAO;AAC1C,UAAM,IAAI,MAAM,uDAAkD;AAAA,EACpE;AACA,MAAI;AACJ,MAAI;AACF,aAAS,IAAI,IAAI,GAAG;AAAA,EACtB,QAAQ;AACN,UAAM,IAAI,MAAM,oCAAoC;AAAA,EACtD;AACA,QAAM,SAAS,OAAO,SAAS,MAAM,GAAG,EAAE,EAAE,YAAY;AACxD,QAAM,UAAU,IAAI;AAAA,KACjB,OAAO,qBAAqB,8BAA8B,IAAI,CAAC,UAAU,MAAM,YAAY,CAAC;AAAA,EAC/F;AACA,MAAI,CAAC,QAAQ,IAAI,MAAM,GAAG;AACxB,UAAM,IAAI,MAAM,6BAA6B,MAAM,kBAAkB;AAAA,EACvE;AACA,OAAK,WAAW,UAAU,WAAW,aAAa,OAAO,YAAY,OAAO,WAAW;AACrF,UAAM,IAAI,MAAM,gDAAgD;AAAA,EAClE;AACF;AAEA,SAAS,YAAY,UAAkB,QAAkC;AACvE,QAAM,WAAW,OAAO,YAAY;AACpC,MAAI,CAAC,OAAO,cAAc,QAAQ,KAAK,YAAY,GAAG;AACpD,UAAM,IAAI,MAAM,wDAAwD;AAAA,EAC1E;AACA,MAAI,WAAW,UAAU;AACvB,UAAM,IAAI,MAAM,6BAA6B,QAAQ,qBAAqB;AAAA,EAC5E;AACF;AAEA,SAAS,mBAAmB,MAAsB;AAChD,MAAI,CAAC,mEAAmE,KAAK,IAAI,GAAG;AAClF,UAAM,IAAI,MAAM,wDAAwD;AAAA,EAC1E;AACA,QAAM,UAAU,KAAK,SAAS,IAAI,IAAI,IAAI,KAAK,SAAS,GAAG,IAAI,IAAI;AACnE,SAAQ,KAAK,SAAS,IAAK,IAAI;AACjC;AAEA,SAAS,UAAU,OAAuB;AACxC,SAAO,IAAI,YAAY,EAAE,OAAO,KAAK,EAAE;AACzC;AAEA,SAAS,gBAAgB,OAAe,OAAqB;AAC3D,MAAI,MAAM,WAAW,KAAK,MAAM,SAAS,KAAK;AAC5C,UAAM,IAAI,MAAM,iBAAiB,KAAK,qCAAgC;AAAA,EACxE;AACF;;;AClKA,SAAS,eAAAC,oBAAmB;AAC5B,YAAY,QAAQ;AAsEpB,eAAe,WAAWC,OAAgD;AACxE,MAAI;AACF,WAAO,KAAK,MAAM,MAAS,YAASA,OAAM,MAAM,CAAC;AAAA,EACnD,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,eAAe,YAAYA,OAAc,KAA6C;AACpF,QAAM,MAAM,KAAK,UAAU,KAAK,MAAM,CAAC;AAIvC,QAAM,MAAM,GAAGA,KAAI,IAAI,QAAQ,GAAG,IAAID,aAAY,CAAC,EAAE,SAAS,KAAK,CAAC;AACpE,QAAS,aAAU,KAAK,KAAK,MAAM;AACnC,MAAI;AACF,UAAS,UAAO,KAAKC,KAAI;AAAA,EAC3B,SAAS,KAAK;AACZ,UAAS,MAAG,KAAK,EAAE,OAAO,KAAK,CAAC,EAAE,MAAM,MAAM,MAAS;AACvD,UAAM;AAAA,EACR;AACF;AAEA,SAAS,kBAAkB,OAA0D;AACnF,SAAO,CAAC,CAAC,SAAS,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK;AACrE;AAEA,eAAe,YAAY,YAGxB;AACD,QAAM,OAAO,MAAM,WAAW,UAAU;AACxC,QAAM,UAAU,kBAAkB,KAAK,UAAU,IAAI,EAAE,GAAG,KAAK,WAAW,IAAI,CAAC;AAC/E,SAAO,EAAE,MAAM,QAAQ;AACzB;AAEA,eAAe,QACb,YACA,MACA,SACe;AACf,OAAK,aAAa;AAClB,QAAM,YAAY,YAAY,IAAI;AACpC;AAKA,SAAS,mBAAmB,GAAqD;AAC/E,MAAI,MAAM,MAAO,QAAO;AACxB,MAAI,MAAM,UAAU,MAAM,kBAAmB,QAAO;AACpD,SAAO;AACT;AAOA,SAAS,YAAY,OAAuB,MAAqD;AAC/F,QAAM,MAAuB;AAAA,IAC3B,MAAM,MAAM;AAAA,IACZ,WAAW,MAAM,YACb,mBAAmB,OAAO,MAAM,SAAS,CAAC,IACzC,MAAM,aAAa;AAAA,EAC1B;AACA,QAAM,cAAc,MAAM,eAAe,MAAM;AAC/C,MAAI,gBAAgB,OAAW,KAAI,cAAc;AACjD,QAAM,UAAU,MAAM,WAAW,MAAM;AACvC,MAAI,YAAY,OAAW,KAAI,UAAU;AACzC,QAAM,OAAO,MAAM,QAAQ,MAAM;AACjC,MAAI,SAAS,OAAW,KAAI,OAAO;AACnC,QAAM,MAAM,MAAM,OAAO,MAAM;AAC/B,MAAI,QAAQ,OAAW,KAAI,MAAM;AACjC,QAAM,MAAM,MAAM,OAAO,MAAM;AAC/B,MAAI,QAAQ,OAAW,KAAI,MAAM;AACjC,QAAM,UAAU,MAAM,WAAW,MAAM;AACvC,MAAI,YAAY,OAAW,KAAI,UAAU;AACzC,QAAM,eAAe,MAAM,gBAAgB,MAAM;AACjD,MAAI,iBAAiB,OAAW,KAAI,eAAe;AACnD,QAAM,aAAa,MAAM,cAAc,MAAM;AAC7C,MAAI,eAAe,OAAW,KAAI,aAAa;AAC/C,QAAM,UAAU,MAAM,WAAW,MAAM;AACvC,MAAI,YAAY,OAAW,KAAI,UAAU;AACzC,QAAM,OAAO,MAAM,QAAQ,MAAM;AACjC,MAAI,SAAS,OAAW,KAAI,OAAO;AACnC,QAAM,iBAAiB,MAAM,kBAAkB,MAAM;AACrD,MAAI,mBAAmB,OAAW,KAAI,iBAAiB;AACvD,QAAM,SAAS,MAAM,UAAU,MAAM;AACrC,MAAI,WAAW,OAAW,KAAI,SAAS;AACvC,SAAO;AACT;AAGA,SAAS,cAAc,MAAc,KAAsB,UAAsC;AAC/F,QAAM,OAAO,SAAS,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI;AACxD,QAAM,OAAsB;AAAA,IAC1B;AAAA,IACA,WAAW,IAAI;AAAA,IACf,SAAS,IAAI,YAAY;AAAA,IACzB,QAAQ,OAAO,KAAK,QAAQ;AAAA,IAC5B,OAAO,MAAM,SAAS,CAAC;AAAA,EACzB;AACA,MAAI,IAAI,gBAAgB,OAAW,MAAK,cAAc,IAAI;AAC1D,MAAI,IAAI,QAAQ,OAAW,MAAK,MAAM,IAAI;AAC1C,MAAI,IAAI,YAAY,OAAW,MAAK,UAAU,IAAI;AAClD,MAAI,IAAI,SAAS,OAAW,MAAK,OAAO,IAAI;AAC5C,MAAI,IAAI,QAAQ,OAAW,MAAK,MAAM,IAAI;AAC1C,MAAI,IAAI,SAAS,OAAW,MAAK,OAAO,IAAI;AAC5C,SAAO;AACT;AAEA,SAAS,UAAU,MAAc,UAA2D;AAC1F,QAAM,OAAO,SAAS,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI;AACxD,SAAO,EAAE,OAAO,MAAM,SAAS,WAAW,OAAO,MAAM,SAAS,CAAC,EAAE;AACrE;AAEA,SAAS,WAAW,KAAsB;AACxC,SAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AACxD;AAKA,eAAsB,QAAQ,MAA+C;AAC3E,QAAM,EAAE,QAAQ,IAAI,MAAM,YAAY,KAAK,UAAU;AACrD,SAAO,OAAO,QAAQ,OAAO,EAAE;AAAA,IAAI,CAAC,CAAC,MAAM,GAAG,MAC5C,cAAc,MAAM,EAAE,GAAG,KAAK,KAAK,GAAG,KAAK,QAAQ;AAAA,EACrD;AACF;AAOA,eAAsB,OAAO,OAAuB,MAA2C;AAC7F,MAAI,CAAC,MAAM,KAAM,QAAO,EAAE,IAAI,OAAO,SAAS,0BAA0B;AAExE,QAAM,EAAE,MAAM,QAAQ,IAAI,MAAM,YAAY,KAAK,UAAU;AAC3D,MAAI,QAAQ,MAAM,IAAI,GAAG;AACvB,WAAO,EAAE,IAAI,OAAO,SAAS,WAAW,MAAM,IAAI,mBAAmB;AAAA,EACvE;AAIA,QAAM,SAAS,KAAK,UAAU,MAAM,IAAI;AACxC,QAAM,oBAAoB,CAAC,EAAE,MAAM,aAAa,MAAM,WAAW,MAAM;AACvE,QAAM,MAAM,oBACR,YAAY,OAAO,MAAM,IACzB,SACE,YAAY,EAAE,GAAG,OAAO,MAAM,MAAM,KAAK,GAAG,MAAM,IAClD,YAAY,KAAK;AAEvB,MAAI,CAAC,qBAAqB,CAAC,QAAQ;AACjC,UAAM,QAAQ,OAAO,KAAK,KAAK,WAAW,CAAC,CAAC,EAAE,KAAK,IAAI;AACvD,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,SAAS,QACL,mBAAmB,MAAM,IAAI,yBAAyB,KAAK,KAC3D,kCAAkC,MAAM,IAAI;AAAA,IAClD;AAAA,EACF;AAEA,MAAI,UAAU,MAAM,WAAW;AAC/B,UAAQ,MAAM,IAAI,IAAI;AACtB,QAAM,QAAQ,KAAK,YAAY,MAAM,OAAO;AAE5C,MAAI,IAAI,SAAS;AACf,WAAO,YAAY,MAAM,MAAM,KAAK,MAAM,WAAW,MAAM,IAAI,SAAS;AAAA,EAC1E;AACA,gBAAc,KAAK,UAAU,GAAG;AAChC,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,SAAS,WAAW,MAAM,IAAI;AAAA,IAC9B,QAAQ,cAAc,MAAM,MAAM,KAAK,KAAK,QAAQ;AAAA,EACtD;AACF;AAGA,eAAsB,UAAU,OAAuB,MAA2C;AAChG,MAAI,CAAC,MAAM,KAAM,QAAO,EAAE,IAAI,OAAO,SAAS,0BAA0B;AAExE,QAAM,EAAE,MAAM,QAAQ,IAAI,MAAM,YAAY,KAAK,UAAU;AAC3D,QAAM,WAAW,QAAQ,MAAM,IAAI;AACnC,MAAI,CAAC,SAAU,QAAO,EAAE,IAAI,OAAO,SAAS,WAAW,MAAM,IAAI,cAAc;AAE/E,QAAM,MAAM,YAAY,OAAO,EAAE,GAAG,UAAU,MAAM,MAAM,KAAK,CAAC;AAChE,UAAQ,MAAM,IAAI,IAAI;AACtB,QAAM,QAAQ,KAAK,YAAY,MAAM,OAAO;AAG5C,MAAI,IAAI,YAAY,OAAO;AACzB,WAAO,YAAY,MAAM,MAAM,KAAK,MAAM,WAAW,MAAM,IAAI,aAAa,EAAE,SAAS,KAAK,CAAC;AAAA,EAC/F;AACA,QAAM,SAAS,MAAM,MAAM,IAAI;AAC/B,gBAAc,KAAK,UAAU,GAAG;AAChC,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,SAAS,WAAW,MAAM,IAAI;AAAA,IAC9B,QAAQ,cAAc,MAAM,MAAM,KAAK,KAAK,QAAQ;AAAA,EACtD;AACF;AAGA,eAAsB,UAAU,MAAc,MAA2C;AACvF,MAAI,CAAC,KAAM,QAAO,EAAE,IAAI,OAAO,SAAS,0BAA0B;AAClE,QAAM,EAAE,MAAM,QAAQ,IAAI,MAAM,YAAY,KAAK,UAAU;AAC3D,MAAI,CAAC,QAAQ,IAAI,EAAG,QAAO,EAAE,IAAI,OAAO,SAAS,WAAW,IAAI,cAAc;AAE9E,QAAM,SAAS,MAAM,IAAI;AACzB,sBAAoB,KAAK,UAAU,IAAI;AACvC,SAAO,QAAQ,IAAI;AACnB,QAAM,QAAQ,KAAK,YAAY,MAAM,OAAO;AAC5C,SAAO,EAAE,IAAI,MAAM,SAAS,WAAW,IAAI,YAAY;AACzD;AAGA,eAAsB,UAAU,MAAc,MAA2C;AACvF,MAAI,CAAC,KAAM,QAAO,EAAE,IAAI,OAAO,SAAS,0BAA0B;AAClE,QAAM,EAAE,MAAM,QAAQ,IAAI,MAAM,YAAY,KAAK,UAAU;AAC3D,QAAM,MAAM,QAAQ,IAAI;AACxB,MAAI,CAAC,KAAK;AACR,WAAO,EAAE,IAAI,OAAO,SAAS,WAAW,IAAI,oCAAoC;AAAA,EAClF;AACA,MAAI,UAAU;AACd,UAAQ,IAAI,IAAI;AAChB,QAAM,QAAQ,KAAK,YAAY,MAAM,OAAO;AAC5C,SAAO,YAAY,MAAM,KAAK,MAAM,WAAW,IAAI,aAAa,EAAE,SAAS,KAAK,CAAC;AACnF;AAGA,eAAsB,WAAW,MAAc,MAA2C;AACxF,MAAI,CAAC,KAAM,QAAO,EAAE,IAAI,OAAO,SAAS,0BAA0B;AAClE,QAAM,EAAE,MAAM,QAAQ,IAAI,MAAM,YAAY,KAAK,UAAU;AAC3D,QAAM,MAAM,QAAQ,IAAI;AACxB,MAAI,CAAC,IAAK,QAAO,EAAE,IAAI,OAAO,SAAS,WAAW,IAAI,sBAAsB;AAE5E,QAAM,SAAS,MAAM,IAAI;AACzB,MAAI,UAAU;AACd,gBAAc,KAAK,UAAU,EAAE,GAAG,KAAK,KAAK,CAAC;AAC7C,UAAQ,IAAI,IAAI;AAChB,QAAM,QAAQ,KAAK,YAAY,MAAM,OAAO;AAC5C,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,SAAS,WAAW,IAAI;AAAA,IACxB,QAAQ,cAAc,MAAM,KAAK,KAAK,QAAQ;AAAA,EAChD;AACF;AAGA,eAAsB,WAAW,MAAc,MAA2C;AACxF,MAAI,CAAC,KAAM,QAAO,EAAE,IAAI,OAAO,SAAS,0BAA0B;AAClE,QAAM,aAAa,KAAK,SAAS,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI;AACnE,MAAI,YAAY;AACd,QAAI;AACF,YAAM,KAAK,SAAS,QAAQ,IAAI;AAChC,YAAM,EAAE,OAAO,MAAM,IAAI,UAAU,MAAM,KAAK,QAAQ;AACtD,aAAO,EAAE,IAAI,MAAM,SAAS,WAAW,IAAI,eAAe,OAAO,MAAM;AAAA,IACzE,SAAS,KAAK;AACZ,aAAO,EAAE,IAAI,OAAO,SAAS,sBAAsB,IAAI,MAAM,WAAW,GAAG,CAAC,GAAG;AAAA,IACjF;AAAA,EACF;AAEA,QAAM,EAAE,QAAQ,IAAI,MAAM,YAAY,KAAK,UAAU;AACrD,QAAM,MAAM,QAAQ,IAAI;AACxB,MAAI,CAAC,IAAK,QAAO,EAAE,IAAI,OAAO,SAAS,WAAW,IAAI,sBAAsB;AAC5E,SAAO,YAAY,MAAM,EAAE,GAAG,KAAK,KAAK,GAAG,MAAM,WAAW,IAAI,aAAa,EAAE,SAAS,KAAK,CAAC;AAChG;AAMA,eAAsB,YAAY,MAAc,MAA2C;AACzF,MAAI,CAAC,KAAM,QAAO,EAAE,IAAI,OAAO,SAAS,0BAA0B;AAClE,QAAM,SAAS,MAAM,WAAW,MAAM,IAAI;AAC1C,MAAI,CAAC,OAAO,GAAI,QAAO;AACvB,QAAM,EAAE,OAAO,MAAM,IAAI,UAAU,MAAM,KAAK,QAAQ;AACtD,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,SAAS,cAAc,MAAM,MAAM,QAAQ,MAAM,WAAW,IAAI,KAAK,GAAG,UAAU,IAAI;AAAA,IACtF;AAAA,IACA;AAAA,EACF;AACF;AASA,eAAe,YACb,MACA,KACA,MACA,WACA,MACsB;AACtB,MAAI;AACF,UAAM,oBAAoB,KAAK,SAAS,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI;AAC1E,QAAI,qBAAqB,MAAM,SAAS;AACtC,YAAM,KAAK,SAAS,QAAQ,IAAI;AAAA,IAClC,WAAW,mBAAmB;AAC5B,YAAM,KAAK,SAAS,QAAQ,IAAI;AAAA,IAClC,OAAO;AACL,YAAM,KAAK,SAAS,MAAM,EAAE,GAAG,KAAK,SAAS,KAAK,CAAC;AAAA,IACrD;AACA,UAAM,EAAE,OAAO,MAAM,IAAI,UAAU,MAAM,KAAK,QAAQ;AACtD,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,SAAS;AAAA,MACT,QAAQ,cAAc,MAAM,KAAK,KAAK,QAAQ;AAAA,MAC9C;AAAA,MACA;AAAA,IACF;AAAA,EACF,SAAS,KAAK;AACZ,UAAM,UAAU,WAAW,GAAG;AAC9B,WAAO;AAAA,MACL,IAAI;AAAA;AAAA,MACJ,SAAS,GAAG,SAAS,oCAAoC,OAAO;AAAA,MAChE,QAAQ,cAAc,MAAM,KAAK,KAAK,QAAQ;AAAA,MAC9C,eAAe;AAAA,IACjB;AAAA,EACF;AACF;AAGA,eAAe,SAAS,MAAc,MAAoC;AACxE,MAAI;AACF,UAAM,KAAK,SAAS,KAAK,IAAI;AAAA,EAC/B,QAAQ;AAAA,EAER;AACF;AAEA,SAAS,cAAc,UAAuB,KAA4B;AACxE,MAAI,OAAO,SAAS,iBAAiB,WAAY,UAAS,aAAa,GAAG;AAC5E;AAEA,SAAS,oBAAoB,UAAuB,MAAoB;AACtE,MAAI,OAAO,SAAS,WAAW,WAAY,UAAS,OAAO,IAAI;AACjE;;;AClaA,SAAS,cAAAC,mBAAkB;AAC3B,YAAYC,SAAQ;AACpB,YAAY,UAAU;AAgCf,SAAS,mBAAmB,KAKxB;AACT,QAAM,QAAQ,KAAK,UAAU;AAAA,IAC3B,WAAW,IAAI;AAAA,IACf,SAAS,IAAI,WAAW;AAAA,IACxB,MAAM,IAAI,QAAQ;AAAA,IAClB,KAAK,IAAI,OAAO;AAAA,EAClB,CAAC;AACD,SAAOC,YAAW,QAAQ,EAAE,OAAO,KAAK,EAAE,OAAO,KAAK,EAAE,MAAM,GAAG,EAAE;AACrE;AAGA,SAAS,aAAa,UAAkB,MAAsB;AAC5D,QAAM,OAAO,KAAK,QAAQ,oBAAoB,GAAG;AACjD,SAAY,UAAK,UAAU,aAAa,GAAG,IAAI,OAAO;AACxD;AAMA,eAAsB,aACpB,UACA,MACA,YAC2B;AAC3B,QAAM,WAAW,MAAM,uBAAuB,UAAU,MAAM,UAAU;AACxE,SAAO,UAAU,SAAS;AAC5B;AAMA,eAAsB,uBACpB,UACA,MACA,YACuC;AACvC,MAAI;AACF,UAAM,MAAM,MAAS,aAAS,aAAa,UAAU,IAAI,GAAG,MAAM;AAClE,UAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,QAAI,OAAO,eAAe,cAAc,CAAC,MAAM,QAAQ,OAAO,KAAK,EAAG,QAAO;AAC7E,WAAO;AAAA,MACL,OAAO,OAAO;AAAA,MACd,gBACE,OAAO,mBAAmB,SACtB,SACA,oBAAoB,OAAO,cAAc;AAAA,MAC/C,WACE,OAAO,cAAc,SACjB,SACA,yBAAyB,EAAE,WAAW,OAAO,UAAU,CAAC,EAAE;AAAA,MAChE,mBACE,OAAO,sBAAsB,SACzB,SACA,iCAAiC,EAAE,mBAAmB,OAAO,kBAAkB,CAAC,EAC7E;AAAA,MACT,SACE,OAAO,YAAY,SACf,SACA,uBAAuB,EAAE,SAAS,OAAO,QAAQ,CAAC,EAAE;AAAA,IAC5D;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGA,eAAsB,cACpB,UACA,MACA,YACA,OACe;AACf,QAAM,WAAW,MAAM,uBAAuB,UAAU,MAAM,UAAU;AACxE,QAAM,wBAAwB,UAAU,MAAM,YAAY;AAAA,IACxD,GAAG;AAAA,IACH;AAAA,EACF,CAAC;AACH;AAGA,eAAsB,wBACpB,UACA,MACA,YACA,UACe;AACf,MAAI;AACF,UAAM,OAAO,aAAa,UAAU,IAAI;AACxC,UAAS,UAAW,aAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AACtD,UAAM,OAAqB,EAAE,SAAS,GAAG,YAAY,GAAG,SAAS;AACjE,UAAM,MAAM,GAAG,IAAI;AACnB,UAAS,cAAU,KAAK,KAAK,UAAU,MAAM,MAAM,CAAC,GAAG,MAAM;AAC7D,UAAS,WAAO,KAAK,IAAI;AAAA,EAC3B,QAAQ;AAAA,EAER;AACF;;;ACrEO,IAAM,uBAAuB,OAAO,OAAO;AAAA,EAChD,iBAAiB;AAAA,EACjB,eAAe;AAAA,EACf,cAAc;AAChB,CAAC;AAED,IAAM,yBAAyB,oBAAI,IAAI;AAAA,EACrC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAqBM,SAAS,gCAAyD;AACvE,SAAO;AAAA,IACL,qBAAqB;AAAA,IACrB,UAAU,EAAE,WAAW,GAAG,UAAU,GAAG,MAAM,EAAE;AAAA,IAC/C,gBAAgB;AAAA,IAChB,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,mBAAmB,CAAC;AAAA,IACpB,kBAAkB,CAAC;AAAA,IACnB,aAAa,CAAC;AAAA,IACd,eAAe;AAAA,IACf,mBAAmB;AAAA,IACnB,cAAc,CAAC;AAAA,EACjB;AACF;AAEO,SAAS,eACd,iBACA,YACA,UAAU,MACM;AAChB,MAAI,CAAC,QAAS,QAAO;AACrB,MAAI,oBAAoB,UAAW,QAAO;AAC1C,MACE,oBAAoB,gBACpB,oBAAoB,kBACpB,oBAAoB,QACpB;AACA,WAAO;AAAA,EACT;AACA,MAAI,oBAAoB,SAAU,QAAO;AACzC,MAAI,oBAAoB,kBAAkB,WAAW,sBAAsB,EAAG,QAAO;AACrF,SAAO;AACT;AAOO,SAAS,yBACd,YACA,YACwB;AACxB,MAAI,CAAC,WAAY,QAAO,CAAC;AACzB,QAAM,SAAiC,CAAC;AACxC,MAAI,WAAW,2BAA2B,UAAa,WAAW,kBAAkB,SAAS,GAAG;AAC9F,UAAM,QAAQ,WAAW,CAAC,GAAG,WAAW,iBAAiB,EAAE,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC,GAAG,IAAI;AACtF,WAAO,KAAK;AAAA,MACV,MAAM;AAAA,MACN,QAAQ,SAAS,WAAW;AAAA,MAC5B;AAAA,MACA,WAAW,WAAW;AAAA,IACxB,CAAC;AAAA,EACH;AACA,MAAI,WAAW,0BAA0B,UAAa,WAAW,iBAAiB,SAAS,GAAG;AAC5F,UAAM,QAAQ,WAAW,CAAC,GAAG,WAAW,gBAAgB,EAAE,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC,GAAG,IAAI;AACrF,WAAO,KAAK;AAAA,MACV,MAAM;AAAA,MACN,QAAQ,SAAS,WAAW;AAAA,MAC5B;AAAA,MACA,WAAW,WAAW;AAAA,IACxB,CAAC;AAAA,EACH;AACA,MAAI,WAAW,qBAAqB,UAAa,WAAW,YAAY,SAAS,GAAG;AAClF,UAAM,QAAQ,WAAW,CAAC,GAAG,WAAW,WAAW,EAAE,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC,GAAG,IAAI;AAChF,WAAO,KAAK;AAAA,MACV,MAAM;AAAA,MACN,QAAQ,SAAS,WAAW;AAAA,MAC5B;AAAA,MACA,WAAW,WAAW;AAAA,IACxB,CAAC;AAAA,EACH;AACA,MAAI,WAAW,kBAAkB,QAAW;AAC1C,WAAO,KAAK;AAAA,MACV,MAAM;AAAA,MACN,QAAQ,WAAW,qBAAqB,WAAW;AAAA,MACnD,OAAO,WAAW;AAAA,MAClB,WAAW,WAAW;AAAA,IACxB,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAOO,SAAS,sBACd,OACA,QACgB;AAChB,MAAI,UAAU,UAAW,QAAO;AAChC,SAAO,OAAO,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,IAAI,aAAa;AACtD;AAEO,SAAS,iBAAiB,SAA+C;AAC9E,MAAI,QAAQ,WAAW,EAAG,QAAO,EAAE,OAAO,EAAE;AAC5C,QAAM,SAAS,CAAC,GAAG,OAAO,EAAE,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC;AAChD,SAAO;AAAA,IACL,OAAO,QAAQ;AAAA,IACf,QAAQ,QAAQ,QAAQ,SAAS,CAAC;AAAA,IAClC,OAAO,OAAO,CAAC;AAAA,IACf,OAAO,OAAO,OAAO,SAAS,CAAC;AAAA,IAC/B,OAAO,WAAW,QAAQ,GAAG;AAAA,IAC7B,OAAO,WAAW,QAAQ,IAAI;AAAA,EAChC;AACF;AAEO,SAAS,YAAe,QAAa,OAAU,OAAqB;AACzE,SAAO,KAAK,KAAK;AACjB,MAAI,OAAO,SAAS,MAAO,QAAO,OAAO,GAAG,OAAO,SAAS,KAAK;AACnE;AAEO,SAAS,oBAAoB,QAAwB;AAC1D,QAAM,aAAa,OAAO,YAAY,EAAE,QAAQ,mBAAmB,GAAG;AACtE,QAAM,UAAU,WAAW,MAAM,GAAG,qBAAqB,YAAY;AACrE,SAAO,uBAAuB,IAAI,OAAO,IAAI,UAAU;AACzD;AAEA,SAAS,WAAW,QAA2B,OAAuB;AACpE,SAAO,OAAO,KAAK,IAAI,OAAO,SAAS,GAAG,KAAK,IAAI,GAAG,KAAK,KAAK,OAAO,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC;AAC9F;;;AC1PA,SAAS,qBAAqB;;;ACH9B,SAAS,wBAAwB;AAQjC,IAAM,cAAc;AAEpB,SAAS,eAAe,SAA2B;AACjD,MAAI,YAAY,KAAK,QAAQ,IAAI,EAAG,QAAO;AAG3C,QAAM,SAAS,QAAQ;AACvB,MAAI,UAAU,OAAO,WAAW,UAAU;AACxC,UAAM,QAAS,OAAoD;AACnE,QAAI,OAAO;AACT,iBAAW,OAAO,OAAO,KAAK,KAAK,GAAG;AACpC,YAAI,YAAY,KAAK,GAAG,EAAG,QAAO;AAAA,MACpC;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAcO,SAAS,YACd,YACA,SACA,QACA,aAAyB,WACzB,UACM;AACN,QAAM,gBAAgB,QAAQ,UAAU,KAAK,QAAQ,IAAI;AACzD,SAAO;AAAA,IACL,MAAM;AAAA,IACN,aAAa,QAAQ,eAAe,GAAG,aAAa;AAAA,IACpD,WAAW,gCAAgC,UAAU,MAAM,QAAQ,eAAe,EAAE;AAAA,IACpF;AAAA,IACA,UAAU,eAAe,OAAO;AAAA,IAChC,cAAc,CAAC,iBAAiB,SAAS;AAAA,IACzC,aAAa,QAAQ,eAAe,EAAE,MAAM,UAAU,YAAY,CAAC,EAAE;AAAA,IACrE,MAAM,QAAQ,OAAO,MAAM,MAAM;AAC/B,YAAM,YAAY,KAAK,IAAI;AAC3B,gBAAU,QAAQ;AAClB,UAAI,KAAK;AACT,UAAI;AAGF,cAAM,OAAO,OAAO,WAAW,aAAa,MAAM,OAAO,IAAI;AAI7D,cAAM,MAAM,MAAM,KAAK,SAAS,QAAQ,MAAM,OAAO,EAAE,QAAQ,KAAK,OAAO,CAAC;AAC5E,YAAI,IAAI,SAAS;AACf,gBAAM,IAAI,MAAM,UAAU,IAAI,OAAO,CAAC;AAAA,QACxC;AACA,aAAK;AACL,eAAO,UAAU,IAAI,OAAO;AAAA,MAC9B,UAAE;AACA,kBAAU,SAAS,EAAE,YAAY,KAAK,IAAI,IAAI,WAAW,GAAG,CAAC;AAAA,MAC/D;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,UAAU,GAAoB;AACrC,MAAI,OAAO,MAAM,SAAU,QAAO;AAClC,MAAI,MAAM,QAAQ,CAAC,GAAG;AACpB,WAAO,EACJ,IAAI,CAAC,SAAS;AACb,UAAI,QAAQ,OAAO,SAAS,UAAU;AACpC,cAAM,IAAK,KAAkE;AAC7E,YAAI,MAAM,OAAQ,QAAQ,KAAuC,QAAQ;AACzE,eAAO,KAAK,UAAU,IAAI;AAAA,MAC5B;AACA,aAAO,OAAO,IAAI;AAAA,IACpB,CAAC,EACA,KAAK,IAAI;AAAA,EACd;AACA,MAAI,KAAK,OAAO,MAAM,UAAU;AAC9B,QAAI,UAAW,GAA+B;AAC5C,aAAO,OAAQ,EAA8B,IAAI;AAAA,IACnD;AACA,WAAO,KAAK,UAAU,CAAC;AAAA,EACzB;AACA,SAAO,OAAO,KAAK,EAAE;AACvB;;;ADmDO,IAAM,cAAN,MAAM,aAAY;AAAA,EACN,UAAU,oBAAI,IAAwB;AAAA;AAAA,EAEtC,kBAAkB,oBAAI,IAA6B;AAAA,EACnD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,qBAAqB,oBAAI,IAA0B;AAAA;AAAA,EAE5D;AAAA,EAER,YAAY,MAA0B;AACpC,SAAK,eAAe,KAAK;AACzB,SAAK,SAAS,KAAK;AACnB,SAAK,MAAM,KAAK;AAChB,SAAK,WAAW,KAAK,YAAY;AACjC,SAAK,WAAW,KAAK;AACrB,SAAK,gBAAgB,KAAK,iBAAiB,cAAc,KAAK;AAC9D,SAAK,+BAA+B,KAAK;AACzC,SAAK,uBAAuB,KAAK;AAAA,EACnC;AAAA,EAEQ,YAAY,MAA0B;AAC5C,UAAM,OAAO,KAAK,QAAQ,IAAI,IAAI;AAClC,QAAI,CAAC,KAAM,OAAM,IAAI,MAAM,eAAe,IAAI,kBAAkB;AAChE,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,mBACJ,MACA,OAOsC;AACtC,UAAM,UAAU,KAAK,4BAA4B;AACjD,UAAM,MAAM,KAAK,wBAAwB,IAAI;AAC7C,WAAO,QAAQ,MAAM;AAAA,MACnB,YAAY;AAAA,MACZ,UAAU,IAAI;AAAA,MACd,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,sBACJ,MACA,aACA,QACiC;AACjC,UAAM,UAAU,KAAK,4BAA4B;AACjD,UAAM,MAAM,KAAK,wBAAwB,IAAI;AAC7C,WAAO,QAAQ,SAAS,EAAE,YAAY,MAAM,UAAU,IAAI,KAAM,aAAa,OAAO,CAAC;AAAA,EACvF;AAAA,EAEA,MAAM,oBAAoB,MAA+C;AACvE,UAAM,UAAU,KAAK,4BAA4B;AACjD,UAAM,MAAM,KAAK,wBAAwB,IAAI;AAC7C,WAAO,QAAQ,OAAO,MAAM,IAAI,GAAI;AAAA,EACtC;AAAA,EAEA,MAAM,wBAAwB,MAAgC;AAC5D,UAAM,UAAU,KAAK,4BAA4B;AACjD,UAAM,MAAM,KAAK,wBAAwB,IAAI;AAC7C,WAAO,QAAQ,WAAW,MAAM,IAAI,GAAI;AAAA,EAC1C;AAAA,EAEQ,8BAAuD;AAC7D,QAAI,CAAC,KAAK,sBAAsB;AAC9B,YAAM,IAAI,MAAM,8DAA8D;AAAA,IAChF;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,wBAAwB,MAA+B;AAC7D,UAAM,MAAM,KAAK,QAAQ,IAAI,IAAI,GAAG,OAAO,KAAK,gBAAgB,IAAI,IAAI;AACxE,QAAI,CAAC,IAAK,OAAM,IAAI,MAAM,eAAe,IAAI,kBAAkB;AAC/D,QAAI,IAAI,cAAc,WAAW,CAAC,IAAI,KAAK;AACzC,YAAM,IAAI,MAAM,eAAe,IAAI,kCAAkC;AAAA,IACvE;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,MAAM,KAAqC;AAC/C,QAAI,IAAI,YAAY,OAAO;AACzB,UAAI,KAAK,QAAQ,IAAI,IAAI,IAAI,GAAG;AAC9B,cAAM,KAAK,KAAK,IAAI,IAAI;AAAA,MAC1B;AACA,WAAK,aAAa,GAAG;AACrB;AAAA,IACF;AACA,SAAK,gBAAgB,OAAO,IAAI,IAAI;AAOpC,QAAI,KAAK,QAAQ,IAAI,IAAI,IAAI,GAAG;AAC9B,YAAM,IAAI;AAAA,QACR,eAAe,IAAI,IAAI;AAAA,MACzB;AAAA,IACF;AAEA,UAAM,OAAO,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC,KAAK;AAClC,UAAM,OAAmB;AAAA,MACvB;AAAA,MACA,OAAO;AAAA,MACP,WAAW,CAAC;AAAA,MACZ,WAAW,CAAC;AAAA,MACZ,UAAU;AAAA,MACV,kBAAkB;AAAA,MAClB,iBAAiB;AAAA,MACjB;AAAA,MACA,UAAU,KAAK,IAAI;AAAA,MACnB,gBAAgB;AAAA,MAChB,YAAY,8BAA8B;AAAA,IAC5C;AACA,SAAK,QAAQ,IAAI,IAAI,MAAM,IAAI;AAC/B,QAAI,MAAM;AACR,YAAM,KAAK,UAAU,IAAI;AAAA,IAC3B,OAAO;AACL,YAAM,KAAK,eAAe,IAAI;AAAA,IAChC;AAAA,EACF;AAAA;AAAA,EAGA,aAAa,KAA4B;AACvC,SAAK,QAAQ,OAAO,IAAI,IAAI;AAC5B,SAAK,gBAAgB,IAAI,IAAI,MAAM,EAAE,GAAG,KAAK,SAAS,MAAM,CAAC;AAAA,EAC/D;AAAA;AAAA,EAGA,OAAO,MAAoB;AACzB,SAAK,QAAQ,OAAO,IAAI;AACxB,SAAK,gBAAgB,OAAO,IAAI;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAc,UAAU,MAAiC;AACvD,UAAM,WAAW,KAAK;AACtB,QAAI,CAAC,UAAU;AACb,YAAM,KAAK,eAAe,IAAI;AAC9B;AAAA,IACF;AACA,UAAM,OAAO,mBAAmB,KAAK,GAAG;AACxC,UAAM,SAAS,MAAM,uBAAuB,UAAU,KAAK,IAAI,MAAM,IAAI;AACzE,QAAI,QAAQ;AACV,WAAK,iBAAiB,OAAO;AAC7B,WAAK,YAAY,OAAO;AACxB,WAAK,oBAAoB,OAAO;AAChC,WAAK,UAAU,OAAO;AACtB,WAAK,WAAW,MAAM,OAAO,KAAK;AAClC,WAAK,QAAQ;AACb,WAAK,gBAAgB;AACrB,WAAK,IAAI;AAAA,QACP,eAAe,KAAK,IAAI,IAAI,mCAAmC,OAAO,MAAM,MAAM;AAAA,MACpF;AACA;AAAA,IACF;AAGA,UAAM,KAAK,eAAe,IAAI;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,gBAAgB,MAAkC;AACtD,UAAM,OAAO,KAAK,QAAQ,IAAI,IAAI;AAClC,QAAI,CAAC,KAAM,OAAM,IAAI,MAAM,eAAe,IAAI,kBAAkB;AAChE,SAAK,WAAW,KAAK,IAAI;AACzB,QAAI,KAAK,UAAU,KAAK,UAAU,YAAa,QAAO,KAAK;AAC3D,QAAI,KAAK,WAAY,QAAO,KAAK;AACjC,UAAM,SAAS,KAAK,UAAU;AAC9B,QAAI,QAAQ;AACV,WAAK,WAAW;AAChB,WAAK,gBAAgB,MAAM,QAAQ,aAAa;AAAA,IAClD;AACA,SAAK,cAAc,YAAY;AAC7B,UAAI;AAEF,aAAK,WAAW;AAChB,aAAK,kBAAkB;AACvB,cAAM,KAAK,eAAe,IAAI;AAC9B,YAAI,CAAC,KAAK,QAAQ;AAChB,gBAAM,IAAI,MAAM,eAAe,IAAI,+BAA+B;AAAA,QACpE;AACA,aAAK,WAAW,KAAK,IAAI;AACzB,aAAK,gBAAgB;AACrB,eAAO,KAAK;AAAA,MACd,UAAE;AACA,aAAK,aAAa;AAAA,MACpB;AAAA,IACF,GAAG;AACH,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,eAAe,MAAoB;AACjC,UAAM,OAAO,KAAK,QAAQ,IAAI,IAAI;AAClC,QAAI,CAAC,KAAM;AAGX,QAAI,CAAC,KAAK,UAAU,CAAC,KAAK,KAAM;AAChC,QAAI,KAAK,UAAU,SAAS,EAAG;AAC/B,UAAM,SAAS,KAAK;AACpB,QAAI,OAAO,WAAW,EAAG;AACzB,eAAW,QAAQ,QAAQ;AACzB,UAAI;AACF,aAAK,aAAa,SAAS,MAAM,OAAO,IAAI,EAAE;AAC9C,aAAK,UAAU,KAAK,KAAK,IAAI;AAAA,MAC/B,SAAS,KAAK;AACZ,aAAK,IAAI,KAAK,aAAa,KAAK,IAAI,qBAAqB,GAAG;AAAA,MAC9D;AAAA,IACF;AACA,SAAK,IAAI,KAAK,eAAe,IAAI,gBAAgB,KAAK,UAAU,MAAM,SAAS;AAC/E,SAAK,OAAO,KAAK,wBAAwB,EAAE,MAAM,WAAW,KAAK,UAAU,OAAO,CAAC;AAAA,EACrF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,iBAAiB,MAAsB;AACrC,UAAM,OAAO,KAAK,QAAQ,IAAI,IAAI;AAClC,QAAI,CAAC,KAAM,QAAO;AAClB,UAAM,QAAQ,KAAK,UAAU;AAC7B,QAAI,UAAU,EAAG,QAAO;AACxB,eAAW,KAAK,KAAK,WAAW;AAC9B,UAAI;AACF,aAAK,aAAa,WAAW,CAAC;AAAA,MAChC,QAAQ;AAAA,MAER;AAAA,IACF;AACA,SAAK,YAAY,CAAC;AAClB,SAAK,IAAI,KAAK,eAAe,IAAI,kBAAkB,KAAK,iBAAiB;AACzE,SAAK,OAAO,KAAK,2BAA2B,EAAE,MAAM,QAAQ,aAAa,CAAC;AAC1E,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,MAAuB;AACjC,UAAM,OAAO,KAAK,QAAQ,IAAI,IAAI;AAClC,WAAO,OAAO,KAAK,UAAU,SAAS,IAAI;AAAA,EAC5C;AAAA,EAEA,MAAM,KAAK,MAA6B;AACtC,UAAM,OAAO,KAAK,QAAQ,IAAI,IAAI;AAClC,QAAI,CAAC,KAAM;AACX,SAAK,mBAAmB;AAIxB,QAAI,KAAK,gBAAgB;AACvB,mBAAa,KAAK,cAAc;AAChC,WAAK,iBAAiB;AAAA,IACxB;AACA,QAAI,KAAK,QAAQ;AACf,WAAK,OAAO,mBAAmB,KAAK,WAAW;AAC/C,UAAI,KAAK,aAAc,MAAK,OAAO,yBAAyB,KAAK,YAAY;AAC7E,WAAK,OAAO,2BAA2B,KAAK,cAAc;AAC1D,WAAK,uBAAuB,KAAK,MAAM;AACvC,YAAM,KAAK,OAAO,MAAM;AACxB,WAAK,SAAS;AAAA,IAChB;AACA,SAAK,eAAe;AACpB,SAAK,aAAa;AAClB,eAAW,KAAK,KAAK,UAAW,MAAK,aAAa,WAAW,CAAC;AAC9D,SAAK,YAAY,CAAC;AAClB,SAAK,YAAY,CAAC;AAClB,SAAK,iBAAiB;AACtB,SAAK,YAAY;AACjB,SAAK,oBAAoB;AACzB,SAAK,UAAU;AAEf,SAAK,iBAAiB;AACtB,SAAK,QAAQ;AACb,SAAK,gBAAgB,MAAM,QAAQ,QAAQ;AAC3C,SAAK,OAAO,KAAK,2BAA2B,EAAE,MAAM,QAAQ,OAAO,CAAC;AAAA,EACtE;AAAA,EAEA,MAAM,QAAQ,MAA6B;AACzC,UAAM,OAAO,KAAK,QAAQ,IAAI,IAAI;AAClC,QAAI,CAAC,KAAM,OAAM,IAAI,MAAM,eAAe,IAAI,kBAAkB;AAChE,SAAK,WAAW;AAChB,SAAK,gBAAgB,MAAM,WAAW,QAAQ;AAC9C,UAAM,KAAK,KAAK,IAAI;AACpB,SAAK,WAAW;AAChB,SAAK,kBAAkB;AACvB,UAAM,KAAK,eAAe,IAAI;AAAA,EAChC;AAAA,EAEA,OAAuF;AACrF,WAAO,MAAM,KAAK,KAAK,QAAQ,OAAO,CAAC,EAAE,IAAI,CAAC,MAAM;AAClD,YAAM,QAAQ,KAAK,iBAAiB,CAAC;AACrC,aAAO;AAAA,QACL,MAAM,EAAE,IAAI;AAAA,QACZ,OAAO,EAAE;AAAA,QACT,WAAW,MAAM;AAAA,QACjB;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,YAAY,UAA4C;AACtD,SAAK,mBAAmB,IAAI,QAAQ;AACpC,WAAO,MAAM,KAAK,mBAAmB,OAAO,QAAQ;AAAA,EACtD;AAAA;AAAA,EAGA,oBAAkD;AAChD,UAAM,SAAS,MAAM,KAAK,KAAK,QAAQ,OAAO,CAAC,EAAE,IAAI,CAAC,SAAS;AAC7D,YAAM,KAAK,KAAK;AAChB,YAAM,aAAa,eAAe,KAAK,OAAO,IAAI,KAAK,IAAI,YAAY,KAAK;AAC5E,YAAM,SAAS,yBAAyB,IAAI,KAAK,IAAI,QAAQ,UAAU;AACvE,aAAO;AAAA,QACL,MAAM,KAAK,IAAI;AAAA,QACf,iBAAiB,KAAK;AAAA,QACtB,aAAa,sBAAsB,YAAY,MAAM;AAAA,QACrD,eAAe,GAAG;AAAA,QAClB,eAAe,GAAG;AAAA,QAClB,iBAAiB,GAAG;AAAA,QACpB,YAAY,GAAG;AAAA,QACf,qBAAqB,GAAG;AAAA,QACxB,UAAU,EAAE,GAAG,GAAG,SAAS;AAAA,QAC3B,gBAAgB,GAAG;AAAA,QACnB,WAAW,GAAG;AAAA,QACd,YAAY,GAAG;AAAA,QACf,cAAc,GAAG;AAAA,QACjB,mBAAmB,iBAAiB,GAAG,iBAAiB;AAAA,QACxD,kBAAkB,iBAAiB,GAAG,gBAAgB;AAAA,QACtD,aAAa,iBAAiB,GAAG,WAAW;AAAA,QAC5C,eAAe,GAAG;AAAA,QAClB,mBAAmB,GAAG;AAAA,QACtB,cAAc,GAAG,aAAa,IAAI,CAAC,WAAW,EAAE,GAAG,MAAM,EAAE;AAAA,QAC3D,cAAc;AAAA,MAChB;AAAA,IACF,CAAC;AACD,UAAM,WAAW,MAAM,KAAK,KAAK,gBAAgB,OAAO,CAAC,EAAE,IAAI,CAAC,QAAQ;AACtE,YAAM,aAAa,8BAA8B;AACjD,aAAO;AAAA,QACL,MAAM,IAAI;AAAA,QACV,iBAAiB;AAAA,QACjB,aAAa;AAAA,QACb,qBAAqB;AAAA,QACrB,UAAU,EAAE,GAAG,WAAW,SAAS;AAAA,QACnC,gBAAgB;AAAA,QAChB,WAAW;AAAA,QACX,YAAY;AAAA,QACZ,cAAc;AAAA,QACd,mBAAmB,iBAAiB,CAAC,CAAC;AAAA,QACtC,kBAAkB,iBAAiB,CAAC,CAAC;AAAA,QACrC,aAAa,iBAAiB,CAAC,CAAC;AAAA,QAChC,eAAe;AAAA,QACf,mBAAmB;AAAA,QACnB,cAAc,CAAC;AAAA,QACf,cAAc,CAAC;AAAA,MACjB;AAAA,IACF,CAAC;AACD,WAAO,CAAC,GAAG,QAAQ,GAAG,QAAQ;AAAA,EAChC;AAAA,EAEA,WAAW,MAA8C;AACvD,UAAM,OAAO,KAAK,QAAQ,IAAI,IAAI;AAClC,QAAI,CAAC,KAAM,QAAO;AAClB,WAAO,gBAAgB,IAAI;AAAA,EAC7B;AAAA,EAEA,MAAM,cAAc,MAAc,OAA8B,CAAC,GAA2B;AAC1F,UAAM,OAAO,KAAK,YAAY,IAAI;AAClC,QAAI,CAAC,KAAK,WAAW,KAAK,UAAW,QAAO,aAAa,KAAK,SAAS;AACvE,UAAM,SAAS,MAAM,KAAK,gBAAgB,IAAI;AAC9C,QAAI,CAAC,OAAO,kBAAkB,GAAG,aAAa,UAAW,QAAO,CAAC;AACjE,SAAK,YAAY,MAAM;AAAA,MACrB,CAAC,WAAW,OAAO,cAAc,SAAS,EAAE,OAAO,IAAI,CAAC,CAAC;AAAA,MACzD,CAAC,SAAS,KAAK;AAAA,IACjB;AACA,UAAM,KAAK,0BAA0B,IAAI;AACzC,WAAO,aAAa,KAAK,SAAS;AAAA,EACpC;AAAA,EAEA,MAAM,sBACJ,MACA,OAA8B,CAAC,GACC;AAChC,UAAM,OAAO,KAAK,YAAY,IAAI;AAClC,QAAI,CAAC,KAAK,WAAW,KAAK,kBAAmB,QAAO,aAAa,KAAK,iBAAiB;AACvF,UAAM,SAAS,MAAM,KAAK,gBAAgB,IAAI;AAC9C,QAAI,CAAC,OAAO,kBAAkB,GAAG,aAAa,UAAW,QAAO,CAAC;AACjE,SAAK,oBAAoB,MAAM;AAAA,MAC7B,CAAC,WAAW,OAAO,sBAAsB,SAAS,EAAE,OAAO,IAAI,CAAC,CAAC;AAAA,MACjE,CAAC,SAAS,KAAK;AAAA,IACjB;AACA,UAAM,KAAK,0BAA0B,IAAI;AACzC,WAAO,aAAa,KAAK,iBAAiB;AAAA,EAC5C;AAAA,EAEA,MAAM,aAAa,MAAc,KAA6C;AAC5E,YAAQ,MAAM,KAAK,gBAAgB,IAAI,GAAG,aAAa,GAAG;AAAA,EAC5D;AAAA,EAEA,MAAM,2BACJ,MACA,KACA,QAC+B;AAC/B,WAAO,yBAAyB,MAAM,KAAK,MAAM,KAAK,aAAa,MAAM,GAAG,GAAG,MAAM;AAAA,EACvF;AAAA,EAEA,MAAM,kBAAkB,MAAc,KAA4B;AAChE,WAAO,MAAM,KAAK,gBAAgB,IAAI,GAAG,kBAAkB,GAAG;AAAA,EAChE;AAAA,EAEA,MAAM,oBAAoB,MAAc,KAA4B;AAClE,WAAO,MAAM,KAAK,gBAAgB,IAAI,GAAG,oBAAoB,GAAG;AAAA,EAClE;AAAA,EAEA,MAAM,YAAY,MAAc,OAA8B,CAAC,GAAyB;AACtF,UAAM,OAAO,KAAK,YAAY,IAAI;AAClC,QAAI,CAAC,KAAK,WAAW,KAAK,QAAS,QAAO,aAAa,KAAK,OAAO;AACnE,UAAM,SAAS,MAAM,KAAK,gBAAgB,IAAI;AAC9C,QAAI,CAAC,OAAO,kBAAkB,GAAG,aAAa,QAAS,QAAO,CAAC;AAC/D,SAAK,UAAU,MAAM;AAAA,MACnB,CAAC,WAAW,OAAO,YAAY,SAAS,EAAE,OAAO,IAAI,CAAC,CAAC;AAAA,MACvD,CAAC,SAAS,KAAK;AAAA,IACjB;AACA,UAAM,KAAK,0BAA0B,IAAI;AACzC,WAAO,aAAa,KAAK,OAAO;AAAA,EAClC;AAAA,EAEA,MAAM,UACJ,YACA,YACA,MAC6B;AAC7B,YAAQ,MAAM,KAAK,gBAAgB,UAAU,GAAG,UAAU,YAAY,IAAI;AAAA,EAC5E;AAAA,EAEA,MAAM,yBACJ,YACA,YACA,MACA,QAC6B;AAC7B,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA,MAAM,KAAK,UAAU,YAAY,YAAY,IAAI;AAAA,MACjD;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,iBAAiB,GAAyB;AAChD,WAAO,EAAE,UAAU,SAAS,IAAI,EAAE,UAAU,MAAM,KAAK,EAAE,aAAa,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI;AAAA,EAC7F;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASQ,WAAW,MAAkB,OAAkB,QAAsC;AAE3F,QAAI,KAAK,QAAQ,KAAK,kBAAkB,CAAC,KAAK,SAAU;AACxD,UAAM,UAAU,KAAK,IAAI;AACzB,UAAM,WAAW,MAAM,OAAO,CAAC,MAAM,CAAC,WAAW,QAAQ,SAAS,EAAE,IAAI,CAAC;AACzE,UAAM,YAAY,KAAK,OAAO,MAAM,KAAK,gBAAgB,KAAK,IAAI,IAAI,IAAI,cAAc,MAAM;AAC9F,UAAM,UAAU,SAAS;AAAA,MAAI,CAAC,MAC5B,YAAY,KAAK,IAAI,MAAM,GAAG,WAAW,KAAK,IAAI,cAAc,WAAW;AAAA,QACzE,SAAS,MAAM;AACb,eAAK,WAAW;AAChB,eAAK,WAAW,oBAAoB,KAAK;AAAA,YACvC,KAAK,WAAW;AAAA,YAChB,KAAK,WAAW;AAAA,UAClB;AACA,eAAK,gBAAgB,MAAM,QAAQ,WAAW,QAAW,QAAW,KAAK;AAAA,QAC3E;AAAA,QACA,UAAU,CAAC,EAAE,YAAY,GAAG,MAAM;AAChC,eAAK,WAAW,gBAAgB,KAAK,IAAI,GAAG,KAAK,WAAW,gBAAgB,CAAC;AAC7E;AAAA,YACE,KAAK,WAAW;AAAA,YAChB;AAAA,YACA,qBAAqB;AAAA,UACvB;AACA,cAAI,IAAI;AACN,iBAAK,cAAc,IAAI;AACvB,iBAAK,gBAAgB,MAAM,QAAQ,MAAM,QAAW,YAAY,KAAK;AAAA,UACvE,OAAO;AACL,iBAAK,cAAc,MAAM,QAAQ,oBAAoB,UAAU;AAAA,UACjE;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AACA,QAAI,KAAK,UAAU;AAEjB,WAAK,YAAY;AACjB;AAAA,IACF;AACA,eAAW,QAAQ,SAAS;AAC1B,UAAI;AACF,aAAK,aAAa,SAAS,MAAM,OAAO,KAAK,IAAI,IAAI,EAAE;AACvD,aAAK,UAAU,KAAK,KAAK,IAAI;AAAA,MAC/B,SAAS,KAAK;AACZ,aAAK,IAAI,KAAK,aAAa,KAAK,IAAI,oBAAoB,GAAG;AAAA,MAC7D;AAAA,IACF;AACA,QAAI,KAAK,QAAQ,QAAQ,SAAS,EAAG,MAAK,iBAAiB;AAAA,EAC7D;AAAA,EAEA,MAAc,qBAAqB,MAAkB,QAAkC;AACrF,UAAM,YAAY,KAAK,IAAI;AAC3B,SAAK,iBAAiB,OAAO,kBAAkB;AAC/C,UAAM,eAAe,KAAK,gBAAgB;AAC1C,QAAI,cAAc,WAAW;AAC3B,UAAI;AACF,aAAK,YAAY,MAAM;AAAA,UACrB,CAAC,WAAW,OAAO,cAAc,SAAS,EAAE,OAAO,IAAI,CAAC,CAAC;AAAA,UACzD,CAAC,SAAS,KAAK;AAAA,QACjB;AAAA,MACF,SAAS,KAAK;AACZ,aAAK,YAAY;AACjB,aAAK,cAAc,MAAM,YAAY,2BAA2B;AAChE,aAAK,IAAI,KAAK,eAAe,KAAK,IAAI,IAAI,+BAA+B,GAAG;AAAA,MAC9E;AACA,UAAI;AACF,aAAK,oBAAoB,MAAM;AAAA,UAC7B,CAAC,WAAW,OAAO,sBAAsB,SAAS,EAAE,OAAO,IAAI,CAAC,CAAC;AAAA,UACjE,CAAC,SAAS,KAAK;AAAA,QACjB;AAAA,MACF,SAAS,KAAK;AACZ,aAAK,oBAAoB;AACzB,aAAK,cAAc,MAAM,YAAY,oCAAoC;AACzE,aAAK,IAAI,KAAK,eAAe,KAAK,IAAI,IAAI,wCAAwC,GAAG;AAAA,MACvF;AAAA,IACF,OAAO;AACL,WAAK,YAAY;AACjB,WAAK,oBAAoB;AAAA,IAC3B;AACA,QAAI,cAAc,SAAS;AACzB,UAAI;AACF,aAAK,UAAU,MAAM;AAAA,UACnB,CAAC,WAAW,OAAO,YAAY,SAAS,EAAE,OAAO,IAAI,CAAC,CAAC;AAAA,UACvD,CAAC,SAAS,KAAK;AAAA,QACjB;AAAA,MACF,SAAS,KAAK;AACZ,aAAK,UAAU;AACf,aAAK,cAAc,MAAM,YAAY,yBAAyB;AAC9D,aAAK,IAAI,KAAK,eAAe,KAAK,IAAI,IAAI,6BAA6B,GAAG;AAAA,MAC5E;AAAA,IACF,OAAO;AACL,WAAK,UAAU;AAAA,IACjB;AACA,UAAM,aAAa,KAAK,IAAI,IAAI;AAChC,gBAAY,KAAK,WAAW,kBAAkB,YAAY,qBAAqB,eAAe;AAC9F,SAAK,gBAAgB,MAAM,YAAY,YAAY,QAAW,YAAY,KAAK;AAAA,EACjF;AAAA,EAEA,MAAc,0BAA0B,MAAiC;AACvE,QAAI,CAAC,KAAK,QAAQ,CAAC,KAAK,SAAU;AAClC,UAAM,WAAW,KAAK;AACtB,UAAM,WAAW,KAAK,iBAAiB,QAAQ,QAAQ;AACvD,UAAM,UAAU,SAAS;AAAA,MAAK,MAC5B,wBAAwB,UAAU,KAAK,IAAI,MAAM,mBAAmB,KAAK,GAAG,GAAG;AAAA,QAC7E,OAAO,KAAK,QAAQ,UAAU,KAAK,CAAC;AAAA,QACpC,gBAAgB,KAAK;AAAA,QACrB,WAAW,KAAK;AAAA,QAChB,mBAAmB,KAAK;AAAA,QACxB,SAAS,KAAK;AAAA,MAChB,CAAC;AAAA,IACH;AACA,SAAK,gBAAgB;AACrB,UAAM;AACN,QAAI,KAAK,kBAAkB,QAAS,MAAK,gBAAgB;AAAA,EAC3D;AAAA;AAAA,EAGQ,kBAAwB;AAC9B,QAAI,KAAK,aAAa,KAAK,iBAAiB,EAAG;AAC/C,SAAK,YAAY,YAAY,MAAM;AACjC,WAAK,KAAK,UAAU;AAAA,IACtB,GAAG,cAAc,KAAK,iBAAiB;AAEvC,SAAK,UAAU,QAAQ;AAAA,EACzB;AAAA;AAAA,EAGA,MAAc,YAA2B;AACvC,QAAI,KAAK,iBAAiB,EAAG;AAC7B,UAAM,MAAM,KAAK,IAAI;AACrB,eAAW,QAAQ,KAAK,QAAQ,OAAO,GAAG;AACxC,UACE,KAAK,QACL,KAAK,UAAU,eACf,KAAK,UACL,MAAM,KAAK,WAAW,KAAK,eAC3B;AACA,cAAM,KAAK,UAAU,IAAI;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,UAAU,MAAiC;AACvD,SAAK,mBAAmB;AAGxB,QAAI,KAAK,gBAAgB;AACvB,mBAAa,KAAK,cAAc;AAChC,WAAK,iBAAiB;AAAA,IACxB;AACA,QAAI,KAAK,QAAQ;AAEf,WAAK,OAAO,mBAAmB,KAAK,WAAW;AAC/C,UAAI,KAAK,aAAc,MAAK,OAAO,yBAAyB,KAAK,YAAY;AAC7E,WAAK,OAAO,2BAA2B,KAAK,cAAc;AAC1D,WAAK,uBAAuB,KAAK,MAAM;AACvC,YAAM,KAAK,OAAO,MAAM;AACxB,WAAK,SAAS;AAAA,IAChB;AACA,SAAK,eAAe;AACpB,SAAK,QAAQ;AACb,SAAK,WAAW;AAChB,SAAK,gBAAgB,MAAM,SAAS,cAAc;AAClD,SAAK,IAAI,KAAK,eAAe,KAAK,IAAI,IAAI,gDAA2C;AACrF,SAAK,OAAO,KAAK,2BAA2B,EAAE,MAAM,KAAK,IAAI,MAAM,QAAQ,aAAa,CAAC;AAAA,EAC3F;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,WAMI;AACF,UAAM,SAAS,MAAM,KAAK,KAAK,QAAQ,OAAO,CAAC,EAAE,IAAI,CAAC,MAAM;AAC1D,YAAM,QAAQ,KAAK,iBAAiB,CAAC;AACrC,aAAO;AAAA,QACL,MAAM,EAAE,IAAI;AAAA,QACZ,OAAO,EAAE;AAAA,QACT,WAAW,MAAM;AAAA,QACjB,SAAS,EAAE,IAAI,YAAY;AAAA,QAC3B;AAAA,MACF;AAAA,IACF,CAAC;AACD,UAAM,WAAW,MAAM,KAAK,KAAK,gBAAgB,OAAO,CAAC,EAAE,IAAI,CAAC,SAAS;AAAA,MACvE,MAAM,IAAI;AAAA,MACV,OAAO;AAAA,MACP,WAAW;AAAA,MACX,SAAS;AAAA,MACT,OAAO,CAAC;AAAA,IACV,EAAE;AACF,WAAO,CAAC,GAAG,QAAQ,GAAG,QAAQ;AAAA,EAChC;AAAA,EAEA,MAAM,UAAyB;AAC7B,QAAI,KAAK,WAAW;AAClB,oBAAc,KAAK,SAAS;AAC5B,WAAK,YAAY;AAAA,IACnB;AACA,eAAW,QAAQ,MAAM,KAAK,KAAK,QAAQ,KAAK,CAAC,GAAG;AAClD,YAAM,KAAK,KAAK,IAAI;AAAA,IACtB;AACA,SAAK,gBAAgB,MAAM;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,SAA6E;AAC3E,WAAO,MAAM,KAAK,KAAK,QAAQ,OAAO,CAAC,EAAE,IAAI,CAAC,OAAO;AAAA,MACnD,MAAM,EAAE,IAAI;AAAA,MACZ,OAAO,EAAE,UAAU;AAAA,IACrB,EAAE;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASiB,iBAAiB,CAAC,MAAc,WAAqC;AACpF,UAAM,OAAO,KAAK,QAAQ,IAAI,IAAI;AAClC,QAAI,CAAC,MAAM,OAAQ;AAEnB,eAAW,KAAK,KAAK,WAAW;AAC9B,UAAI;AACF,aAAK,aAAa,WAAW,CAAC;AAAA,MAChC,QAAQ;AAAA,MAER;AAAA,IACF;AACA,SAAK,YAAY,CAAC;AAClB,SAAK,iBAAiB;AACtB,UAAM,aAAa,KAAK,OAAO,UAAU;AAEzC,SAAK,WAAW,MAAM,YAAY,KAAK,MAAM;AAC7C,SAAK,KAAK,0BAA0B,IAAI;AACxC,SAAK,OAAO,KAAK,wBAAwB;AAAA,MACvC,MAAM,KAAK,IAAI;AAAA,MACf,WAAW,KAAK,UAAU;AAAA,IAC5B,CAAC;AACD,SAAK,IAAI;AAAA,MACP,eAAe,KAAK,IAAI,IAAI,sBAAsB,KAAK,iBAAiB,IAAI,EAAE,MAAM;AAAA,IACtF;AAAA,EACF;AAAA,EAEiB,qBAAqB,CAAC,SAAuB;AAC5D,UAAM,OAAO,KAAK,QAAQ,IAAI,IAAI;AAClC,QAAI,CAAC,KAAM;AACX,SAAK,YAAY;AACjB,SAAK,oBAAoB;AACzB,SAAK,KAAK,0BAA0B,IAAI;AACxC,SAAK,IAAI,KAAK,eAAe,IAAI,gCAAgC;AAAA,EACnE;AAAA,EAEiB,mBAAmB,CAAC,SAAuB;AAC1D,UAAM,OAAO,KAAK,QAAQ,IAAI,IAAI;AAClC,QAAI,CAAC,KAAM;AACX,SAAK,UAAU;AACf,SAAK,KAAK,0BAA0B,IAAI;AACxC,SAAK,IAAI,KAAK,eAAe,IAAI,8BAA8B;AAAA,EACjE;AAAA,EAEQ,oBAAoB,QAAyB;AACnD,WAAO,4BAA4B,KAAK,kBAAkB;AAC1D,WAAO,0BAA0B,KAAK,gBAAgB;AAAA,EACxD;AAAA,EAEQ,uBAAuB,QAAyB;AACtD,WAAO,+BAA+B,KAAK,kBAAkB;AAC7D,WAAO,6BAA6B,KAAK,gBAAgB;AAAA,EAC3D;AAAA,EAEiB,cAAc,CAC7B,MACA,MACA,YACS;AACT,UAAM,OAAO,KAAK,QAAQ,IAAI,IAAI;AAClC,QAAI,CAAC,KAAM;AACX,QAAI,KAAK,MAAM;AAGb,WAAK,SAAS;AACd,WAAK,QAAQ;AACb,WAAK,cAAc,MAAM,aAAa,mBAAmB;AACzD,WAAK,OAAO,KAAK,2BAA2B;AAAA,QAC1C;AAAA,QACA,QAAQ,QAAQ,QAAQ,SAAS;AAAA,MACnC,CAAC;AACD;AAAA,IACF;AACA,eAAW,KAAK,KAAK,WAAW;AAC9B,UAAI;AACF,aAAK,aAAa,WAAW,CAAC;AAAA,MAChC,QAAQ;AAAA,MAER;AAAA,IACF;AACA,SAAK,YAAY,CAAC;AAClB,SAAK,YAAY,CAAC;AAClB,SAAK,iBAAiB;AACtB,SAAK,YAAY;AACjB,SAAK,oBAAoB;AACzB,SAAK,UAAU;AACf,SAAK,QAAQ;AACb,SAAK,cAAc,MAAM,aAAa,cAAc;AACpD,SAAK,OAAO,KAAK,2BAA2B,EAAE,MAAM,QAAQ,QAAQ,QAAQ,SAAS,GAAG,CAAC;AACzF,SAAK,kBAAkB,IAAI;AAAA,EAC7B;AAAA;AAAA,EAGiB,wBAAwB,CAAC,SAAuB;AAC/D,UAAM,OAAO,KAAK,QAAQ,IAAI,IAAI;AAClC,QAAI,CAAC,KAAM;AACX,QAAI,KAAK,MAAM;AACb,WAAK,SAAS;AACd,WAAK,QAAQ;AACb,WAAK,cAAc,MAAM,aAAa,sBAAsB;AAC5D,WAAK,OAAO,KAAK,2BAA2B,EAAE,MAAM,QAAQ,4BAA4B,CAAC;AACzF;AAAA,IACF;AACA,eAAW,KAAK,KAAK,WAAW;AAC9B,UAAI;AACF,aAAK,aAAa,WAAW,CAAC;AAAA,MAChC,QAAQ;AAAA,MAER;AAAA,IACF;AACA,SAAK,YAAY,CAAC;AAClB,SAAK,YAAY,CAAC;AAClB,SAAK,iBAAiB;AACtB,SAAK,YAAY;AACjB,SAAK,oBAAoB;AACzB,SAAK,UAAU;AACf,SAAK,QAAQ;AACb,SAAK,cAAc,MAAM,aAAa,iBAAiB;AACvD,SAAK,OAAO,KAAK,2BAA2B,EAAE,MAAM,QAAQ,kBAAkB,CAAC;AAC/E,SAAK,kBAAkB,IAAI;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAwB,uBAAuB,cAAc,UAAU;AAAA;AAAA,EAEvE,OAAwB,0BAA0B,cAAc,UAAU;AAAA;AAAA,EAE1E,OAAwB,yBAAyB;AAAA,EAEzC,kBAAkB,MAAwB;AAChD,QAAI,KAAK,iBAAkB;AAC3B,QAAI,KAAK,mBAAmB,aAAY,sBAAsB;AAC5D,WAAK,QAAQ;AACb,WAAK,cAAc,MAAM,aAAa,qBAAqB;AAC3D,WAAK,IAAI;AAAA,QACP,eAAe,KAAK,IAAI,IAAI,qBAAqB,KAAK,eAAe,yCAAyC,KAAK,IAAI,IAAI;AAAA,MAC7H;AACA,WAAK,OAAO,KAAK,2BAA2B;AAAA,QAC1C,MAAM,KAAK,IAAI;AAAA,QACf,QAAQ,uBAAuB,KAAK,eAAe;AAAA,MACrD,CAAC;AACD;AAAA,IACF;AACA,SAAK,mBAAmB;AAMxB,QAAI,KAAK,gBAAgB;AACvB,mBAAa,KAAK,cAAc;AAChC,WAAK,iBAAiB;AAAA,IACxB;AAIA,UAAM,OAAO,KAAK;AAAA,MAChB,aAAY,0BAA0B,KAAK,KAAK;AAAA,MAChD,aAAY;AAAA,IACd;AACA,UAAM,SAAS,OAAO,cAAc,UAAU,iBAAiB,KAAK,OAAO,IAAI,IAAI;AACnF,UAAM,QAAQ,KAAK,IAAI,KAAK,KAAK,MAAM,OAAO,MAAM,CAAC;AACrD,SAAK,iBAAiB,WAAW,MAAM;AACrC,WAAK,iBAAiB;AACtB,WAAK,KAAK,iBAAiB,IAAI;AAAA,IACjC,GAAG,KAAK;AAAA,EACV;AAAA,EAEA,MAAc,iBAAiB,MAAiC;AAC9D,SAAK,mBAAmB;AACxB,SAAK;AACL,SAAK,WAAW;AAChB,SAAK,gBAAgB,MAAM,aAAa,WAAW;AACnD,UAAM,KAAK,eAAe,IAAI;AAAA,EAChC;AAAA,EAEQ,cAAc,MAAkB,gBAAgB,MAAY;AAClE,UAAM,aAAa,KAAK,cAAc,IAAI;AAC1C,eAAW,gBAAgB,KAAK,IAAI;AACpC,QAAI,cAAe,YAAW,sBAAsB;AAAA,EACtD;AAAA,EAEQ,cACN,MACA,aACA,QACA,YACM;AACN,UAAM,aAAa,KAAK,cAAc,IAAI;AAC1C,UAAM,aAAa,oBAAoB,MAAM;AAC7C,eAAW,gBAAgB,KAAK,IAAI;AACpC,eAAW,kBAAkB;AAC7B,eAAW,aAAa;AACxB,eAAW;AACX,eAAW,SAAS,WAAW;AAC/B,SAAK,gBAAgB,MAAM,WAAW,YAAY,aAAa,UAAU;AAAA,EAC3E;AAAA,EAEQ,gBACN,MACA,MACA,QACA,aACA,YACA,SAAS,MACH;AACN,UAAM,aAAa,KAAK,cAAc,IAAI;AAC1C,UAAM,aAAa,eAAe,KAAK,OAAO,YAAY,KAAK,IAAI,YAAY,KAAK;AACpF,UAAM,SAAS,yBAAyB,YAAY,KAAK,IAAI,QAAQ,UAAU;AAC/E,UAAM,QAA2B;AAAA,MAC/B,YAAY,KAAK,IAAI;AAAA,MACrB;AAAA,MACA,IAAI,KAAK,IAAI;AAAA,MACb,iBAAiB,KAAK;AAAA,MACtB,aAAa,sBAAsB,YAAY,MAAM;AAAA,IACvD;AACA,QAAI,WAAW,OAAW,OAAM,SAAS,oBAAoB,MAAM;AACnE,QAAI,gBAAgB,OAAW,OAAM,cAAc;AACnD,QAAI,eAAe,OAAW,OAAM,aAAa,KAAK,IAAI,GAAG,KAAK,MAAM,UAAU,CAAC;AACnF,QAAI,QAAQ;AACV,kBAAY,WAAW,cAAc,OAAO,qBAAqB,aAAa;AAAA,IAChF;AACA,eAAW,YAAY,KAAK,oBAAoB;AAC9C,UAAI;AACF,iBAAS,EAAE,GAAG,MAAM,CAAC;AAAA,MACvB,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGQ,cAAc,MAA2C;AAC/D,QAAI,CAAC,KAAK,WAAY,MAAK,aAAa,8BAA8B;AACtE,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAc,eAAe,MAAiC;AAC5D,UAAM,eAAe,cAAc,UAAU;AAC7C,QAAI,UAAU;AACd,WAAO,UAAU,cAAc;AAC7B;AACA,YAAM,YAAY,KAAK,IAAI;AAC3B,WAAK,QAAQ,YAAY,IAAI,eAAe;AAC5C,WAAK,WAAW;AAChB,UAAI;AACJ,UAAI;AACJ,UAAI;AACF,iBAAS,IAAI,UAAU;AAAA,UACrB,MAAM,KAAK,IAAI;AAAA,UACf,WAAW,KAAK,IAAI;AAAA,UACpB,SAAS,KAAK,IAAI;AAAA,UAClB,MAAM,KAAK,IAAI;AAAA,UACf,KAAK,KAAK,IAAI;AAAA,UACd,KAAK,KAAK,IAAI;AAAA,UACd,SAAS,KAAK,IAAI;AAAA,UAClB,kBAAkB,KAAK,IAAI;AAAA,UAC3B,kBAAkB,KAAK,IAAI;AAAA,UAC3B,gBAAgB,KAAK,IAAI;AAAA,UACzB,uBAAuB,KAAK,+BAA+B,KAAK,GAAG;AAAA,QACrE,CAAC;AACD,YAAI,KAAK,IAAI,cAAc,SAAS;AAClC,iBAAO,gBAAgB,KAAK,WAAW;AAAA,QACzC,OAAO;AAIL,4BAAkB,MAAM,KAAK,sBAAsB,KAAK,IAAI,IAAI;AAChE,iBAAO,sBAAsB,eAAe;AAAA,QAC9C;AAEA,eAAO,wBAAwB,KAAK,cAAc;AAClD,aAAK,oBAAoB,MAAM;AAC/B,cAAM,OAAO,QAAQ;AAIrB,YAAI,KAAK,UAAU,KAAK,WAAW,QAAQ;AACzC,gBAAM,QAAQ,KAAK;AACnB,gBAAM,kBAAkB,KAAK;AAC7B,eAAK,OAAO,mBAAmB,KAAK,WAAW;AAC/C,cAAI,gBAAiB,OAAM,yBAAyB,eAAe;AACnE,gBAAM,2BAA2B,KAAK,cAAc;AACpD,eAAK,uBAAuB,KAAK;AACjC,gBAAM,MAAM,EAAE,MAAM,MAAM;AAAA,UAE1B,CAAC;AAAA,QACH;AACA,aAAK,SAAS;AACd,aAAK,eAAe;AACpB,cAAM,cAAc,KAAK,kBAAkB,KAAK,UAAU;AAC1D,aAAK,QAAQ;AAGb,aAAK,kBAAkB;AACvB,cAAM,KAAK;AACX,cAAM,aAAa,GAAG,UAAU;AAChC,cAAM,KAAK,qBAAqB,MAAM,EAAE;AAExC,cAAM,KAAK,0BAA0B,IAAI;AACzC,aAAK,WAAW,MAAM,YAAY,EAAE;AACpC,cAAM,aAAa,KAAK,IAAI,IAAI;AAChC;AAAA,UACE,KAAK,WAAW;AAAA,UAChB;AAAA,UACA,qBAAqB;AAAA,QACvB;AACA,aAAK,cAAc,OAAO,KAAK,WAAW,iBAAiB,KAAK,SAAS;AACzE,aAAK;AAAA,UACH;AAAA,UACA,cAAc,cAAc;AAAA,UAC5B;AAAA,UACA;AAAA,UACA;AAAA,QACF;AACA,aAAK,WAAW,KAAK,IAAI;AACzB,YAAI,KAAK,KAAM,MAAK,gBAAgB;AACpC,aAAK,OAAO,KAAK,cAAc,2BAA2B,wBAAwB;AAAA,UAChF,MAAM,KAAK,IAAI;AAAA,UACf,WAAW,KAAK,UAAU;AAAA,QAC5B,CAAC;AACD;AAAA,MACF,SAAS,KAAK;AACZ,aAAK,cAAc,MAAM,aAAa,0BAA0B,KAAK,IAAI,IAAI,SAAS;AACtF,aAAK,IAAI,KAAK,eAAe,KAAK,IAAI,IAAI,qBAAqB,OAAO,WAAW,GAAG;AACpF,YAAI,QAAQ;AACV,iBAAO,mBAAmB,KAAK,WAAW;AAC1C,cAAI,gBAAiB,QAAO,yBAAyB,eAAe;AACpE,iBAAO,2BAA2B,KAAK,cAAc;AACrD,eAAK,uBAAuB,MAAM;AAClC,gBAAM,OAAO,MAAM,EAAE,MAAM,MAAM;AAAA,UAEjC,CAAC;AAAA,QACH;AACA,YAAI,WAAW,cAAc;AAC3B,eAAK,IAAI;AAAA,YACP,eAAe,KAAK,IAAI,IAAI,6BAA6B,YAAY;AAAA,YACrE;AAAA,UACF;AACA,eAAK,QAAQ;AACb,eAAK,SAAS;AAMd,cAAI,KAAK,gBAAgB;AACvB,yBAAa,KAAK,cAAc;AAChC,iBAAK,iBAAiB;AAAA,UACxB;AACA,eAAK,mBAAmB;AACxB,eAAK,OAAO,KAAK,2BAA2B;AAAA,YAC1C,MAAM,KAAK,IAAI;AAAA,YACf,QAAQ,eAAe,QAAQ,IAAI,UAAU;AAAA,UAC/C,CAAC;AACD;AAAA,QACF;AACA,cAAM,QAAQ,MAAM,KAAK;AACzB,cAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,KAAK,CAAC;AAAA,MAC/C;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAM,oBAAoB;AAC1B,IAAM,oBAAoB;AAE1B,eAAe,aACb,MACA,QACiB;AACjB,QAAM,QAAgB,CAAC;AACvB,QAAM,cAAc,oBAAI,IAAY;AACpC,MAAI;AACJ,WAAS,aAAa,GAAG,aAAa,mBAAmB,cAAc;AACrE,UAAM,OAAO,MAAM,KAAK,MAAM;AAC9B,UAAM,KAAK,GAAG,OAAO,IAAI,CAAC;AAC1B,QAAI,MAAM,SAAS,mBAAmB;AACpC,YAAM,IAAI,MAAM,uBAAuB,iBAAiB,QAAQ;AAAA,IAClE;AACA,UAAM,OAAO,KAAK;AAClB,QAAI,CAAC,KAAM,QAAO;AAClB,QAAI,YAAY,IAAI,IAAI,EAAG,OAAM,IAAI,MAAM,gCAAgC,IAAI,GAAG;AAClF,gBAAY,IAAI,IAAI;AACpB,aAAS;AAAA,EACX;AACA,QAAM,IAAI,MAAM,uBAAuB,iBAAiB,QAAQ;AAClE;AAEA,SAAS,aAAgB,SAAmB;AAC1C,SAAO,gBAAgB,OAAO;AAChC;AAEA,SAAS,gBAAgB,MAAsC;AAC7D,SAAO;AAAA,IACL,MAAM,KAAK,IAAI;AAAA,IACf,OAAO,KAAK;AAAA,IACZ,gBAAgB,KAAK,iBAAiB,gBAAgB,KAAK,cAAc,IAAI;AAAA,IAC7E,WAAW,KAAK,YAAY,aAAa,KAAK,SAAS,IAAI;AAAA,IAC3D,mBAAmB,KAAK,oBAAoB,aAAa,KAAK,iBAAiB,IAAI;AAAA,IACnF,SAAS,KAAK,UAAU,aAAa,KAAK,OAAO,IAAI;AAAA,EACvD;AACF;;;AEnwCA,SAAS,oBAA+D;AACxE,SAAS,iBAAAC,sBAAqB;AAC9B,SAAS,kBAAAC,uBAAsB;AAkF/B,IAAM,cAAc;AACpB,IAAM,kBAAkB;AACxB,IAAM,mBAAmB;AACzB,IAAM,iBAAiB;AAEhB,IAAM,YAAN,MAAgB;AAAA,EACJ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEjB,YAAY,MAAwB;AAClC,SAAK,OAAO,KAAK;AACjB,SAAK,aAAa,KAAK,cAAc;AAAA,MACnC,MAAM,cAAc,YAAY;AAAA,MAChC,SAAS,cAAc,YAAY;AAAA,IACrC;AACA,SAAK,SAAS,KAAK;AACnB,SAAK,YAAY,gBAAgB,KAAK,aAAa,CAAC,CAAC;AACrD,SAAK,UAAU,gBAAgB,KAAK,WAAW,CAAC,CAAC;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,cAAc,KAAqC;AACvD,UAAM,OAAO,IAAI,KAAK;AACtB,QAAI,CAAC,KAAM,QAAO;AAElB,QAAI;AACJ,QAAI;AACF,YAAM,KAAK,MAAM,IAAI;AAAA,IACvB,QAAQ;AACN,aAAO,KAAK,YAAY,MAAM,aAAa,aAAa;AAAA,IAC1D;AAEA,QAAI,OAAO,QAAQ,YAAY,QAAQ,QAAQ,OAAO,IAAI,WAAW,UAAU;AAC7E,YAAM,KAAK,OAAO,OAAO,QAAQ,WAAY,IAAI,MAAM,OAAQ;AAC/D,aAAO,KAAK,YAAY,MAAM,MAAM,iBAAiB,iBAAiB;AAAA,IACxE;AAEA,UAAM,iBAAiB,IAAI,OAAO,UAAa,IAAI,OAAO;AAI1D,QAAI,gBAAgB;AAClB,aAAO;AAAA,IACT;AAEA,QAAI;AACF,YAAM,SAAS,MAAM,KAAK,SAAS,IAAI,QAAQ,IAAI,MAAM;AACzD,UAAI,WAAW,2BAA2B;AACxC,eAAO,KAAK;AAAA,UACVC,eAAc,IAAI,EAAE;AAAA,UACpB;AAAA,UACA,qBAAqB,IAAI,MAAM;AAAA,QACjC;AAAA,MACF;AACA,aAAO,KAAK,UAAU,EAAE,SAAS,OAAO,IAAI,IAAI,IAAI,OAAO,CAAC;AAAA,IAC9D,SAAS,KAAK;AACZ,YAAM,UAAUC,gBAAe,GAAG;AAClC,WAAK,QAAQ,OAAO,uBAAuB,IAAI,MAAM,YAAY,OAAO,EAAE;AAC1E,aAAO,KAAK,YAAYD,eAAc,IAAI,EAAE,GAAG,gBAAgB,OAAO;AAAA,IACxE;AAAA,EACF;AAAA,EAEA,MAAc,SAAS,QAAgB,QAAmC;AACxE,YAAQ,QAAQ;AAAA,MACd,KAAK;AACH,eAAO;AAAA,UACL,iBAAiB,cAAc;AAAA,UAC/B,cAAc;AAAA,YACZ,OAAO,EAAE,aAAa,MAAM;AAAA,YAC5B,GAAI,KAAK,UAAU,SAAS,IACxB,EAAE,WAAW,EAAE,WAAW,OAAO,aAAa,MAAM,EAAE,IACtD,CAAC;AAAA,YACL,GAAI,KAAK,QAAQ,SAAS,IAAI,EAAE,SAAS,EAAE,aAAa,MAAM,EAAE,IAAI,CAAC;AAAA,UACvE;AAAA,UACA,YAAY,KAAK;AAAA,QACnB;AAAA,MACF,KAAK;AACH,eAAO,CAAC;AAAA,MACV,KAAK,cAAc;AACjB,cAAM,QAAQ,MAAM,KAAK,KAAK,UAAU;AACxC,eAAO,EAAE,MAAM;AAAA,MACjB;AAAA,MACA,KAAK,cAAc;AACjB,cAAM,IAAK,UAAU,CAAC;AACtB,YAAI,OAAO,EAAE,SAAS,UAAU;AAC9B,gBAAM,IAAI,MAAM,qCAAqC;AAAA,QACvD;AACA,cAAM,OACJ,EAAE,aAAa,OAAO,EAAE,cAAc,YAAY,CAAC,MAAM,QAAQ,EAAE,SAAS,IACvE,EAAE,YACH,CAAC;AACP,cAAM,MAAM,MAAM,KAAK,KAAK,SAAS,EAAE,MAAM,IAAI;AACjD,eAAO,EAAE,SAAS,gBAAgB,IAAI,OAAO,GAAG,SAAS,IAAI,QAAQ;AAAA,MACvE;AAAA,MACA,KAAK,kBAAkB;AACrB,YAAI,KAAK,UAAU,WAAW,EAAG,QAAO;AACxC,cAAM,OAAO,SAAS,KAAK,WAAW,MAAM;AAC5C,eAAO;AAAA,UACL,WAAW,KAAK,MAAM,IAAI,CAAC,EAAE,UAAU,WAAW,GAAG,SAAS,MAAM,QAAQ;AAAA,UAC5E,GAAI,KAAK,aAAa,EAAE,YAAY,KAAK,WAAW,IAAI,CAAC;AAAA,QAC3D;AAAA,MACF;AAAA,MACA,KAAK;AACH,YAAI,KAAK,UAAU,WAAW,EAAG,QAAO;AACxC,eAAO,EAAE,mBAAmB,CAAC,EAAE;AAAA,MACjC,KAAK,kBAAkB;AACrB,YAAI,KAAK,UAAU,WAAW,EAAG,QAAO;AACxC,cAAM,MAAM,oBAAoB,QAAQ,OAAO,gBAAgB;AAC/D,cAAM,WAAW,KAAK,UAAU,KAAK,CAAC,cAAc,UAAU,QAAQ,GAAG;AACzE,YAAI,CAAC,SAAU,OAAM,IAAI,MAAM,uBAAuB,GAAG,EAAE;AAC3D,eAAO,EAAE,UAAU,gBAAgB,SAAS,QAAQ,EAAE;AAAA,MACxD;AAAA,MACA,KAAK,gBAAgB;AACnB,YAAI,KAAK,QAAQ,WAAW,EAAG,QAAO;AACtC,cAAM,OAAO,SAAS,KAAK,SAAS,MAAM;AAC1C,eAAO;AAAA,UACL,SAAS,KAAK,MAAM;AAAA,YAClB,CAAC,EAAE,UAAU,WAAW,UAAU,WAAW,GAAG,OAAO,MAAM;AAAA,UAC/D;AAAA,UACA,GAAI,KAAK,aAAa,EAAE,YAAY,KAAK,WAAW,IAAI,CAAC;AAAA,QAC3D;AAAA,MACF;AAAA,MACA,KAAK,eAAe;AAClB,YAAI,KAAK,QAAQ,WAAW,EAAG,QAAO;AACtC,cAAM,OAAO,oBAAoB,QAAQ,QAAQ,aAAa;AAC9D,cAAM,SAAS,KAAK,QAAQ,KAAK,CAAC,cAAc,UAAU,SAAS,IAAI;AACvE,YAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,qBAAqB,IAAI,EAAE;AACxD,cAAM,QAAQ,aAAa,MAAM;AACjC,cAAM,OAAO,aAAa,MAAM,WAAW,GAAG,uBAAuB;AACrE,mBAAW,YAAY,OAAO,aAAa,CAAC,GAAG;AAC7C,cAAI,SAAS,YAAY,KAAK,SAAS,IAAI,MAAM,QAAW;AAC1D,kBAAM,IAAI,MAAM,WAAW,IAAI,wBAAwB,SAAS,IAAI,GAAG;AAAA,UACzE;AAAA,QACF;AACA,cAAM,WAAW,OAAO,WACpB;AAAA,UACE;AAAA,YACE,MAAM;AAAA,YACN,SAAS,EAAE,MAAM,QAAQ,MAAM,qBAAqB,OAAO,UAAU,IAAI,EAAE;AAAA,UAC7E;AAAA,QACF,IACA,gBAAgB,OAAO,YAAY,CAAC,CAAC;AACzC,eAAO,EAAE,aAAa,OAAO,aAAa,SAAS;AAAA,MACrD;AAAA,MACA;AACE,eAAO;AAAA,IACX;AAAA,EACF;AAAA,EAEQ,YAAY,IAA4B,MAAc,SAAyB;AACrF,WAAO,KAAK,UAAU,EAAE,SAAS,OAAO,IAAI,OAAO,EAAE,MAAM,QAAQ,EAAE,CAAC;AAAA,EACxE;AACF;AAEA,IAAM,mBAAmB;AAEzB,SAAS,SAAY,OAAY,QAAkE;AACjG,QAAM,SAAS,aAAa,MAAM,EAAE,QAAQ;AAC5C,MAAI,SAAS;AACb,MAAI,WAAW,QAAW;AACxB,QAAI,OAAO,WAAW,YAAY,CAAC,QAAQ,KAAK,MAAM,GAAG;AACvD,YAAM,IAAI,MAAM,6DAA6D;AAAA,IAC/E;AACA,aAAS,OAAO,MAAM;AACtB,QAAI,CAAC,OAAO,cAAc,MAAM,EAAG,OAAM,IAAI,MAAM,oCAAoC;AAAA,EACzF;AACA,QAAM,OAAO,MAAM,MAAM,QAAQ,SAAS,gBAAgB;AAC1D,QAAM,OAAO,SAAS,KAAK;AAC3B,SAAO;AAAA,IACL,OAAO;AAAA,IACP,GAAI,OAAO,MAAM,SAAS,EAAE,YAAY,OAAO,IAAI,EAAE,IAAI,CAAC;AAAA,EAC5D;AACF;AAEA,SAAS,aAAa,QAA0C;AAC9D,SAAO,UAAU,OAAO,WAAW,YAAY,CAAC,MAAM,QAAQ,MAAM,IAC/D,SACD,CAAC;AACP;AAEA,SAAS,oBAAoB,QAAiB,OAAe,QAAwB;AACnF,QAAM,QAAQ,aAAa,MAAM,EAAE,KAAK;AACxC,MAAI,OAAO,UAAU,YAAY,MAAM,WAAW,GAAG;AACnD,UAAM,IAAI,MAAM,GAAG,MAAM,iCAAiC,KAAK,GAAG;AAAA,EACpE;AACA,SAAO;AACT;AAEA,SAAS,aAAa,OAAgB,OAAuC;AAC3E,MAAI,UAAU,OAAW,QAAO,CAAC;AACjC,MAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAAG;AAC/D,UAAM,IAAI,MAAM,GAAG,KAAK,oBAAoB;AAAA,EAC9C;AACA,QAAM,SAAiC,CAAC;AACxC,aAAW,CAAC,KAAK,IAAI,KAAK,OAAO,QAAQ,KAAgC,GAAG;AAC1E,QAAI,OAAO,SAAS,SAAU,OAAM,IAAI,MAAM,GAAG,KAAK,IAAI,GAAG,mBAAmB;AAChF,WAAO,GAAG,IAAI;AAAA,EAChB;AACA,SAAO;AACT;AAEA,SAAS,qBAAqB,UAAkB,MAAsC;AACpF,SAAO,SAAS,QAAQ,uCAAuC,CAAC,QAAQ,SAAiB;AACvF,UAAM,QAAQ,KAAK,IAAI;AACvB,QAAI,UAAU,OAAW,OAAM,IAAI,MAAM,qCAAqC,IAAI,GAAG;AACrF,WAAO;AAAA,EACT,CAAC;AACH;AAEA,IAAM,4BAA4B,uBAAO,kBAAkB;AAGpD,SAAS,gBAAgB,SAAyD;AACvF,MAAI,OAAO,YAAY,SAAU,QAAO,CAAC,EAAE,MAAM,QAAQ,MAAM,QAAQ,CAAC;AACxE,MAAI,MAAM,QAAQ,OAAO,GAAG;AAE1B,UAAM,YAAY,QAAQ;AAAA,MACxB,CAAC,MAAM,KAAK,OAAO,MAAM,YAAa,EAAqC,SAAS;AAAA,IACtF;AACA,QAAI,UAAW,QAAO;AACtB,WAAO,CAAC,EAAE,MAAM,QAAQ,MAAM,QAAQ,IAAI,CAAC,MAAM,cAAc,CAAC,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC;AAAA,EACjF;AACA,MAAI,YAAY,UAAa,YAAY,KAAM,QAAO,CAAC,EAAE,MAAM,QAAQ,MAAM,GAAG,CAAC;AACjF,SAAO,CAAC,EAAE,MAAM,QAAQ,MAAM,cAAc,OAAO,EAAE,CAAC;AACxD;AAEA,SAAS,cAAc,GAAoB;AACzC,MAAI,OAAO,MAAM,SAAU,QAAO;AAClC,MAAI;AACF,WAAO,KAAK,UAAU,CAAC;AAAA,EACzB,QAAQ;AACN,WAAO,OAAO,CAAC;AAAA,EACjB;AACF;AAmBO,SAAS,WAAW,QAAmB,OAA0B,CAAC,GAAqB;AAC5F,QAAM,QAA+B,KAAK,SAAS,QAAQ;AAC3D,QAAM,SAAS,KAAK,UAAU,QAAQ;AACtC,MAAI,SAAS;AACb,MAAI,SAAS;AACb,MAAI,iBAAiB;AAErB,MAAI,aAA4B,QAAQ,QAAQ;AAEhD,QAAM,YAAY,CAAC,MAAc;AAC/B,iBAAa,WACV;AAAA,MACC,MACE,IAAI,QAAc,CAAC,YAAY;AAC7B,eAAO,MAAM,GAAG,CAAC;AAAA,GAAM,MAAM,QAAQ,CAAC;AAAA,MACxC,CAAC;AAAA,IACL,EACC,MAAM,CAAC,QAAQ;AACd,YAAM,MAAMC,gBAAe,GAAG;AAC9B,cAAQ;AAAA,QACN,KAAK,UAAU;AAAA,UACb,OAAO;AAAA,UACP,OAAO;AAAA,UACP,SAAS;AAAA,UACT,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QACpC,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAAA,EACL;AAEA,QAAM,SAAS,CAAC,UAA2B;AAKzC,QAAI,eAAgB;AACpB,cAAU,OAAO,UAAU,WAAW,QAAQ,MAAM,SAAS,MAAM;AACnE,QAAI,OAAO,SAAS,eAAe;AACjC,uBAAiB;AACjB,eAAS;AACT,cAAQ;AAAA,QACN,KAAK,UAAU;AAAA,UACb,OAAO;AAAA,UACP,OAAO;AAAA,UACP,SAAS,uBAAuB,aAAa;AAAA,UAC7C,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QACpC,CAAC;AAAA,MACH;AAKA,UAAI;AACF,QAAC,MAAiC,QAAQ;AAC1C,QAAC,MAAmC,UAAU;AAAA,MAChD,QAAQ;AAAA,MAER;AACA,YAAM;AACN;AAAA,IACF;AACA,QAAI,MAAM,OAAO,QAAQ,IAAI;AAC7B,WAAO,QAAQ,IAAI;AACjB,YAAM,OAAO,OAAO,MAAM,GAAG,GAAG;AAChC,eAAS,OAAO,MAAM,MAAM,CAAC;AAC7B,YAAM,OAAO,QAAQ,IAAI;AACzB,UAAI,CAAC,KAAK,KAAK,EAAG;AAClB,WAAK,OACF,cAAc,IAAI,EAClB,KAAK,CAAC,QAAQ;AAMb,YAAI,QAAQ,KAAM,WAAU,GAAG;AAAA,MACjC,CAAC,EACA,MAAM,CAAC,QAAQ;AAGd,gBAAQ;AAAA,UACN,KAAK,UAAU;AAAA,YACb,OAAO;AAAA,YACP,OAAO;AAAA,YACP,SAASA,gBAAe,GAAG;AAAA,YAC3B,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,UACpC,CAAC;AAAA,QACH;AAAA,MACF,CAAC;AAAA,IACL;AAAA,EACF;AAEA,MAAI;AAMJ,QAAM,OAAO,IAAI,QAAc,CAAC,YAAY;AAC1C,kBAAc,MAAM;AAElB,WAAK,WAAW,KAAK,MAAM,QAAQ,CAAC;AAAA,IACtC;AAAA,EACF,CAAC;AAED,QAAM,QAAQ,MAAM;AAClB,QAAI,OAAQ;AACZ,aAAS;AACT,UAAM,IAAI,QAAQ,MAAM;AACxB,gBAAY;AAAA,EACd;AAEA,QAAM,GAAG,QAAQ,MAAM;AACvB,QAAM,KAAK,OAAO,KAAK;AACvB,QAAM,KAAK,SAAS,KAAK;AACzB,MAAI,OAAQ,MAAkC,WAAW,YAAY;AACnE,IAAC,MAAiC,OAAO;AAAA,EAC3C;AAEA,SAAO;AAAA,IACL,OAAO,MAAM;AACX,YAAM;AAAA,IACR;AAAA,IACA;AAAA,EACF;AACF;AAIA,IAAM,gBAAgB,IAAI,OAAO;AAuBjC,SAAS,eAAe,MAAuB;AAC7C,SAAO,SAAS,eAAe,SAAS,SAAS,SAAS;AAC5D;AAWO,SAAS,UACd,QACA,OAAyB,CAAC,GACA;AAC1B,QAAM,OAAO,KAAK,QAAQ;AAC1B,QAAM,OAAO,KAAK,QAAQ;AAC1B,QAAM,QAAQ,KAAK;AACnB,QAAM,MAAM,KAAK;AAEjB,MAAI,CAAC,eAAe,IAAI,KAAK,CAAC,OAAO;AACnC,WAAO,QAAQ;AAAA,MACb,IAAI;AAAA,QACF,qDAAqD,IAAI;AAAA,MAE3D;AAAA,IACF;AAAA,EACF;AAEA,QAAM,aAAa,aAAa,CAAC,KAAsB,QAAwB;AAC7E,SAAK,kBAAkB,QAAQ,KAAK,KAAK,OAAO,GAAG;AAAA,EACrD,CAAC;AAED,SAAO,IAAI,QAAyB,CAAC,SAAS,WAAW;AACvD,eAAW,KAAK,SAAS,MAAM;AAC/B,eAAW,OAAO,MAAM,MAAM,MAAM;AAClC,iBAAW,eAAe,SAAS,MAAM;AACzC,YAAM,OAAO,WAAW,QAAQ;AAChC,YAAM,YAAY,OAAO,SAAS,YAAY,OAAO,KAAK,OAAO;AACjE,YAAM,cAAc,SAAS,QAAQ,UAAU;AAC/C,cAAQ;AAAA,QACN,MAAM;AAAA,QACN;AAAA,QACA,KAAK,UAAU,WAAW,IAAI,SAAS;AAAA,QACvC,OAAO,MACL,IAAI,QAAc,CAAC,SAAS;AAC1B,qBAAW,MAAM,MAAM,KAAK,CAAC;AAAA,QAC/B,CAAC;AAAA,MACL,CAAC;AAAA,IACH,CAAC;AAAA,EACH,CAAC;AACH;AAEA,eAAe,kBACb,QACA,KACA,KACA,OACA,KACe;AACf,QAAM,OAAO,CAAC,QAAgBC,OAAc,OAAO,uBAAuB;AACxE,QAAI,UAAU,QAAQ,EAAE,gBAAgB,KAAK,CAAC;AAC9C,QAAI,IAAIA,KAAI;AAAA,EACd;AAGA,MAAI,IAAI,WAAW,OAAO;AACxB,WAAO,KAAK,KAAK,KAAK,UAAU,EAAE,QAAQ,MAAM,QAAQ,iBAAiB,CAAC,CAAC;AAAA,EAC7E;AACA,MAAI,IAAI,WAAW,QAAQ;AACzB,WAAO,KAAK,KAAK,KAAK,UAAU,EAAE,OAAO,qBAAqB,CAAC,CAAC;AAAA,EAClE;AACA,MAAI,OAAO;AACT,UAAM,OAAO,IAAI,QAAQ,iBAAiB;AAC1C,UAAM,WAAW,UAAU,KAAK;AAChC,QAAI,SAAS,UAAU;AACrB,aAAO,KAAK,KAAK,KAAK,UAAU,EAAE,OAAO,eAAe,CAAC,CAAC;AAAA,IAC5D;AAAA,EACF;AAEA,MAAI,OAAO;AACX,MAAI,WAAW;AACf,MAAI,GAAG,QAAQ,CAAC,UAAkB;AAChC,QAAI,SAAU;AACd,YAAQ,MAAM,SAAS,MAAM;AAC7B,QAAI,KAAK,SAAS,eAAe;AAC/B,iBAAW;AACX,WAAK,KAAK,KAAK,UAAU,EAAE,OAAO,oBAAoB,CAAC,CAAC;AACxD,UAAI,QAAQ;AAAA,IACd;AAAA,EACF,CAAC;AACD,MAAI,GAAG,OAAO,MAAM;AAClB,QAAI,SAAU;AACd,SAAK,OACF,cAAc,IAAI,EAClB,KAAK,CAAC,QAAQ;AAEb,UAAI,QAAQ,KAAM,QAAO,KAAK,KAAK,EAAE;AACrC,aAAO,KAAK,KAAK,GAAG;AAAA,IACtB,CAAC,EACA,MAAM,CAAC,QAAQ;AACd,WAAK,OAAO,2BAA2BD,gBAAe,GAAG,CAAC,EAAE;AAC5D,WAAK,KAAK,KAAK,UAAU,EAAE,OAAO,iBAAiB,CAAC,CAAC;AAAA,IACvD,CAAC;AAAA,EACL,CAAC;AACH;;;AC1lBA,YAAYE,SAAQ;AAEpB,SAAS,aAAa,oBAAoB;AAa1C,IAAM,sBAAsB;AAC5B,IAAM,kBAAkB,OAAO;AAC/B,IAAM,cAAc;AACpB,IAAM,0BAA0B;AAoDzB,IAAM,qBAAN,MAAyB;AAAA,EAC9B,YACmB,UACA,OACjB;AAFiB;AACA;AAAA,EAChB;AAAA,EAFgB;AAAA,EACA;AAAA,EAGnB,MAAM,KAAK,YAAoB,UAA+D;AAC5F,UAAM,oBAAoB,qBAAqB,QAAQ;AACvD,WAAO,aAAa,KAAK,UAAU,YAAY;AAC7C,YAAM,OAAO,MAAM,KAAK,SAAS;AACjC,YAAM,QAAQ,KAAK,QAAQ;AAAA,QACzB,CAAC,cACC,UAAU,eAAe,cAAc,UAAU,aAAa;AAAA,MAClE;AACA,aAAO,QAAQ,KAAK,aAAa,KAAK,IAAI;AAAA,IAC5C,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,KAAK,OAA8C;AACvD,UAAM,aAAa,6BAA6B,KAAK;AACrD,UAAM,aAAa,KAAK,UAAU,YAAY;AAC5C,YAAM,OAAO,MAAM,KAAK,SAAS;AACjC,YAAM,OAAO,KAAK,QAAQ;AAAA,QACxB,CAAC,UACC,EAAE,MAAM,eAAe,WAAW,cAAc,MAAM,aAAa,WAAW;AAAA,MAClF;AACA,WAAK,KAAK,KAAK,aAAa,UAAU,CAAC;AACvC,UAAI,KAAK,SAAS;AAChB,cAAM,IAAI,MAAM,2BAA2B,WAAW,UAAU;AAClE,YAAM,KAAK,UAAU,IAAI;AAAA,IAC3B,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,OAAO,YAAoB,UAAoC;AACnE,UAAM,oBAAoB,qBAAqB,QAAQ;AACvD,WAAO,aAAa,KAAK,UAAU,YAAY;AAC7C,YAAM,OAAO,MAAM,KAAK,SAAS;AACjC,YAAM,OAAO,KAAK,QAAQ;AAAA,QACxB,CAAC,UAAU,EAAE,MAAM,eAAe,cAAc,MAAM,aAAa;AAAA,MACrE;AACA,UAAI,KAAK,WAAW,KAAK,QAAQ,OAAQ,QAAO;AAChD,YAAM,KAAK,UAAU,IAAI;AACzB,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAAA,EAEA,MAAc,WAAoC;AAChD,QAAI;AACJ,QAAI;AACF,YAAMC,QAAO,MAAS,SAAK,KAAK,QAAQ;AACxC,UAAIA,MAAK,OAAO,gBAAiB,OAAM,IAAI,MAAM,oCAAoC;AACrF,YAAM,MAAS,aAAS,KAAK,UAAU,MAAM;AAAA,IAC/C,SAAS,OAAO;AACd,UAAK,MAAgC,SAAS,SAAU,QAAO,UAAU;AACzE,YAAM;AAAA,IACR;AACA,QAAI;AACJ,QAAI;AACF,eAAS,KAAK,MAAM,GAAG;AAAA,IACzB,QAAQ;AACN,YAAM,IAAI,MAAM,mCAAmC;AAAA,IACrD;AACA,WAAO,kBAAkB,MAAM;AAAA,EACjC;AAAA,EAEA,MAAc,UAAU,SAAuD;AAC7E,UAAM,OAAuB;AAAA,MAC3B,SAAS;AAAA,MACT,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MAClC;AAAA,IACF;AACA,UAAM,YAAY,KAAK,UAAU,GAAG,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;AAAA,GAAM,EAAE,MAAM,IAAM,CAAC;AAAA,EACxF;AAAA,EAEQ,aAAa,OAA4D;AAC/E,UAAM,cAAc,KAAK,MAAM,QAAQ,MAAM,SAAS,WAAW;AACjE,UAAM,eAAe,MAAM,SAAS,eAChC,KAAK,MAAM,QAAQ,MAAM,SAAS,YAAY,IAC9C;AACJ,QACE,CAAC,KAAK,MAAM,YAAY,WAAW,KAClC,gBAAgB,CAAC,KAAK,MAAM,YAAY,YAAY,GACrD;AACA,YAAM,IAAI,MAAM,oDAAoD;AAAA,IACtE;AACA,WAAO;AAAA,MACL,YAAY,MAAM;AAAA,MAClB,UAAU,MAAM;AAAA,MAChB,UAAU,MAAM;AAAA,MAChB,qBAAqB,MAAM;AAAA,MAC3B;AAAA,MACA;AAAA,MACA,WAAW,MAAM,SAAS,aAAa;AAAA,MACvC,WAAW,MAAM,SAAS;AAAA,MAC1B,QAAQ,CAAC,GAAI,MAAM,SAAS,UAAU,CAAC,CAAE;AAAA,MACzC,WAAW,MAAM;AAAA,IACnB;AAAA,EACF;AAAA,EAEQ,aAAa,OAA4D;AAC/E,QACE,CAAC,KAAK,MAAM,YAAY,MAAM,WAAW,KACxC,MAAM,iBAAiB,UAAa,CAAC,KAAK,MAAM,YAAY,MAAM,YAAY,GAC/E;AACA,YAAM,IAAI,MAAM,+CAA+C;AAAA,IACjE;AACA,UAAM,QAAgC;AAAA,MACpC,YAAY,MAAM;AAAA,MAClB,UAAU,MAAM;AAAA,MAChB,UAAU,MAAM;AAAA,MAChB,qBAAqB,MAAM;AAAA,MAC3B,UAAU;AAAA,QACR,aAAa,KAAK,MAAM,QAAQ,MAAM,WAAW;AAAA,QACjD,cAAc,MAAM,eAAe,KAAK,MAAM,QAAQ,MAAM,YAAY,IAAI;AAAA,QAC5E,WAAW,MAAM;AAAA,QACjB,UAAU,MAAM;AAAA,QAChB,WAAW,MAAM;AAAA,QACjB,QAAQ,CAAC,GAAG,MAAM,MAAM;AAAA,MAC1B;AAAA,MACA,WAAW,MAAM;AAAA,IACnB;AACA,WAAO,6BAA6B,KAAK;AAAA,EAC3C;AACF;AAEO,IAAM,qCAAN,MAA6E;AAAA,EAKlF,YAA6B,SAAoD;AAApD;AAC3B,SAAK,WAAW,qBAAqB,QAAQ,QAAQ;AACrD,SAAK,gBAAgB,QAAQ,iBAAiB;AAAA,EAChD;AAAA,EAH6B;AAAA,EAJrB;AAAA,EACS;AAAA,EACA;AAAA,EAOjB,MAAM,eAAe,SAAoE;AACvF,SAAK,cAAc,OAAO;AAC1B,QAAI,QAAQ,MAAM,KAAK,QAAQ,MAAM,KAAK,KAAK,QAAQ,YAAY,KAAK,QAAQ;AAChF,QAAI,CAAC,MAAO,QAAO;AACnB,QACE,MAAM,SAAS,cAAc,UAC7B,MAAM,SAAS,aAAa,KAAK,IAAI,IAAI,KAAK,eAC9C;AACA,cAAQ,MAAM,KAAK,QAAQ,OAAO,QAAQ,MAAM;AAAA,IAClD;AACA,QAAI,CAAC,MAAO,QAAO;AACnB,QAAI,MAAM,SAAS,cAAc,UAAa,MAAM,SAAS,aAAa,KAAK,IAAI,GAAG;AACpF,WAAK,KAAK,mBAAmB,KAAK;AAClC,aAAO;AAAA,IACT;AACA,gCAA4B,MAAM,UAAU,KAAK,QAAQ;AACzD,WAAO,EAAE,GAAG,MAAM,UAAU,QAAQ,CAAC,GAAI,MAAM,SAAS,UAAU,CAAC,CAAE,EAAE;AAAA,EACzE;AAAA,EAEA,MAAM,mBACJ,WACA,SACkB;AAClB,SAAK,cAAc,OAAO;AAC1B,QAAI,UAAU,aAAa,KAAK,SAAU,QAAO;AACjD,UAAM,QAAQ,MAAM,KAAK,QAAQ,MAAM,KAAK,KAAK,QAAQ,YAAY,KAAK,QAAQ;AAClF,QAAI,CAAC,OAAO,SAAS,cAAc;AACjC,UAAI,MAAO,MAAK,KAAK,mBAAmB,KAAK;AAC7C,aAAO;AAAA,IACT;AACA,WAAQ,MAAM,KAAK,QAAQ,OAAO,QAAQ,MAAM,MAAO;AAAA,EACzD;AAAA,EAEQ,QACN,OACA,QAC6C;AAC7C,QAAI,KAAK,eAAgB,QAAO,KAAK;AACrC,SAAK,iBAAiB,KAAK,aAAa,OAAO,MAAM,EAAE,QAAQ,MAAM;AACnE,WAAK,iBAAiB;AAAA,IACxB,CAAC;AACD,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAc,aACZ,OACA,QAC6C;AAC7C,UAAM,eAAe,MAAM,SAAS;AACpC,QAAI,CAAC,cAAc;AACjB,WAAK,KAAK,mBAAmB,KAAK;AAClC,aAAO;AAAA,IACT;AACA,UAAM,WAAW,MAAM,sBAAsB;AAAA,MAC3C,qBAAqB,MAAM;AAAA,MAC3B,UAAU,MAAM;AAAA,MAChB,UAAU,MAAM;AAAA,MAChB;AAAA,MACA;AAAA,IACF,CAAC;AACD,UAAM,OAAO,6BAA6B;AAAA,MACxC,GAAG;AAAA,MACH;AAAA,MACA,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC,CAAC;AACD,UAAM,KAAK,QAAQ,MAAM,KAAK,IAAI;AAClC,SAAK,KAAK,aAAa,IAAI;AAC3B,WAAO;AAAA,EACT;AAAA,EAEQ,cAAc,SAAwC;AAC5D,QAAI,QAAQ,eAAe,KAAK,QAAQ,cAAc,QAAQ,aAAa,KAAK,UAAU;AACxF,YAAM,IAAI,MAAM,uEAAuE;AAAA,IACzF;AAAA,EACF;AAAA,EAEQ,KAAK,OAA4C,OAAqC;AAC5F,SAAK,QAAQ,gBAAgB;AAAA,MAC3B,YAAY,MAAM;AAAA,MAClB;AAAA,MACA,UAAU,MAAM;AAAA,MAChB,WAAW,MAAM,SAAS;AAAA,MAC1B,QAAQ,CAAC,GAAI,MAAM,SAAS,UAAU,CAAC,CAAE;AAAA,IAC3C,CAAC;AAAA,EACH;AACF;AAEO,SAAS,iDACd,SAC6E;AAC7E,QAAM,YAAY,oBAAI,IAAgD;AACtE,SAAO,CAAC,WAAW;AACjB,QAAI,OAAO,cAAc,WAAW,CAAC,OAAO,IAAK,QAAO;AACxD,UAAM,WAAW,qBAAqB,OAAO,GAAG;AAChD,UAAM,MAAM,GAAG,OAAO,IAAI,KAAK,QAAQ;AACvC,QAAI,WAAW,UAAU,IAAI,GAAG;AAChC,QAAI,CAAC,UAAU;AACb,iBAAW,IAAI,mCAAmC;AAAA,QAChD,YAAY,OAAO;AAAA,QACnB;AAAA,QACA,OAAO,QAAQ;AAAA,QACf,eAAe,QAAQ;AAAA,QACvB,eAAe,QAAQ;AAAA,MACzB,CAAC;AACD,gBAAU,IAAI,KAAK,QAAQ;AAAA,IAC7B;AACA,WAAO;AAAA,EACT;AACF;AAEA,SAAS,YAA4B;AACnC,SAAO,EAAE,SAAS,qBAAqB,YAAW,oBAAI,KAAK,CAAC,GAAE,YAAY,GAAG,SAAS,CAAC,EAAE;AAC3F;AAEA,SAAS,kBAAkB,OAAgC;AACzD,MACE,CAAC,SAAS,KAAK,KACf,MAAM,SAAS,MAAM,uBACrB,CAAC,MAAM,QAAQ,MAAM,SAAS,CAAC,GAC/B;AACA,UAAM,IAAI,MAAM,2DAA2D;AAAA,EAC7E;AACA,MAAI,MAAM,SAAS,EAAE,SAAS;AAC5B,UAAM,IAAI,MAAM,sCAAsC;AACxD,SAAO;AAAA,IACL,SAAS;AAAA,IACT,WAAW,cAAc,MAAM,WAAW,GAAG,aAAa,GAAG;AAAA,IAC7D,SAAS,MAAM,SAAS,EAAE,IAAI,sBAAsB;AAAA,EACtD;AACF;AAEA,SAAS,uBAAuB,OAA6C;AAC3E,MAAI,CAAC,SAAS,KAAK,EAAG,OAAM,IAAI,MAAM,yCAAyC;AAC/E,QAAM,WAAW,qBAAqB,cAAc,MAAM,UAAU,GAAG,YAAY,IAAK,CAAC;AACzF,QAAM,sBAAsB,uCAAuC,MAAM,qBAAqB,CAAC;AAC/F,QAAM,SAAS,YAAY,MAAM,QAAQ,GAAG,UAAU,GAAG;AACzD,QAAM,YAAY,MAAM,WAAW;AACnC,MAAI,cAAc,WAAc,OAAO,cAAc,YAAY,CAAC,OAAO,SAAS,SAAS,IAAI;AAC7F,UAAM,IAAI,MAAM,mDAAmD;AAAA,EACrE;AACA,SAAO;AAAA,IACL,YAAY,cAAc,MAAM,YAAY,GAAG,cAAc,GAAG;AAAA,IAChE;AAAA,IACA,UAAU,cAAc,MAAM,UAAU,GAAG,YAAY,IAAK;AAAA,IAC5D;AAAA,IACA,aAAa,cAAc,MAAM,aAAa,GAAG,eAAe,KAAM;AAAA,IACtE,cACE,MAAM,cAAc,MAAM,SACtB,SACA,cAAc,MAAM,cAAc,GAAG,gBAAgB,KAAM;AAAA,IACjE,WAAW,cAAc,MAAM,WAAW,GAAG,aAAa,EAAE;AAAA,IAC5D;AAAA,IACA;AAAA,IACA,WAAW,cAAc,MAAM,WAAW,GAAG,aAAa,GAAG;AAAA,EAC/D;AACF;AAEA,SAAS,6BAA6B,OAAuD;AAC3F,QAAM,aAAa,cAAc,MAAM,YAAY,cAAc,GAAG;AACpE,QAAM,WAAW,qBAAqB,MAAM,QAAQ;AACpD,QAAM,sBAAsB,uCAAuC,MAAM,mBAAmB;AAC5F,MAAI,qBAAqB,MAAM,SAAS,QAAQ,MAAM,UAAU;AAC9D,UAAM,IAAI,MAAM,6BAA6B;AAAA,EAC/C;AACA,QAAM,WAAwB;AAAA,IAC5B,GAAG,MAAM;AAAA,IACT;AAAA,IACA,QAAQ,YAAY,MAAM,SAAS,UAAU,CAAC,GAAG,UAAU,GAAG;AAAA,EAChE;AACA,8BAA4B,EAAE,GAAG,UAAU,WAAW,OAAU,GAAG,QAAQ;AAC3E,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,UAAU,cAAc,MAAM,UAAU,YAAY,IAAK;AAAA,IACzD;AAAA,IACA;AAAA,IACA,WAAW,cAAc,MAAM,WAAW,aAAa,GAAG;AAAA,EAC5D;AACF;AAEA,SAAS,SAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEA,SAAS,cAAc,OAAgB,OAAe,WAA2B;AAC/E,MACE,OAAO,UAAU,YACjB,MAAM,WAAW,KACjB,MAAM,SAAS,aACf,SAAS,KAAK,KAAK,GACnB;AACA,UAAM,IAAI,MAAM,0BAA0B,KAAK,cAAc;AAAA,EAC/D;AACA,SAAO;AACT;AAEA,SAAS,YAAY,OAAgB,OAAe,UAA4B;AAC9E,MAAI,CAAC,MAAM,QAAQ,KAAK,KAAK,MAAM,SAAS,UAAU;AACpD,UAAM,IAAI,MAAM,0BAA0B,KAAK,2BAA2B;AAAA,EAC5E;AACA,SAAO,CAAC,GAAG,IAAI,IAAI,MAAM,IAAI,CAAC,UAAU,cAAc,OAAO,OAAO,GAAG,CAAC,CAAC,CAAC;AAC5E;",
6
- "names": ["request", "lookup", "record", "record", "requiredString", "optionalString", "value", "ToolError", "https", "ConfigError", "net", "ConfigError", "randomBytes", "ToolError", "ToolError", "randomBytes", "body", "request", "randomBytes", "path", "createHash", "fs", "createHash", "expectDefined", "toErrorMessage", "expectDefined", "toErrorMessage", "body", "fs", "stat"]
3
+ "sources": ["../src/authorization.ts", "../src/authorization-manager.ts", "../src/client.ts", "../src/constants.ts", "../src/protocol.ts", "../src/tool-schema.ts", "../src/sse-reader.ts", "../src/transport-base.ts", "../src/transport-security.ts", "../src/transport-jsonrpc.ts", "../src/transport-sse.ts", "../src/read-body.ts", "../src/transport-streamable.ts", "../src/content-selection.ts", "../src/manage.ts", "../src/manifest-cache.ts", "../src/operations.ts", "../src/registry.ts", "../src/wrap-tool.ts", "../src/server.ts", "../src/token-store.ts"],
4
+ "sourcesContent": ["import { createHash, randomBytes, timingSafeEqual } from 'node:crypto';\nimport * as dns from 'node:dns/promises';\nimport * as http from 'node:http';\nimport * as https from 'node:https';\nimport * as net from 'node:net';\nimport { isPrivateIPv4, isPrivateIPv6 } from '@wrongstack/core/utils';\n\nexport interface MCPAccessToken {\n accessToken: string;\n tokenType?: string | undefined;\n /** Exact canonical MCP resource URI this token was minted for. */\n resource: string;\n expiresAt?: number | undefined;\n scopes?: string[] | undefined;\n}\n\nexport interface MCPAuthorizationContext {\n serverName: string;\n resource: string;\n signal?: AbortSignal | undefined;\n}\n\nexport interface MCPAuthorizationChallenge {\n status: 401;\n resource: string;\n resourceMetadataUrl?: string | undefined;\n scopes: string[];\n rawScheme: 'Bearer';\n}\n\nexport interface MCPProtectedResourceMetadata {\n resource: string;\n authorizationServers: string[];\n scopesSupported: string[];\n}\n\nexport interface MCPAuthorizationServerMetadata {\n issuer: string;\n authorizationEndpoint: string;\n tokenEndpoint: string;\n registrationEndpoint?: string | undefined;\n scopesSupported: string[];\n}\n\nexport interface MCPAuthorizationDiscoveryResult {\n resourceMetadataUrl: string;\n authorizationServerMetadataUrl: string;\n protectedResource: MCPProtectedResourceMetadata;\n authorizationServer: MCPAuthorizationServerMetadata;\n}\n\nexport type MCPAuthorizationJsonFetcher = (\n url: string,\n signal?: AbortSignal | undefined,\n) => Promise<unknown | undefined>;\n\nexport interface MCPAuthorizationDiscoveryOptions {\n challengeHeader?: string | null | undefined;\n signal?: AbortSignal | undefined;\n timeoutMs?: number | undefined;\n maxResponseBytes?: number | undefined;\n lookup?: BrowserCompatibleDnsLookup | undefined;\n /** Test/host override. Production callers should use the pinned default. */\n fetchJson?: MCPAuthorizationJsonFetcher | undefined;\n}\n\nexport interface MCPAuthorizationSession {\n authorizationUrl: string;\n state: string;\n codeVerifier: string;\n redirectUri: string;\n clientId: string;\n resource: string;\n}\n\nexport interface MCPTokenSet extends MCPAccessToken {\n refreshToken?: string | undefined;\n}\n\nexport interface MCPAuthorizationRequestOptions {\n authorizationServer: MCPAuthorizationServerMetadata;\n clientId: string;\n redirectUri: string;\n resource: string;\n scopes?: readonly string[] | undefined;\n}\n\nexport interface MCPTokenExchangeOptions {\n authorizationServer: MCPAuthorizationServerMetadata;\n clientId: string;\n redirectUri: string;\n resource: string;\n code: string;\n codeVerifier: string;\n signal?: AbortSignal | undefined;\n timeoutMs?: number | undefined;\n maxResponseBytes?: number | undefined;\n lookup?: BrowserCompatibleDnsLookup | undefined;\n}\n\nexport interface MCPTokenRefreshOptions {\n authorizationServer: MCPAuthorizationServerMetadata;\n clientId: string;\n resource: string;\n refreshToken: string;\n signal?: AbortSignal | undefined;\n timeoutMs?: number | undefined;\n maxResponseBytes?: number | undefined;\n lookup?: BrowserCompatibleDnsLookup | undefined;\n}\n\ntype BrowserCompatibleDnsLookup = (\n hostname: string,\n) => Promise<readonly { address: string; family: number }[]>;\n\n/**\n * Host-owned bridge to vault-backed OAuth state. The MCP package never stores\n * access or refresh tokens itself and never exposes them through config.\n */\nexport interface MCPAuthorizationProvider {\n getAccessToken(context: MCPAuthorizationContext): Promise<MCPAccessToken | undefined>;\n /** Refresh/discover/reauthorize. Return true to retry the HTTP request once. */\n handleUnauthorized?(\n challenge: MCPAuthorizationChallenge,\n context: MCPAuthorizationContext,\n ): Promise<boolean>;\n}\n\nexport function canonicalMcpResource(rawUrl: string): string {\n let url: URL;\n try {\n url = new URL(rawUrl);\n } catch {\n throw new Error('MCP authorization resource must be an absolute URL');\n }\n if (url.protocol !== 'https:' && !isLoopbackHttp(url)) {\n throw new Error('MCP authorization resource must use HTTPS (except loopback development)');\n }\n if (url.username || url.password || url.hash) {\n throw new Error('MCP authorization resource must not contain credentials or a fragment');\n }\n if (url.pathname === '/' && !url.search) return url.origin;\n return url.toString();\n}\n\nexport function authorizationHeaderForToken(\n token: MCPAccessToken,\n expectedResource: string,\n now = Date.now(),\n): string {\n if (canonicalMcpResource(token.resource) !== expectedResource) {\n throw new Error('MCP access token resource does not match the target server');\n }\n if (token.expiresAt !== undefined && token.expiresAt <= now) {\n throw new Error('MCP access token is expired');\n }\n const tokenType = token.tokenType ?? 'Bearer';\n if (tokenType.toLowerCase() !== 'bearer') {\n throw new Error(`Unsupported MCP OAuth token type \"${tokenType}\"`);\n }\n if (!token.accessToken || token.accessToken.length > 16_384 || /[\\r\\n]/.test(token.accessToken)) {\n throw new Error('MCP access token is empty, oversized, or contains invalid characters');\n }\n return `Bearer ${token.accessToken}`;\n}\n\nexport function parseMcpBearerChallenge(\n header: string | null,\n resource: string,\n): MCPAuthorizationChallenge {\n const challenge: MCPAuthorizationChallenge = {\n status: 401,\n resource,\n scopes: [],\n rawScheme: 'Bearer',\n };\n if (!header) return challenge;\n const bearer = /(?:^|,)\\s*Bearer(?:\\s+|$)/i.exec(header);\n if (!bearer) return challenge;\n const parameters = header.slice(bearer.index + bearer[0].length);\n const resourceMetadata = challengeParameter(parameters, 'resource_metadata');\n if (resourceMetadata) {\n const metadataUrl = validateMetadataUrl(resourceMetadata);\n if (metadataUrl) challenge.resourceMetadataUrl = metadataUrl;\n }\n const scope = challengeParameter(parameters, 'scope');\n if (scope) {\n challenge.scopes = [...new Set(scope.split(/\\s+/).filter(Boolean))].slice(0, 64);\n }\n return challenge;\n}\n\n/** RFC 9728 fallback order for an MCP endpoint when no challenge URL exists. */\nexport function protectedResourceMetadataUrls(resource: string): string[] {\n const url = new URL(canonicalMcpResource(resource));\n const suffix = url.pathname === '/' ? '' : url.pathname;\n const candidates = [\n new URL(`/.well-known/oauth-protected-resource${suffix}`, url.origin).toString(),\n new URL('/.well-known/oauth-protected-resource', url.origin).toString(),\n ];\n return [...new Set(candidates)];\n}\n\n/** RFC 8414 + OIDC discovery order required by the MCP authorization spec. */\nexport function authorizationServerMetadataUrls(issuer: string): string[] {\n const url = secureOAuthUrl(issuer, 'authorization server issuer');\n const suffix = url.pathname === '/' ? '' : url.pathname;\n const candidates = [\n new URL(`/.well-known/oauth-authorization-server${suffix}`, url.origin).toString(),\n new URL(`/.well-known/openid-configuration${suffix}`, url.origin).toString(),\n ];\n if (suffix) {\n candidates.push(\n new URL(\n `${suffix.replace(/\\/$/, '')}/.well-known/openid-configuration`,\n url.origin,\n ).toString(),\n );\n }\n return candidates;\n}\n\nexport function parseProtectedResourceMetadata(\n value: unknown,\n expectedResource: string,\n): MCPProtectedResourceMetadata {\n const metadata = record(value, 'protected resource metadata');\n const resource = canonicalMcpResource(requiredString(metadata['resource'], 'resource'));\n if (resource !== canonicalMcpResource(expectedResource)) {\n throw new Error('MCP protected resource metadata resource does not match the target server');\n }\n const authorizationServers = boundedStringArray(\n metadata['authorization_servers'],\n 'authorization_servers',\n 8,\n ).map((issuer) => secureOAuthUrl(issuer, 'authorization server issuer').toString());\n if (authorizationServers.length === 0) {\n throw new Error('MCP protected resource metadata must declare an authorization server');\n }\n return {\n resource,\n authorizationServers,\n scopesSupported: optionalStringArray(metadata['scopes_supported'], 'scopes_supported', 128),\n };\n}\n\nexport function parseAuthorizationServerMetadata(\n value: unknown,\n expectedIssuer: string,\n): MCPAuthorizationServerMetadata {\n const metadata = record(value, 'authorization server metadata');\n const issuer = secureOAuthUrl(requiredString(metadata['issuer'], 'issuer'), 'issuer').toString();\n if (issuer !== secureOAuthUrl(expectedIssuer, 'expected issuer').toString()) {\n throw new Error('MCP authorization metadata issuer mismatch');\n }\n const methods = boundedStringArray(\n metadata['code_challenge_methods_supported'],\n 'code_challenge_methods_supported',\n 16,\n );\n if (!methods.includes('S256')) {\n throw new Error('MCP authorization server does not advertise required PKCE S256 support');\n }\n const registration = optionalString(metadata['registration_endpoint'], 'registration_endpoint');\n return {\n issuer,\n authorizationEndpoint: secureOAuthUrl(\n requiredString(metadata['authorization_endpoint'], 'authorization_endpoint'),\n 'authorization endpoint',\n ).toString(),\n tokenEndpoint: secureOAuthUrl(\n requiredString(metadata['token_endpoint'], 'token_endpoint'),\n 'token endpoint',\n ).toString(),\n registrationEndpoint: registration\n ? secureOAuthUrl(registration, 'registration endpoint').toString()\n : undefined,\n scopesSupported: optionalStringArray(metadata['scopes_supported'], 'scopes_supported', 128),\n };\n}\n\n/**\n * Re-validate the normalized authorization-server shape before it is accepted\n * from host-owned persistence. PKCE support is established during discovery;\n * this guard protects the persisted endpoints and bounded fields themselves.\n */\nexport function validateMcpAuthorizationServerMetadata(\n value: unknown,\n): MCPAuthorizationServerMetadata {\n const metadata = record(value, 'stored authorization server metadata');\n const registration = optionalString(metadata['registrationEndpoint'], 'registrationEndpoint');\n return {\n issuer: secureOAuthUrl(requiredString(metadata['issuer'], 'issuer'), 'issuer').toString(),\n authorizationEndpoint: secureOAuthUrl(\n requiredString(metadata['authorizationEndpoint'], 'authorizationEndpoint'),\n 'authorization endpoint',\n ).toString(),\n tokenEndpoint: secureOAuthUrl(\n requiredString(metadata['tokenEndpoint'], 'tokenEndpoint'),\n 'token endpoint',\n ).toString(),\n registrationEndpoint: registration\n ? secureOAuthUrl(registration, 'registration endpoint').toString()\n : undefined,\n scopesSupported: optionalStringArray(metadata['scopesSupported'], 'scopesSupported', 128),\n };\n}\n\n/**\n * Discover and validate MCP OAuth metadata without following redirects. The\n * default fetcher resolves once and opens the socket to that exact IP, making\n * discovery resistant to DNS rebinding.\n */\nexport async function discoverMcpAuthorization(\n resource: string,\n options: MCPAuthorizationDiscoveryOptions = {},\n): Promise<MCPAuthorizationDiscoveryResult> {\n const canonicalResource = canonicalMcpResource(resource);\n const resourceUrl = new URL(canonicalResource);\n const allowedLoopbackHostname = isLoopbackHttp(resourceUrl)\n ? unbracket(resourceUrl.hostname).toLowerCase()\n : undefined;\n const fetchJson =\n options.fetchJson ??\n ((url, signal) =>\n requestPinnedJson(url, {\n signal,\n timeoutMs: options.timeoutMs,\n maxResponseBytes: options.maxResponseBytes,\n lookup: options.lookup,\n allowedLoopbackHostname,\n }));\n\n const challenge = parseMcpBearerChallenge(options.challengeHeader ?? null, canonicalResource);\n const resourceCandidates = challenge.resourceMetadataUrl\n ? [challenge.resourceMetadataUrl]\n : protectedResourceMetadataUrls(canonicalResource);\n const resourceDiscovery = await discoverFirst(\n resourceCandidates,\n fetchJson,\n options.signal,\n (value) => parseProtectedResourceMetadata(value, canonicalResource),\n 'protected resource metadata',\n );\n const issuer = resourceDiscovery.value.authorizationServers[0]!;\n const authorizationDiscovery = await discoverFirst(\n authorizationServerMetadataUrls(issuer),\n fetchJson,\n options.signal,\n (value) => parseAuthorizationServerMetadata(value, issuer),\n 'authorization server metadata',\n );\n return {\n resourceMetadataUrl: resourceDiscovery.url,\n authorizationServerMetadataUrl: authorizationDiscovery.url,\n protectedResource: resourceDiscovery.value,\n authorizationServer: authorizationDiscovery.value,\n };\n}\n\nexport function createMcpAuthorizationRequest(\n options: MCPAuthorizationRequestOptions,\n): MCPAuthorizationSession {\n const resource = canonicalMcpResource(options.resource);\n const clientId = boundedCredential(options.clientId, 'client id');\n const redirectUri = validateRedirectUri(options.redirectUri);\n const scopes = validateScopes(options.scopes ?? []);\n const codeVerifier = base64Url(randomBytes(32));\n const codeChallenge = base64Url(createHash('sha256').update(codeVerifier).digest());\n const state = base64Url(randomBytes(32));\n const authorizationUrl = secureOAuthUrl(\n options.authorizationServer.authorizationEndpoint,\n 'authorization endpoint',\n );\n authorizationUrl.searchParams.set('response_type', 'code');\n authorizationUrl.searchParams.set('client_id', clientId);\n authorizationUrl.searchParams.set('redirect_uri', redirectUri);\n authorizationUrl.searchParams.set('state', state);\n authorizationUrl.searchParams.set('code_challenge', codeChallenge);\n authorizationUrl.searchParams.set('code_challenge_method', 'S256');\n authorizationUrl.searchParams.set('resource', resource);\n if (scopes.length > 0) authorizationUrl.searchParams.set('scope', scopes.join(' '));\n return {\n authorizationUrl: authorizationUrl.toString(),\n state,\n codeVerifier,\n redirectUri,\n clientId,\n resource,\n };\n}\n\nexport function parseMcpAuthorizationCallback(\n callbackUrl: string,\n session: Pick<MCPAuthorizationSession, 'redirectUri' | 'state'>,\n): string {\n let callback: URL;\n try {\n callback = new URL(callbackUrl);\n } catch {\n throw new Error('MCP OAuth callback must be an absolute URL');\n }\n const expected = new URL(validateRedirectUri(session.redirectUri));\n if (\n callback.protocol !== expected.protocol ||\n callback.hostname !== expected.hostname ||\n callback.port !== expected.port ||\n callback.pathname !== expected.pathname\n ) {\n throw new Error('MCP OAuth callback redirect URI does not match the authorization session');\n }\n const returnedState = callback.searchParams.get('state') ?? '';\n if (!constantTimeEqual(returnedState, session.state)) {\n throw new Error('MCP OAuth callback state mismatch');\n }\n const oauthError = callback.searchParams.get('error');\n if (oauthError)\n throw new Error(`MCP OAuth authorization failed: ${boundedErrorCode(oauthError)}`);\n return boundedCredential(callback.searchParams.get('code') ?? '', 'authorization code');\n}\n\nexport async function exchangeMcpAuthorizationCode(\n options: MCPTokenExchangeOptions,\n): Promise<MCPTokenSet> {\n const resource = canonicalMcpResource(options.resource);\n const body = new URLSearchParams({\n grant_type: 'authorization_code',\n code: boundedCredential(options.code, 'authorization code'),\n client_id: boundedCredential(options.clientId, 'client id'),\n redirect_uri: validateRedirectUri(options.redirectUri),\n code_verifier: validateCodeVerifier(options.codeVerifier),\n resource,\n }).toString();\n const response = await requestPinnedJson(options.authorizationServer.tokenEndpoint, {\n method: 'POST',\n body,\n headers: { 'content-type': 'application/x-www-form-urlencoded' },\n signal: options.signal,\n timeoutMs: options.timeoutMs,\n maxResponseBytes: options.maxResponseBytes,\n lookup: options.lookup,\n allowedLoopbackHostname: loopbackHostnameForResource(resource),\n });\n if (response === undefined) throw new Error('MCP OAuth token endpoint returned no response');\n return parseTokenResponse(response, resource);\n}\n\nexport async function refreshMcpAccessToken(options: MCPTokenRefreshOptions): Promise<MCPTokenSet> {\n const resource = canonicalMcpResource(options.resource);\n const previousRefreshToken = boundedCredential(options.refreshToken, 'refresh token');\n const body = new URLSearchParams({\n grant_type: 'refresh_token',\n refresh_token: previousRefreshToken,\n client_id: boundedCredential(options.clientId, 'client id'),\n resource,\n }).toString();\n const response = await requestPinnedJson(options.authorizationServer.tokenEndpoint, {\n method: 'POST',\n body,\n headers: { 'content-type': 'application/x-www-form-urlencoded' },\n signal: options.signal,\n timeoutMs: options.timeoutMs,\n maxResponseBytes: options.maxResponseBytes,\n lookup: options.lookup,\n allowedLoopbackHostname: loopbackHostnameForResource(resource),\n });\n if (response === undefined) throw new Error('MCP OAuth token endpoint returned no response');\n const parsed = parseTokenResponse(response, resource);\n return { ...parsed, refreshToken: parsed.refreshToken ?? previousRefreshToken };\n}\n\nfunction challengeParameter(parameters: string, name: string): string | undefined {\n const pattern = new RegExp(\n `(?:^|,)\\\\s*${name}\\\\s*=\\\\s*(?:\"((?:\\\\\\\\.|[^\"\\\\\\\\])*)\"|([^,\\\\s]+))`,\n 'i',\n );\n const match = pattern.exec(parameters);\n const value = match?.[1] ?? match?.[2];\n return value?.replace(/\\\\([\"\\\\])/g, '$1');\n}\n\nfunction validateMetadataUrl(value: string): string | undefined {\n try {\n const url = new URL(value);\n if (url.username || url.password || url.hash) return undefined;\n if (url.protocol !== 'https:' && !isLoopbackHttp(url)) return undefined;\n return url.toString();\n } catch {\n return undefined;\n }\n}\n\nfunction record(value: unknown, label: string): Record<string, unknown> {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error(`MCP ${label} must be an object`);\n }\n return value as Record<string, unknown>;\n}\n\nfunction requiredString(value: unknown, field: string): string {\n if (typeof value !== 'string' || value.length === 0 || value.length > 4_096) {\n throw new Error(`MCP authorization field \"${field}\" must be a bounded non-empty string`);\n }\n return value;\n}\n\nfunction optionalString(value: unknown, field: string): string | undefined {\n return value === undefined ? undefined : requiredString(value, field);\n}\n\nfunction boundedStringArray(value: unknown, field: string, maxItems: number): string[] {\n if (!Array.isArray(value) || value.length > maxItems) {\n throw new Error(`MCP authorization field \"${field}\" must be an array of at most ${maxItems}`);\n }\n return [...new Set(value.map((entry) => requiredString(entry, field)))];\n}\n\nfunction optionalStringArray(value: unknown, field: string, maxItems: number): string[] {\n return value === undefined ? [] : boundedStringArray(value, field, maxItems);\n}\n\nfunction secureOAuthUrl(value: string, label: string): URL {\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n throw new Error(`MCP ${label} must be an absolute URL`);\n }\n if (url.protocol !== 'https:' && !isLoopbackHttp(url)) {\n throw new Error(`MCP ${label} must use HTTPS (except loopback development)`);\n }\n if (url.username || url.password || url.search || url.hash) {\n throw new Error(`MCP ${label} must not contain credentials, query, or fragment components`);\n }\n if (url.pathname === '/') return new URL(url.origin);\n return url;\n}\n\nasync function discoverFirst<T>(\n candidates: readonly string[],\n fetchJson: MCPAuthorizationJsonFetcher,\n signal: AbortSignal | undefined,\n parse: (value: unknown) => T,\n label: string,\n): Promise<{ url: string; value: T }> {\n const failures: string[] = [];\n for (const candidate of candidates) {\n signal?.throwIfAborted();\n try {\n const value = await fetchJson(candidate, signal);\n if (value === undefined) {\n failures.push(`${candidate}: not found`);\n continue;\n }\n return { url: candidate, value: parse(value) };\n } catch (error) {\n signal?.throwIfAborted();\n failures.push(`${candidate}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n throw new Error(`MCP ${label} discovery failed (${failures.join('; ')})`);\n}\n\nasync function requestPinnedJson(\n rawUrl: string,\n options: {\n method?: 'GET' | 'POST' | undefined;\n body?: string | undefined;\n headers?: Record<string, string> | undefined;\n signal?: AbortSignal | undefined;\n timeoutMs?: number | undefined;\n maxResponseBytes?: number | undefined;\n lookup?: BrowserCompatibleDnsLookup | undefined;\n allowedLoopbackHostname?: string | undefined;\n },\n): Promise<unknown | undefined> {\n const url = secureOAuthUrl(rawUrl, 'discovery URL');\n const target = await resolvePinnedAddress(url, options);\n const timeoutMs = options.timeoutMs ?? 10_000;\n const maxBytes = options.maxResponseBytes ?? 64 * 1024;\n options.signal?.throwIfAborted();\n\n return new Promise<unknown | undefined>((resolve, reject) => {\n let settled = false;\n const finish = (error?: Error, value?: unknown) => {\n if (settled) return;\n settled = true;\n options.signal?.removeEventListener('abort', onAbort);\n if (error) reject(error);\n else resolve(value);\n };\n const onAbort = () => {\n request.destroy(options.signal?.reason instanceof Error ? options.signal.reason : undefined);\n };\n const headers: Record<string, string | number> = {\n accept: 'application/json',\n host: url.host,\n ...options.headers,\n };\n if (options.body !== undefined) {\n headers['content-length'] = Buffer.byteLength(options.body);\n }\n const requestOptions: http.RequestOptions = {\n host: target.address,\n family: target.family,\n port: Number(url.port || (url.protocol === 'https:' ? 443 : 80)),\n method: options.method ?? 'GET',\n path: `${url.pathname}${url.search}`,\n headers,\n ...(url.protocol === 'https:' && net.isIP(unbracket(url.hostname)) === 0\n ? { servername: unbracket(url.hostname) }\n : {}),\n };\n const requestFn = url.protocol === 'https:' ? https.request : http.request;\n const request = requestFn(requestOptions, (response) => {\n // Node only invokes the HTTP response callback after a status line has\n // been parsed, so statusCode is present here.\n const status = response.statusCode!;\n if (status === 404 || status === 410) {\n response.resume();\n finish(undefined, undefined);\n return;\n }\n if (status >= 300 && status < 400) {\n response.resume();\n finish(new Error('MCP OAuth discovery redirects are not allowed'));\n return;\n }\n if (status < 200 || status >= 300) {\n response.resume();\n finish(new Error(`MCP OAuth discovery HTTP ${status}`));\n return;\n }\n const contentType = response.headers['content-type'] ?? '';\n if (!/^(?:application\\/json|[^;]+\\+json)(?:;|$)/i.test(contentType)) {\n response.resume();\n finish(new Error('MCP OAuth discovery response must be JSON'));\n return;\n }\n const declaredLength = Number(response.headers['content-length'] ?? 0);\n if (Number.isFinite(declaredLength) && declaredLength > maxBytes) {\n response.destroy();\n finish(new Error(`MCP OAuth discovery response exceeds ${maxBytes} bytes`));\n return;\n }\n const chunks: Buffer[] = [];\n let size = 0;\n response.on('data', (chunk: Buffer) => {\n size += chunk.length;\n if (size > maxBytes) {\n response.destroy();\n finish(new Error(`MCP OAuth discovery response exceeds ${maxBytes} bytes`));\n return;\n }\n chunks.push(chunk);\n });\n response.once('end', () => {\n try {\n finish(undefined, JSON.parse(Buffer.concat(chunks).toString('utf8')));\n } catch {\n finish(new Error('MCP OAuth discovery response is not valid JSON'));\n }\n });\n response.once('error', (error) => finish(error));\n });\n request.setTimeout(timeoutMs, () => {\n request.destroy(new Error(`MCP OAuth discovery timed out after ${timeoutMs}ms`));\n });\n request.once('error', (error) => finish(error));\n options.signal?.addEventListener('abort', onAbort, { once: true });\n request.end(options.body);\n });\n}\n\nasync function resolvePinnedAddress(\n url: URL,\n options: {\n lookup?: BrowserCompatibleDnsLookup | undefined;\n allowedLoopbackHostname?: string | undefined;\n },\n): Promise<{ address: string; family: 4 | 6 }> {\n const hostname = unbracket(url.hostname).toLowerCase();\n const literalFamily = net.isIP(hostname);\n if (literalFamily === 4 || literalFamily === 6) {\n assertDiscoveryAddressAllowed(\n hostname,\n literalFamily,\n hostname,\n options.allowedLoopbackHostname,\n );\n return { address: hostname, family: literalFamily };\n }\n const lookup = options.lookup ?? ((host) => dns.lookup(host, { all: true }));\n const records = await lookup(hostname);\n if (records.length === 0)\n throw new Error(`MCP OAuth discovery DNS returned no addresses for ${hostname}`);\n for (const record of records) {\n if (record.family !== 4 && record.family !== 6) {\n throw new Error('MCP OAuth discovery DNS returned an unsupported address family');\n }\n assertDiscoveryAddressAllowed(\n record.address,\n record.family,\n hostname,\n options.allowedLoopbackHostname,\n );\n }\n const selected = records[0]!;\n return { address: selected.address, family: selected.family as 4 | 6 };\n}\n\nfunction assertDiscoveryAddressAllowed(\n address: string,\n family: 4 | 6,\n hostname: string,\n allowedLoopbackHostname: string | undefined,\n): void {\n const isPrivate = family === 4 ? isPrivateIPv4(address) : isPrivateIPv6(address);\n if (!isPrivate) return;\n const loopback = family === 4 ? address.startsWith('127.') : address === '::1';\n if (loopback && hostname === allowedLoopbackHostname) return;\n throw new Error(`MCP OAuth discovery blocked private address ${address}`);\n}\n\nfunction unbracket(hostname: string): string {\n return hostname.startsWith('[') && hostname.endsWith(']') ? hostname.slice(1, -1) : hostname;\n}\n\nfunction validateRedirectUri(value: string): string {\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n throw new Error('MCP OAuth redirect URI must be an absolute URL');\n }\n if (url.protocol !== 'https:' && !isLoopbackHttp(url)) {\n throw new Error('MCP OAuth redirect URI must use HTTPS or loopback HTTP');\n }\n if (url.username || url.password || url.search || url.hash) {\n throw new Error('MCP OAuth redirect URI must not contain credentials, query, or fragment');\n }\n return url.toString();\n}\n\nfunction validateScopes(scopes: readonly string[]): string[] {\n if (scopes.length > 128) throw new Error('MCP OAuth scope list exceeds 128 entries');\n const normalized = scopes.map((scope) => {\n if (!scope || scope.length > 256 || /\\s/.test(scope)) {\n throw new Error('MCP OAuth scopes must be bounded non-empty tokens');\n }\n return scope;\n });\n return [...new Set(normalized)];\n}\n\nfunction validateCodeVerifier(value: string): string {\n if (value.length < 43 || value.length > 128 || !/^[A-Za-z0-9._~-]+$/.test(value)) {\n throw new Error('MCP OAuth PKCE code verifier is invalid');\n }\n return value;\n}\n\nfunction boundedCredential(value: string, label: string): string {\n if (!value || value.length > 16_384 || /[\\r\\n]/.test(value)) {\n throw new Error(`MCP OAuth ${label} is empty, oversized, or invalid`);\n }\n return value;\n}\n\nfunction boundedErrorCode(value: string): string {\n return /^[A-Za-z0-9._-]{1,128}$/.test(value) ? value : 'invalid_error';\n}\n\nfunction base64Url(value: Uint8Array): string {\n return Buffer.from(value).toString('base64url');\n}\n\nfunction constantTimeEqual(left: string, right: string): boolean {\n const leftHash = createHash('sha256').update(left).digest();\n const rightHash = createHash('sha256').update(right).digest();\n return timingSafeEqual(leftHash, rightHash);\n}\n\nfunction parseTokenResponse(value: unknown, resource: string): MCPTokenSet {\n const response = record(value, 'token response');\n const accessToken = boundedCredential(\n requiredString(response['access_token'], 'access_token'),\n 'access token',\n );\n const tokenType = optionalString(response['token_type'], 'token_type') ?? 'Bearer';\n if (tokenType.toLowerCase() !== 'bearer') {\n throw new Error(`Unsupported MCP OAuth token type \"${tokenType}\"`);\n }\n const expiresIn = response['expires_in'];\n let expiresAt: number | undefined;\n if (expiresIn !== undefined) {\n if (\n typeof expiresIn !== 'number' ||\n !Number.isFinite(expiresIn) ||\n expiresIn <= 0 ||\n expiresIn > 31_536_000\n ) {\n throw new Error('MCP OAuth expires_in must be between 1 second and 1 year');\n }\n expiresAt = Date.now() + Math.floor(expiresIn * 1_000);\n }\n const refresh = optionalString(response['refresh_token'], 'refresh_token');\n const scope = optionalString(response['scope'], 'scope');\n const token: MCPTokenSet = {\n accessToken,\n tokenType: 'Bearer',\n resource,\n scopes: scope ? validateScopes(scope.split(/\\s+/).filter(Boolean)) : [],\n ...(expiresAt !== undefined ? { expiresAt } : {}),\n ...(refresh ? { refreshToken: boundedCredential(refresh, 'refresh token') } : {}),\n };\n authorizationHeaderForToken(token, resource);\n return token;\n}\n\nfunction loopbackHostnameForResource(resource: string): string | undefined {\n const url = new URL(resource);\n return isLoopbackHttp(url) ? unbracket(url.hostname).toLowerCase() : undefined;\n}\n\nfunction isLoopbackHttp(url: URL): boolean {\n if (url.protocol !== 'http:') return false;\n return (\n url.hostname === 'localhost' ||\n url.hostname === '127.0.0.1' ||\n url.hostname === '[::1]' ||\n url.hostname === '::1'\n );\n}\n", "import {\n canonicalMcpResource,\n createMcpAuthorizationRequest,\n discoverMcpAuthorization,\n exchangeMcpAuthorizationCode,\n type MCPAuthorizationDiscoveryOptions,\n type MCPAuthorizationDiscoveryResult,\n type MCPAuthorizationSession,\n type MCPTokenExchangeOptions,\n type MCPTokenSet,\n parseMcpAuthorizationCallback,\n parseMcpBearerChallenge,\n} from './authorization.js';\nimport type {\n MCPAuthorizationStateEvent,\n MCPStoredAuthorization,\n MCPVaultTokenStore,\n} from './token-store.js';\n\nconst DEFAULT_PENDING_TTL_MS = 10 * 60_000;\nconst MAX_PENDING_AUTHORIZATIONS = 32;\n\ntype DiscoverAuthorization = (\n resource: string,\n options?: MCPAuthorizationDiscoveryOptions,\n) => Promise<MCPAuthorizationDiscoveryResult>;\n\ntype ExchangeAuthorizationCode = (options: MCPTokenExchangeOptions) => Promise<MCPTokenSet>;\n\nexport interface MCPAuthorizationManagerOptions {\n store: MCPVaultTokenStore;\n pendingTtlMs?: number | undefined;\n discover?: DiscoverAuthorization | undefined;\n exchange?: ExchangeAuthorizationCode | undefined;\n now?: (() => number) | undefined;\n onStateChange?: ((event: MCPAuthorizationStateEvent) => void) | undefined;\n}\n\nexport interface MCPAuthorizationStartInput {\n serverName: string;\n resource: string;\n clientId: string;\n redirectUri: string;\n scopes?: readonly string[] | undefined;\n challengeHeader?: string | null | undefined;\n signal?: AbortSignal | undefined;\n}\n\nexport interface MCPAuthorizationStartResult {\n serverName: string;\n resource: string;\n authorizationUrl: string;\n redirectUri: string;\n scopes: string[];\n expiresAt: number;\n}\n\nexport interface MCPAuthorizationCompleteInput {\n serverName: string;\n resource: string;\n callbackUrl: string;\n signal?: AbortSignal | undefined;\n}\n\nexport interface MCPAuthorizationStatus {\n serverName: string;\n resource: string;\n state: 'not_authorized' | 'pending' | 'authorized' | 'expired';\n expiresAt?: number | undefined;\n scopes: string[];\n canRefresh: boolean;\n}\n\ninterface PendingAuthorization {\n session: MCPAuthorizationSession;\n discovery: MCPAuthorizationDiscoveryResult;\n scopes: string[];\n expiresAt: number;\n}\n\n/**\n * Surface-neutral manual OAuth coordinator. PKCE verifier/state stay only in\n * this bounded, expiring in-memory map; completed credentials are handed to\n * the host-owned vault store.\n */\nexport class MCPAuthorizationManager {\n private readonly pending = new Map<string, PendingAuthorization>();\n private readonly pendingTtlMs: number;\n private readonly discover: DiscoverAuthorization;\n private readonly exchange: ExchangeAuthorizationCode;\n private readonly now: () => number;\n\n constructor(private readonly options: MCPAuthorizationManagerOptions) {\n this.pendingTtlMs = options.pendingTtlMs ?? DEFAULT_PENDING_TTL_MS;\n if (!Number.isFinite(this.pendingTtlMs) || this.pendingTtlMs <= 0) {\n throw new Error('MCP authorization pending TTL must be a positive finite number');\n }\n this.discover = options.discover ?? discoverMcpAuthorization;\n this.exchange = options.exchange ?? exchangeMcpAuthorizationCode;\n this.now = options.now ?? Date.now;\n }\n\n async begin(input: MCPAuthorizationStartInput): Promise<MCPAuthorizationStartResult> {\n const resource = canonicalMcpResource(input.resource);\n const key = authorizationKey(input.serverName, resource);\n this.pruneExpired();\n if (!this.pending.has(key) && this.pending.size >= MAX_PENDING_AUTHORIZATIONS) {\n throw new Error('Too many pending MCP authorization sessions');\n }\n const discovery = await this.discover(resource, {\n challengeHeader: input.challengeHeader,\n signal: input.signal,\n });\n const challengeScopes = parseMcpBearerChallenge(input.challengeHeader ?? null, resource).scopes;\n const scopes = input.scopes ? [...input.scopes] : challengeScopes;\n const session = createMcpAuthorizationRequest({\n authorizationServer: discovery.authorizationServer,\n clientId: input.clientId,\n redirectUri: input.redirectUri,\n resource,\n scopes,\n });\n const normalizedScopes =\n new URL(session.authorizationUrl).searchParams.get('scope')?.split(' ').filter(Boolean) ?? [];\n const expiresAt = this.now() + this.pendingTtlMs;\n this.pending.set(key, { session, discovery, scopes: normalizedScopes, expiresAt });\n return {\n serverName: boundedServerName(input.serverName),\n resource,\n authorizationUrl: session.authorizationUrl,\n redirectUri: session.redirectUri,\n scopes: [...normalizedScopes],\n expiresAt,\n };\n }\n\n async complete(input: MCPAuthorizationCompleteInput): Promise<MCPAuthorizationStatus> {\n const serverName = boundedServerName(input.serverName);\n const resource = canonicalMcpResource(input.resource);\n const key = authorizationKey(serverName, resource);\n this.pruneExpired();\n const pending = this.pending.get(key);\n if (!pending) {\n throw new Error('No live MCP authorization session exists for this server');\n }\n const code = parseMcpAuthorizationCallback(input.callbackUrl, pending.session);\n // Authorization codes and PKCE verifiers are one-shot. Remove before the\n // network exchange so retries cannot accidentally replay either value.\n this.pending.delete(key);\n const tokenSet = await this.exchange({\n authorizationServer: pending.discovery.authorizationServer,\n clientId: pending.session.clientId,\n redirectUri: pending.session.redirectUri,\n resource,\n code,\n codeVerifier: pending.session.codeVerifier,\n signal: input.signal,\n });\n const stored: MCPStoredAuthorization = {\n serverName,\n resource,\n clientId: pending.session.clientId,\n authorizationServer: pending.discovery.authorizationServer,\n tokenSet,\n updatedAt: new Date(this.now()).toISOString(),\n };\n await this.options.store.save(stored);\n this.emit('authorized', stored);\n return statusFromStored(stored, this.now());\n }\n\n async status(serverName: string, resource: string): Promise<MCPAuthorizationStatus> {\n const normalizedName = boundedServerName(serverName);\n const normalizedResource = canonicalMcpResource(resource);\n this.pruneExpired();\n const pending = this.pending.get(authorizationKey(normalizedName, normalizedResource));\n if (pending) {\n return {\n serverName: normalizedName,\n resource: normalizedResource,\n state: 'pending',\n expiresAt: pending.expiresAt,\n scopes: [...pending.scopes],\n canRefresh: false,\n };\n }\n const stored = await this.options.store.load(normalizedName, normalizedResource);\n return stored\n ? statusFromStored(stored, this.now())\n : {\n serverName: normalizedName,\n resource: normalizedResource,\n state: 'not_authorized',\n scopes: [],\n canRefresh: false,\n };\n }\n\n async disconnect(serverName: string, resource: string): Promise<boolean> {\n const normalizedName = boundedServerName(serverName);\n const normalizedResource = canonicalMcpResource(resource);\n this.pending.delete(authorizationKey(normalizedName, normalizedResource));\n const removed = await this.options.store.remove(normalizedName, normalizedResource);\n if (removed) {\n this.options.onStateChange?.({\n serverName: normalizedName,\n state: 'removed',\n resource: normalizedResource,\n });\n }\n return removed;\n }\n\n private pruneExpired(): void {\n const now = this.now();\n for (const [key, value] of this.pending) {\n if (value.expiresAt <= now) this.pending.delete(key);\n }\n }\n\n private emit(state: MCPAuthorizationStateEvent['state'], value: MCPStoredAuthorization): void {\n this.options.onStateChange?.({\n serverName: value.serverName,\n state,\n resource: value.resource,\n expiresAt: value.tokenSet.expiresAt,\n scopes: [...(value.tokenSet.scopes ?? [])],\n });\n }\n}\n\nfunction statusFromStored(value: MCPStoredAuthorization, now: number): MCPAuthorizationStatus {\n return {\n serverName: value.serverName,\n resource: value.resource,\n state:\n value.tokenSet.expiresAt !== undefined && value.tokenSet.expiresAt <= now\n ? 'expired'\n : 'authorized',\n expiresAt: value.tokenSet.expiresAt,\n scopes: [...(value.tokenSet.scopes ?? [])],\n canRefresh: !!value.tokenSet.refreshToken,\n };\n}\n\nfunction authorizationKey(serverName: string, resource: string): string {\n return `${boundedServerName(serverName)}\\0${resource}`;\n}\n\nfunction boundedServerName(value: string): string {\n if (!value || value.length > 256 || /[\\r\\n\\0]/.test(value)) {\n throw new Error('MCP authorization server name is invalid');\n }\n return value;\n}\n", "import { type ChildProcess, spawn } from 'node:child_process';\nimport { buildChildEnv, toErrorMessage } from '@wrongstack/core/utils';\nimport type { MCPAuthorizationProvider } from './authorization.js';\nimport { MCP_CONSTANTS } from './constants.js';\nimport {\n type MCPGetPromptResult,\n type MCPListPromptsResult,\n type MCPListResourcesResult,\n type MCPListResourceTemplatesResult,\n type MCPReadResourceResult,\n type MCPServerMetadata,\n parseGetPromptResult,\n parseListPromptsResult,\n parseListResourcesResult,\n parseListResourceTemplatesResult,\n parseReadResourceResult,\n parseServerMetadata,\n} from './protocol.js';\nimport { normalizeMCPTools } from './tool-schema.js';\nimport { type HttpTransportOptions, SSETransport, StreamableHTTPTransport } from './transport.js';\nimport { isJsonRpcResult } from './transport-jsonrpc.js';\n\nexport type Transport = 'stdio' | 'sse' | 'streamable-http';\n\nexport interface MCPClientOptions {\n name: string;\n transport: Transport;\n command?: string | undefined;\n args?: string[] | undefined;\n env?: Record<string, string> | undefined;\n url?: string | undefined;\n headers?: Record<string, string> | undefined;\n startupTimeoutMs?: number | undefined;\n requestTimeoutMs?: number | undefined;\n /** Host-owned, vault-backed authorization for HTTP transports. */\n authorizationProvider?: MCPAuthorizationProvider | undefined;\n /**\n * Allowlist of env var names to forward from the parent process (process.env)\n * to the child. Values are resolved at spawn time and merged into `env`\n * via the `extra` path of `buildChildEnv` (unfiltered). This is how built-in\n * MCP server presets (GitHub, Slack, Brave Search, \u2026) get their API tokens\n * without storing them in config.json or being scrubbed by the secret filter.\n */\n passthroughEnv?: string[] | undefined;\n}\n\nexport type ConnectionState =\n | 'idle'\n | 'connecting'\n | 'connected'\n | 'disconnected'\n | 'reconnecting'\n | 'failed'\n /** Lazy server: registered from a cached manifest, process not spawned. */\n | 'dormant';\n\nexport interface MCPTool {\n name: string;\n description?: string | undefined;\n inputSchema: Record<string, unknown>;\n}\n\nexport interface ToolCallResult {\n content: unknown;\n isError: boolean;\n}\n\nexport interface MCPRequestOptions {\n signal?: AbortSignal | undefined;\n}\n\nexport interface MCPPageOptions extends MCPRequestOptions {\n cursor?: string | undefined;\n}\n\ninterface JsonRpcRequest {\n jsonrpc: '2.0';\n id: number;\n method: string;\n params?: unknown | undefined;\n}\n\nexport interface JsonRpcResponse {\n jsonrpc: '2.0';\n id: number;\n result?: unknown | undefined;\n error?: { code: number | undefined; message: string; data?: unknown | undefined } | undefined;\n}\n\ntype JsonRpcServerRequest = {\n jsonrpc: '2.0';\n id: number | string;\n method: string;\n params?: unknown | undefined;\n};\n\ntype ExitListener = (name: string, code: number | null, signal: string | null) => void;\n/**\n * Fired when the server sends `notifications/tools/list_changed`. The\n * client refreshes its cached tool list before invoking listeners, so\n * subscribers can call `listTools()` for the fresh set.\n */\ntype ToolsChangedListener = (name: string, tools: MCPTool[]) => void;\nexport type MCPListChangedListener = (name: string) => void;\n\n/**\n * Force-kill a child and its descendants. On Windows a stdio server is launched\n * through a `.cmd` shim with `shell: true`, so `child` is the `cmd.exe` wrapper\n * and the real server (npx\u2192node / uvx) is its grandchild \u2014 `child.kill('SIGKILL')`\n * signals only the wrapper and orphans the server, which then accumulates across\n * every close / restart / idle-sleep. `taskkill /T /F` tears down the whole tree.\n */\nexport function forceKillTree(child: ChildProcess): void {\n if (child.pid === undefined) {\n try {\n child.kill('SIGKILL');\n } catch {\n /* already gone */\n }\n return;\n }\n if (process.platform === 'win32') {\n const killer = spawn('taskkill', ['/pid', String(child.pid), '/T', '/F'], {\n stdio: 'ignore',\n windowsHide: true,\n });\n killer.once('error', () => {\n try {\n child.kill('SIGKILL');\n } catch {\n /* already gone */\n }\n });\n killer.unref();\n return;\n }\n try {\n child.kill('SIGKILL');\n } catch {\n /* already gone */\n }\n}\n\n/**\n * Lightweight MCP client supporting three transport types:\n * - stdio: spawns a child process and communicates over pipes\n * - sse: connects to an HTTP SSE endpoint for server events, POST for requests\n * - streamable-http: session-based HTTP transport with NDJSON responses\n */\nexport class MCPClient {\n /**\n * Maximum bytes the rx buffer may accumulate before the connection is\n * forcefully closed. A well-behaved JSON-RPC server emits newline-delimited\n * messages that are individually much smaller than this; a server that never\n * sends a newline would grow the buffer without limit and OOM the process.\n * 16 MiB is generous for any legitimate single message while bounding the\n * worst-case memory to a predictable cap.\n */\n private static readonly MAX_RX_BUFFER_BYTES = 16 * 1024 * 1024;\n\n private state: ConnectionState = 'idle';\n private child?: ChildProcess | undefined;\n private nextId = 1;\n /**\n * In-flight JSON-RPC calls keyed by id. `resolve` settles the call; `reject`\n * is invoked from {@link failPending} when the underlying transport dies\n * (stdio child exit, `close()`) so callers don't hang forever.\n */\n private readonly pending = new Map<\n number,\n { resolve: (res: JsonRpcResponse) => void; reject: (err: Error) => void; timer: NodeJS.Timeout }\n >();\n private rxBuffer = '';\n private _tools: MCPTool[] = [];\n /** Server-declared handshake metadata. Populated for stdio in the first protocol slice. */\n private _serverMetadata?: MCPServerMetadata | undefined;\n /** Cached tool list \u2014 survives reconnects so the registry can re-register without re-discovering. */\n private _toolsCache?: MCPTool[] | undefined;\n private _drainPending = false;\n private _lastNotifySkipped = false;\n // HTTP transports\n private sseTransport?: SSETransport | undefined;\n private httpTransport?: StreamableHTTPTransport | undefined;\n /** Notified when the stdio child process exits so the registry can attempt reconnect. */\n private readonly exitListeners = new Set<ExitListener>();\n /** Notified when the server announces a tools/list_changed notification. */\n private readonly toolsChangedListeners = new Set<ToolsChangedListener>();\n private readonly resourcesChangedListeners = new Set<MCPListChangedListener>();\n private readonly promptsChangedListeners = new Set<MCPListChangedListener>();\n /** Notified when an HTTP transport (SSE or streamable-http) disconnects. */\n private readonly disconnectListeners = new Set<() => void>();\n\n constructor(public readonly opts: MCPClientOptions) {}\n\n getState(): ConnectionState {\n return this.state;\n }\n\n getServerMetadata(): MCPServerMetadata | undefined {\n const metadata = this._serverMetadata;\n if (!metadata) return undefined;\n return {\n ...metadata,\n capabilities: { ...metadata.capabilities },\n serverInfo: { ...metadata.serverInfo },\n };\n }\n\n listTools(): MCPTool[] {\n return this._tools.length > 0\n ? [...this._tools]\n : this._toolsCache\n ? [...this._toolsCache]\n : [];\n }\n\n /** Returns true if a prior notify() call was skipped due to backpressure. */\n hadNotifySkipped(): boolean {\n return this._lastNotifySkipped;\n }\n\n /**\n * Register a listener for child-process exit events.\n * The registry uses this to trigger reconnection.\n */\n addExitListener(listener: ExitListener): void {\n this.exitListeners.add(listener);\n }\n\n removeExitListener(listener: ExitListener): void {\n this.exitListeners.delete(listener);\n }\n\n /**\n * Register a listener for transport disconnect events (SSE / streamable-http).\n * Used by the registry to trigger reconnection for HTTP-based servers.\n */\n addDisconnectListener(listener: () => void): void {\n this.disconnectListeners.add(listener);\n }\n\n removeDisconnectListener(listener: () => void): void {\n this.disconnectListeners.delete(listener);\n }\n\n async connect(): Promise<void> {\n this.state = 'connecting';\n this._serverMetadata = undefined;\n\n if (this.opts.transport === 'stdio') {\n await this.connectStdio();\n } else if (this.opts.transport === 'sse') {\n await this.connectSSE();\n } else if (this.opts.transport === 'streamable-http') {\n await this.connectStreamableHTTP();\n } else {\n this.state = 'failed';\n throw new Error(`Unknown transport \"${this.opts.transport}\"`);\n }\n }\n\n private async connectStdio(): Promise<void> {\n if (!this.opts.command) {\n this.state = 'failed';\n throw new Error('MCP stdio transport requires \"command\"');\n }\n\n // Defense-in-depth: clear any rx state from a previous connect attempt\n // on this instance. The registry normally creates a fresh client per\n // (re)connect cycle, but a leftover rxBuffer from a half-initialized\n // attempt would corrupt JSON-RPC parsing on the new stream.\n this.rxBuffer = '';\n\n // On Windows, MCP servers are usually launched via `npx`/`npm`/`uvx`,\n // which resolve to `.cmd` shims. Since the CVE-2024-27980 fix Node refuses\n // to spawn `.cmd`/`.bat` without a shell (raw spawn throws ENOENT), so the\n // whole npx-based preset catalog is unusable without a shell. We pass the\n // full command line as a single string (with each token cmd.exe-quoted) and\n // `shell: true` \u2014 an empty args array avoids the DEP0190 warning that\n // `shell:true` + an args array triggers. Server command+args come from\n // config (admin-controlled), not the model, so shell use is not an\n // injection vector here.\n // Resolve passthroughEnv: forward explicitly-listed env var names from\n // the parent process to the child. This lets MCP server presets (GitHub,\n // Slack, Brave Search, \u2026) get their API tokens without storing them in\n // config.json or being scrubbed by buildChildEnv()'s secret filter.\n const extraEnv: Record<string, string> = { ...this.opts.env };\n if (this.opts.passthroughEnv) {\n for (const name of this.opts.passthroughEnv) {\n const val = process.env[name];\n if (val !== undefined) {\n extraEnv[name] = val;\n }\n }\n }\n const isWin = process.platform === 'win32';\n const rawArgs = this.opts.args ?? [];\n const spawnEnv = buildChildEnv({ extra: extraEnv });\n const stdio: ['pipe', 'pipe', 'pipe'] = ['pipe', 'pipe', 'pipe'];\n const child = isWin\n ? spawn([this.opts.command, ...rawArgs].map(quoteWindowsArg).join(' '), {\n env: spawnEnv,\n stdio,\n shell: true,\n // Without this every MCP server spawned from a console-less host\n // (WebUI server, scheduled runs) opens a visible console window.\n windowsHide: true,\n })\n : spawn(this.opts.command, rawArgs, { env: spawnEnv, stdio, windowsHide: true });\n this.child = child;\n\n child.stdout?.on('data', (chunk: Buffer) => this.onData(chunk.toString()));\n child.stderr?.on('data', () => {\n // intentionally discard stderr noise from server\n });\n child.stdin?.on('error', (err: Error) => {\n // Pipe failures such as EPIPE are emitted asynchronously by Writable;\n // the try/catch around stdin.write() cannot intercept them. Always own\n // the stream error so a child that exits during startup rejects pending\n // requests instead of surfacing as an uncaught process exception.\n this.failPending(`MCP \"${this.opts.name}\" stdin error: ${toErrorMessage(err)}`);\n });\n child.on('exit', (code, signal) => {\n this.state = 'disconnected';\n // Reject any in-flight JSON-RPC requests \u2014 without this, callers\n // (e.g. callTool during a tool invocation) await forever on a child\n // that has already gone away.\n this.failPending(\n `MCP \"${this.opts.name}\" child exited (code=${code ?? 'null'} signal=${signal ?? 'null'})`,\n );\n for (const listener of this.exitListeners) {\n try {\n listener(this.opts.name, code, signal);\n } catch {\n /* ignore */\n }\n }\n });\n child.on('error', (err: Error) => {\n this.state = 'failed';\n // Spawn/runtime errors (ENOENT, EACCES, ...) can fire *after* the child\n // handle exists but often without a matching 'exit' event. Without\n // failing in-flight requests here, callers awaiting the startup\n // `initialize` (or any tools/call) hang until their timeout instead of\n // rejecting promptly.\n this.failPending(`MCP \"${this.opts.name}\" child error: ${toErrorMessage(err)}`);\n });\n\n const initialize = await this.request(\n 'initialize',\n {\n protocolVersion: MCP_CONSTANTS.PROTOCOL_VERSION,\n capabilities: { tools: {} },\n clientInfo: MCP_CONSTANTS.CLIENT_INFO,\n },\n this.opts.startupTimeoutMs ?? 10_000,\n );\n if (initialize.error) {\n this.state = 'failed';\n throw new Error(`MCP initialize failed: ${initialize.error.message}`);\n }\n try {\n this._serverMetadata = parseServerMetadata(initialize.result);\n } catch (err) {\n this.state = 'failed';\n throw new Error(`MCP initialize returned malformed server metadata: ${toErrorMessage(err)}`);\n }\n try {\n await this.notify('notifications/initialized', {});\n } catch (err) {\n console.warn(\n '[MCP] notify(\"notifications/initialized\") failed for \"' +\n this.opts.name +\n '\": ' +\n toErrorMessage(err),\n );\n }\n const toolsRes = await this.request('tools/list', {});\n if (toolsRes.error) {\n this._tools = [];\n } else {\n const result = toolsRes.result as { tools?: MCPTool[] | undefined } | undefined;\n this._tools = normalizeMCPTools(result?.tools);\n }\n // Cache tools so reconnect can re-register without re-discovering\n this._toolsCache = this._tools;\n this.state = 'connected';\n }\n\n private async connectSSE(): Promise<void> {\n if (!this.opts.url) {\n this.state = 'failed';\n throw new Error('MCP SSE transport requires \"url\"');\n }\n const httpOpts: HttpTransportOptions = {\n name: this.opts.name,\n url: this.opts.url,\n headers: this.opts.headers,\n startupTimeoutMs: this.opts.startupTimeoutMs,\n requestTimeoutMs: this.opts.requestTimeoutMs,\n authorizationProvider: this.opts.authorizationProvider,\n };\n this.sseTransport = new SSETransport(httpOpts);\n this.sseTransport.onDisconnect(() => {\n this.state = 'disconnected';\n for (const cb of this.disconnectListeners) {\n try {\n cb();\n } catch {\n /* ignore */\n }\n }\n });\n this.sseTransport.onToolsChanged((tools) => {\n this._tools = tools;\n // Keep the reconnect-recovery cache in sync. Without this, an empty\n // tools update would leave `_toolsCache` pointing at the previous\n // non-empty list, and `listTools()` would serve the stale cache\n // (since it falls back to the cache when `_tools` is empty).\n this._toolsCache = tools;\n for (const cb of this.toolsChangedListeners) {\n try {\n cb(this.opts.name, tools);\n } catch {\n /* ignore */\n }\n }\n });\n this.sseTransport.onResourcesChanged(() => this.emitCapabilityChanged('resources'));\n this.sseTransport.onPromptsChanged(() => this.emitCapabilityChanged('prompts'));\n try {\n await this.sseTransport.connect();\n } catch (err) {\n // Tear down the partial transport deterministically: its SSE read\n // loop is async-running on a `ReadableStreamDefaultReader`, and its\n // `AbortController` is wired into the connect-time startup timer.\n // Without this close(), the reader can keep the response body alive\n // until GC. The transport is fresh (never reached the success\n // path), so close() is safe and idempotent.\n const t = this.sseTransport;\n this.sseTransport = undefined;\n await t.close().catch(() => {\n /* best-effort cleanup */\n });\n this.state = 'failed';\n throw err;\n }\n this._tools = this.sseTransport.listTools();\n this._toolsCache = this._tools;\n this._serverMetadata = this.sseTransport.getServerMetadata();\n this.state = 'connected';\n }\n\n private async connectStreamableHTTP(): Promise<void> {\n if (!this.opts.url) {\n this.state = 'failed';\n throw new Error('MCP streamable-http transport requires \"url\"');\n }\n const httpOpts: HttpTransportOptions = {\n name: this.opts.name,\n url: this.opts.url,\n headers: this.opts.headers,\n startupTimeoutMs: this.opts.startupTimeoutMs,\n requestTimeoutMs: this.opts.requestTimeoutMs,\n authorizationProvider: this.opts.authorizationProvider,\n };\n this.httpTransport = new StreamableHTTPTransport(httpOpts);\n this.httpTransport.onDisconnect(() => {\n this.state = 'disconnected';\n for (const cb of this.disconnectListeners) {\n try {\n cb();\n } catch {\n /* ignore */\n }\n }\n });\n this.httpTransport.onToolsChanged((tools) => {\n this._tools = tools;\n // Same cache-sync reasoning as the SSE branch above \u2014 keep\n // `_toolsCache` in lockstep with `_tools` on every transport\n // update so the empty-list fallback in `listTools()` never serves\n // stale data.\n this._toolsCache = tools;\n for (const cb of this.toolsChangedListeners) {\n try {\n cb(this.opts.name, tools);\n } catch {\n /* ignore */\n }\n }\n });\n this.httpTransport.onResourcesChanged(() => this.emitCapabilityChanged('resources'));\n this.httpTransport.onPromptsChanged(() => this.emitCapabilityChanged('prompts'));\n try {\n await this.httpTransport.connect();\n } catch (err) {\n // Same teardown reasoning as the SSE branch \u2014 the partial transport's\n // `AbortController` and any in-flight header/state would otherwise\n // outlive this client instance until GC.\n const t = this.httpTransport;\n this.httpTransport = undefined;\n await t.close().catch(() => {\n /* best-effort cleanup */\n });\n this.state = 'failed';\n throw err;\n }\n this._tools = this.httpTransport.listTools();\n this._toolsCache = this._tools;\n this._serverMetadata = this.httpTransport.getServerMetadata();\n this.state = 'connected';\n }\n\n async callTool(\n name: string,\n input: unknown,\n opts?: { signal?: AbortSignal | undefined },\n ): Promise<ToolCallResult> {\n if (this.state !== 'connected') {\n throw new Error(`MCP client \"${this.opts.name}\" not connected (state=${this.state})`);\n }\n // Delegate to the active transport\n if (this.sseTransport) {\n return this.sseTransport.callTool(name, input, opts);\n }\n if (this.httpTransport) {\n return this.httpTransport.callTool(name, input, opts);\n }\n // stdio\n const res = await this.request('tools/call', { name, arguments: input }, undefined, opts);\n if (res.error) {\n return { content: res.error.message, isError: true };\n }\n const result = res.result as\n | { content?: unknown | undefined; isError?: boolean | undefined }\n | undefined;\n return {\n content: result?.content ?? '',\n isError: Boolean(result?.isError),\n };\n }\n\n async listResources(opts: MCPPageOptions = {}): Promise<MCPListResourcesResult> {\n const params = pageParams(opts.cursor, 'resources/list cursor');\n return this.requestCapability(\n 'resources',\n 'resources/list',\n params,\n parseListResourcesResult,\n opts,\n );\n }\n\n async listResourceTemplates(opts: MCPPageOptions = {}): Promise<MCPListResourceTemplatesResult> {\n const params = pageParams(opts.cursor, 'resources/templates/list cursor');\n return this.requestCapability(\n 'resources',\n 'resources/templates/list',\n params,\n parseListResourceTemplatesResult,\n opts,\n );\n }\n\n async readResource(uri: string, opts: MCPRequestOptions = {}): Promise<MCPReadResourceResult> {\n validateProtocolString(uri, 'resource URI');\n return this.requestCapability(\n 'resources',\n 'resources/read',\n { uri },\n parseReadResourceResult,\n opts,\n );\n }\n\n async subscribeResource(uri: string, opts: MCPRequestOptions = {}): Promise<void> {\n validateProtocolString(uri, 'resource URI');\n this.requireResourceSubscriptions('resources/subscribe');\n await this.requestCapability(\n 'resources',\n 'resources/subscribe',\n { uri },\n parseEmptyResult,\n opts,\n );\n }\n\n async unsubscribeResource(uri: string, opts: MCPRequestOptions = {}): Promise<void> {\n validateProtocolString(uri, 'resource URI');\n this.requireResourceSubscriptions('resources/unsubscribe');\n await this.requestCapability(\n 'resources',\n 'resources/unsubscribe',\n { uri },\n parseEmptyResult,\n opts,\n );\n }\n\n async listPrompts(opts: MCPPageOptions = {}): Promise<MCPListPromptsResult> {\n const params = pageParams(opts.cursor, 'prompts/list cursor');\n return this.requestCapability('prompts', 'prompts/list', params, parseListPromptsResult, opts);\n }\n\n async getPrompt(\n name: string,\n args?: Record<string, string> | undefined,\n opts: MCPRequestOptions = {},\n ): Promise<MCPGetPromptResult> {\n validateProtocolString(name, 'prompt name');\n if (args && Object.keys(args).length > 64) {\n throw new Error('MCP prompt arguments exceed the limit of 64');\n }\n for (const [key, value] of Object.entries(args ?? {})) {\n validateProtocolString(key, 'prompt argument name');\n validateProtocolString(value, `prompt argument \"${key}\"`, true);\n }\n return this.requestCapability(\n 'prompts',\n 'prompts/get',\n args === undefined ? { name } : { name, arguments: args },\n parseGetPromptResult,\n opts,\n );\n }\n\n async close(): Promise<void> {\n if (this.child) {\n const child = this.child;\n // Always register the listener first. Checking exitCode/signalCode\n // before registering creates a TOCTOU race: the child can exit between\n // the check and child.once('exit', ...), so the listener never fires\n // and exitPromise hangs forever. The double-check below handles the\n // case where the child already exited before we registered.\n const exitPromise = new Promise<void>((resolve) => {\n child.once('exit', () => resolve());\n if (child.exitCode !== null || child.signalCode !== null) resolve();\n });\n try {\n // Initial SIGTERM lets the server flush logs / clean up sockets.\n child.kill();\n } catch {\n // ignore\n }\n // Wait briefly for graceful exit, then escalate to SIGKILL. A stuck\n // server that ignores SIGTERM would otherwise stay alive after\n // close() returns \u2014 orphan child processes accumulate over restarts.\n const GRACEFUL_MS = 800;\n const FORCE_TIMEOUT_MS = 1200;\n const gracefulRace = await Promise.race([\n exitPromise.then(() => 'exited' as const),\n new Promise<'timeout'>((resolve) => setTimeout(() => resolve('timeout'), GRACEFUL_MS)),\n ]);\n if (gracefulRace === 'timeout') {\n // On Windows the graceful child.kill() above only signals the cmd.exe\n // wrapper, so this escalation is always reached \u2014 tree-kill the real\n // server (taskkill /T /F) instead of just the wrapper. POSIX SIGKILLs\n // the child directly.\n forceKillTree(child);\n await Promise.race([\n exitPromise,\n new Promise<void>((resolve) => setTimeout(resolve, FORCE_TIMEOUT_MS)),\n ]);\n }\n }\n // Reject pending requests BEFORE closing transports. This matters for\n // in-flight HTTP requests: they are not yet in `this.pending` (waiting\n // for a response from the network), so failPending() must run while the\n // transport is still alive. After this, the transport close is safe to\n // call even on a never-started or HTTP-only client \u2014 the exit handler\n // may have already run failPending, but calling it again with the same\n // pending set is a no-op (failPending guards on `this.pending.size`).\n this.failPending(`MCP \"${this.opts.name}\" closed`);\n this.sseTransport?.close();\n this.httpTransport?.close();\n this.state = 'disconnected';\n }\n\n private request(\n method: string,\n params: unknown,\n timeoutMs = this.opts.requestTimeoutMs ?? 60_000,\n opts?: { signal?: AbortSignal | undefined },\n ): Promise<JsonRpcResponse> {\n // For HTTP transports, delegate to the transport's request method.\n // SSE and streamable-http both use postRaw which handles the full\n // round-trip including timeout signal.\n if (this.sseTransport) return this.sseTransport.request(method, params, timeoutMs, opts);\n if (this.httpTransport) return this.httpTransport.request(method, params, timeoutMs, opts);\n\n // stdio path\n const signal = opts?.signal;\n if (signal?.aborted) {\n const err = new Error(`MCP \"${this.opts.name}\" request \"${method}\" aborted before send`);\n err.name = 'AbortError';\n return Promise.reject(err);\n }\n const id = this.nextId++;\n const req: JsonRpcRequest = { jsonrpc: '2.0', id, method, params };\n return new Promise((resolve, reject) => {\n // Abort support: drop the pending entry, notify the server per the MCP\n // cancellation spec (`notifications/cancelled`, best-effort \u2014 the\n // server SHOULD stop processing), and surface an AbortError so the\n // executor classifies it as user cancellation (never retried).\n const onAbort = signal\n ? () => {\n const pending = this.pending.get(id);\n this.pending.delete(id);\n if (pending) clearTimeout(pending.timer);\n void this.notify('notifications/cancelled', {\n requestId: id,\n reason: 'client aborted',\n }).catch(() => {\n /* best-effort \u2014 the child may already be gone */\n });\n const err = new Error(`MCP \"${this.opts.name}\" request \"${method}\" aborted by client`);\n err.name = 'AbortError';\n reject(err);\n }\n : undefined;\n if (signal && onAbort) signal.addEventListener('abort', onAbort, { once: true });\n const detach = () => {\n if (signal && onAbort) signal.removeEventListener('abort', onAbort);\n };\n const timer = setTimeout(() => {\n this.pending.delete(id);\n detach();\n reject(\n new Error(`MCP \"${this.opts.name}\" request \"${method}\" timed out after ${timeoutMs}ms`),\n );\n }, timeoutMs);\n this.pending.set(id, {\n resolve: (res) => {\n clearTimeout(timer);\n detach();\n resolve(res);\n },\n reject: (err) => {\n clearTimeout(timer);\n detach();\n reject(err);\n },\n timer,\n });\n const stdin = this.child?.stdin;\n if (!stdin || stdin.destroyed) {\n // No writable stdin (child never spawned, already exited, or stream\n // destroyed). Reject immediately instead of leaving the request\n // pending until it times out.\n const pending = this.pending.get(id);\n this.pending.delete(id);\n if (pending) clearTimeout(pending.timer);\n detach();\n reject(new Error(`MCP \"${this.opts.name}\" request \"${method}\": stdin not writable`));\n return;\n }\n try {\n stdin.write(JSON.stringify(req) + '\\n');\n } catch (err) {\n const pending = this.pending.get(id);\n this.pending.delete(id);\n if (pending) clearTimeout(pending.timer);\n detach();\n reject(err);\n }\n });\n }\n\n private async requestCapability<T>(\n capability: 'resources' | 'prompts',\n method: string,\n params: unknown,\n parse: (value: unknown) => T,\n opts: MCPRequestOptions,\n ): Promise<T> {\n if (this.state !== 'connected') {\n throw new Error(`MCP client \"${this.opts.name}\" not connected (state=${this.state})`);\n }\n const metadata = this._serverMetadata;\n if (!metadata) {\n throw new Error(\n `MCP server \"${this.opts.name}\" capability metadata is unavailable for ${method}`,\n );\n }\n if (!metadata.capabilities[capability]) {\n throw new Error(\n `MCP server \"${this.opts.name}\" does not advertise the ${capability} capability`,\n );\n }\n const response = await this.request(method, params, undefined, opts);\n if (response.error) {\n throw new Error(`MCP ${method} failed: ${response.error.message}`);\n }\n return parse(response.result);\n }\n\n private requireResourceSubscriptions(method: string): void {\n if (this.state !== 'connected') {\n throw new Error(`MCP client \"${this.opts.name}\" not connected (state=${this.state})`);\n }\n if (this._serverMetadata?.capabilities.resources?.subscribe !== true) {\n throw new Error(\n `MCP server \"${this.opts.name}\" does not advertise resource subscriptions for ${method}`,\n );\n }\n }\n\n /**\n * Reject every in-flight {@link request} call. Used when the underlying\n * transport dies \u2014 without this, callers awaiting `tools/call` over a\n * killed stdio child or a closed transport would hang indefinitely.\n */\n private failPending(reason: string): void {\n if (this.pending.size === 0) return;\n const err = new Error(reason);\n for (const [, entry] of this.pending) {\n try {\n clearTimeout(entry.timer);\n entry.reject(err);\n } catch {\n /* ignore */\n }\n }\n this.pending.clear();\n }\n\n private async notify(method: string, params: unknown): Promise<void> {\n const req = { jsonrpc: '2.0', method, params };\n const encoded = JSON.stringify(req) + '\\n';\n try {\n const ok = this.child?.stdin?.write(encoded);\n if (!ok) {\n // Only the first caller waits for drain; others just warn and return.\n // This avoids a race where two concurrent notify() calls each start\n // their own drain-wait, then both resolve and the buffer is still full.\n if (this._drainPending) {\n this._lastNotifySkipped = true;\n console.warn(\n JSON.stringify({\n level: 'warn',\n event: 'mcp.notify_skipped_backpressure',\n server: this.opts.name,\n method,\n message: 'stdin buffer backpressure (already waiting for drain)',\n timestamp: new Date().toISOString(),\n }),\n );\n return;\n }\n this._drainPending = true;\n await new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => {\n this.child?.stdin?.removeListener?.('drain', onDrain);\n this.child?.stdin?.removeListener?.('error', onError);\n this._drainPending = false;\n reject(new Error(`MCP notify(\"${method}\") drain timeout`));\n }, 500);\n const onDrain = () => {\n clearTimeout(timeout);\n this.child?.stdin?.removeListener?.('drain', onDrain);\n this.child?.stdin?.removeListener?.('error', onError);\n this._drainPending = false;\n resolve();\n };\n const onError = (err: Error) => {\n clearTimeout(timeout);\n this.child?.stdin?.removeListener?.('drain', onDrain);\n this.child?.stdin?.removeListener?.('error', onError);\n this._drainPending = false;\n reject(err);\n };\n this.child?.stdin?.once('drain', onDrain);\n this.child?.stdin?.once('error', onError);\n });\n }\n } catch (err) {\n throw new Error(`[MCP] notify(\"${method}\") failed: ${toErrorMessage(err)}`);\n }\n }\n\n private onData(s: string): void {\n this.rxBuffer += s;\n\n // Guard against a malicious or buggy server that never emits a newline \u2014\n // without this cap the buffer grows without limit and OOMs the process.\n if (this.rxBuffer.length > MCPClient.MAX_RX_BUFFER_BYTES) {\n const truncated = this.rxBuffer.length;\n this.rxBuffer = '';\n this.failPending(\n `MCP \"${this.opts.name}\" rx buffer overflow (${truncated} bytes without a newline) \u2014 closing connection`,\n );\n void this.close();\n return;\n }\n\n let idx = this.rxBuffer.indexOf('\\n');\n while (idx !== -1) {\n const line = this.rxBuffer.slice(0, idx).trim();\n this.rxBuffer = this.rxBuffer.slice(idx + 1);\n if (line) this.onLine(line);\n idx = this.rxBuffer.indexOf('\\n');\n }\n }\n\n private onLine(line: string): void {\n let msg: unknown;\n try {\n msg = JSON.parse(line);\n } catch {\n return;\n }\n\n if (typeof msg !== 'object' || msg === null) return;\n const envelope = msg as Record<string, unknown>;\n if (envelope['jsonrpc'] !== '2.0') return;\n\n // A server request is never a response, even if its id collides with one\n // of our pending calls. Resolve pending calls only after the envelope has\n // passed the strict response guard below.\n if (typeof envelope['method'] === 'string') {\n const id = envelope['id'];\n if (typeof id === 'number' || typeof id === 'string') {\n this.handleServerRequest({\n jsonrpc: '2.0',\n id,\n method: envelope['method'],\n params: envelope['params'],\n });\n return;\n }\n\n // Notifications have a `method` but no `id`. The MCP spec defines\n // list_changed notifications for cache invalidation.\n if (Object.hasOwn(envelope, 'id')) return;\n if (envelope['method'] === 'notifications/tools/list_changed') {\n void this.handleToolsListChanged();\n } else if (envelope['method'] === 'notifications/resources/list_changed') {\n this.emitCapabilityChanged('resources');\n } else if (envelope['method'] === 'notifications/prompts/list_changed') {\n this.emitCapabilityChanged('prompts');\n }\n return;\n }\n\n if (!isJsonRpcResult(msg)) return;\n const response = msg as JsonRpcResponse;\n if (this.pending.has(response.id)) {\n const entry = this.pending.get(response.id);\n this.pending.delete(response.id);\n entry?.resolve(response);\n }\n }\n\n private handleServerRequest(request: JsonRpcServerRequest): void {\n const message =\n request.method === 'sampling/createMessage'\n ? 'Client sampling is disabled by policy'\n : `Method not found: ${request.method}`;\n const response = {\n jsonrpc: '2.0',\n id: request.id,\n error: { code: -32601, message },\n };\n\n try {\n this.child?.stdin?.write(`${JSON.stringify(response)}\\n`);\n } catch {\n // Best-effort protocol reply. A closed stdio stream is handled by the\n // normal child-exit path, which also rejects every pending client call.\n }\n }\n\n /**\n * L2-C: refresh the cached tool list when the server announces a\n * `tools/list_changed`. Listeners (the registry) re-wrap and\n * re-register. Failures are swallowed \u2014 a stale cache is preferable\n * to a hard crash on a transient notification glitch.\n */\n private async handleToolsListChanged(): Promise<void> {\n try {\n const toolsRes = await this.request('tools/list', {});\n const tools = normalizeMCPTools(\n (toolsRes.result as { tools?: unknown | undefined } | undefined)?.tools,\n );\n this._tools = tools;\n this._toolsCache = tools;\n for (const listener of this.toolsChangedListeners) {\n try {\n listener(this.opts.name, [...tools]);\n } catch {\n // listeners must be best-effort\n }\n }\n } catch {\n // ignore \u2014 keep the existing cache\n }\n }\n\n addToolsChangedListener(listener: ToolsChangedListener): void {\n this.toolsChangedListeners.add(listener);\n }\n\n removeToolsChangedListener(listener: ToolsChangedListener): void {\n this.toolsChangedListeners.delete(listener);\n }\n\n addResourcesChangedListener(listener: MCPListChangedListener): void {\n this.resourcesChangedListeners.add(listener);\n }\n\n removeResourcesChangedListener(listener: MCPListChangedListener): void {\n this.resourcesChangedListeners.delete(listener);\n }\n\n addPromptsChangedListener(listener: MCPListChangedListener): void {\n this.promptsChangedListeners.add(listener);\n }\n\n removePromptsChangedListener(listener: MCPListChangedListener): void {\n this.promptsChangedListeners.delete(listener);\n }\n\n private emitCapabilityChanged(capability: 'resources' | 'prompts'): void {\n const listeners =\n capability === 'resources' ? this.resourcesChangedListeners : this.promptsChangedListeners;\n for (const listener of listeners) {\n try {\n listener(this.opts.name);\n } catch {\n /* listeners are best-effort */\n }\n }\n }\n}\n\n/**\n * Quote a single argument for `cmd.exe` when spawning with `shell: true` on\n * Windows. Only args containing whitespace or quotes need wrapping; inside\n * double quotes cmd.exe escapes a literal `\"` as `\"\"`. Backslashes are literal\n * inside cmd quotes, so paths like `C:\\Program Files\\x` pass through unharmed.\n */\nexport function quoteWindowsArg(arg: string): string {\n if (!/[\\s\"]/.test(arg)) return arg;\n return `\"${arg.replace(/\"/g, '\"\"')}\"`;\n}\n\nconst MAX_PROTOCOL_INPUT_CHARS = 8_192;\n\nfunction validateProtocolString(\n value: unknown,\n label: string,\n allowEmpty = false,\n): asserts value is string {\n if (typeof value !== 'string' || (!allowEmpty && value.length === 0)) {\n throw new Error(`MCP ${label} must be ${allowEmpty ? 'a string' : 'a non-empty string'}`);\n }\n if (value.length > MAX_PROTOCOL_INPUT_CHARS) {\n throw new Error(`MCP ${label} exceeds ${MAX_PROTOCOL_INPUT_CHARS} characters`);\n }\n}\n\nfunction pageParams(cursor: string | undefined, label: string): Record<string, string> {\n if (cursor === undefined) return {};\n validateProtocolString(cursor, label);\n return { cursor };\n}\n\nfunction parseEmptyResult(value: unknown): void {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error('Malformed MCP empty result: expected object');\n }\n}\n", "/**\n * Shared constants for the MCP package.\n *\n * Centralizing these values means:\n * - Protocol version and client identity are updated in one place\n * - Reconnect parameters can be overridden via config in the future\n * - No scattered magic values across multiple files\n */\nexport const MCP_CONSTANTS = Object.freeze({\n /** MCP protocol version advertised during handshake. */\n PROTOCOL_VERSION: '2024-11-05',\n\n /** Identity announced to MCP servers during `initialize`. */\n CLIENT_INFO: Object.freeze({\n name: 'wrongstack',\n version: '0.1.10',\n }),\n\n /** Reconnection behaviour when a transport disconnects. */\n RECONNECT: Object.freeze({\n /** Max full reconnect cycles before the slot is marked `failed`. */\n MAX_CYCLES: 5,\n /** Base delay between cycles (exponential backoff applied on top). */\n BASE_DELAY_MS: 1000,\n /** Jitter factor applied to the backoff (0 = no jitter, 1 = full). */\n JITTER_FACTOR: 0.2,\n /** Max connection attempts within a single cycle. */\n MAX_ATTEMPTS: 3,\n /** Base multiplier for the exponential backoff formula (`delay = BASE * multiplier^attempt`). */\n BACKOFF_MULTIPLIER: 2,\n }),\n\n /** Timing for graceful / forced disconnect. */\n DISCONNECT: Object.freeze({\n /** Ms to wait for in-flight requests to complete before force-closing. */\n GRACEFUL_MS: 800,\n /** Ms after which the force disconnect is triggered. */\n FORCE_TIMEOUT_MS: 1200,\n }),\n\n /** Lazy-connect idle lifecycle. */\n IDLE: Object.freeze({\n /** Default ms a lazy server stays connected with no tool calls before auto-sleep. */\n DEFAULT_TIMEOUT_MS: 300_000,\n /** How often the idle sweep runs (kept well below the timeout). */\n SWEEP_INTERVAL_MS: 30_000,\n }),\n\n /** JSON-RPC response timeout for outstanding requests. */\n RESPONSE_TIMEOUT_MS: 500,\n\n /** Max buffer size for the SSE reader. */\n SSE_READER_MAX_BUFFER: 256 * 1024,\n\n /** Max characters logged from a request body. */\n REQUEST_LOG_CAP: 1024,\n} as const);\n", "/** Typed MCP protocol surface for server discovery, resources, and prompts. */\n\nexport interface MCPImplementationInfo {\n name: string;\n version: string;\n title?: string | undefined;\n}\n\nexport interface MCPServerCapabilities {\n tools?: { listChanged?: boolean | undefined } | undefined;\n resources?: { subscribe?: boolean | undefined; listChanged?: boolean | undefined } | undefined;\n prompts?: { listChanged?: boolean | undefined } | undefined;\n logging?: Record<string, never> | undefined;\n [capability: string]: unknown;\n}\n\nexport interface MCPServerMetadata {\n protocolVersion: string;\n capabilities: MCPServerCapabilities;\n serverInfo: MCPImplementationInfo;\n instructions?: string | undefined;\n}\n\nexport interface MCPResource {\n uri: string;\n name: string;\n title?: string | undefined;\n description?: string | undefined;\n mimeType?: string | undefined;\n size?: number | undefined;\n annotations?: Record<string, unknown> | undefined;\n}\n\nexport interface MCPResourceTemplate {\n uriTemplate: string;\n name: string;\n title?: string | undefined;\n description?: string | undefined;\n mimeType?: string | undefined;\n annotations?: Record<string, unknown> | undefined;\n}\n\nexport interface MCPResourceContents {\n uri: string;\n mimeType?: string | undefined;\n text?: string | undefined;\n blob?: string | undefined;\n}\n\nexport interface MCPPromptArgument {\n name: string;\n description?: string | undefined;\n required?: boolean | undefined;\n}\n\nexport interface MCPPrompt {\n name: string;\n title?: string | undefined;\n description?: string | undefined;\n arguments?: MCPPromptArgument[] | undefined;\n}\n\nexport interface MCPPromptMessage {\n role: 'user' | 'assistant';\n /** Preserve text, image, audio, embedded-resource, and resource-link blocks. */\n content: unknown;\n}\n\nexport interface MCPListResourcesResult {\n resources: MCPResource[];\n nextCursor?: string | undefined;\n}\n\nexport interface MCPListResourceTemplatesResult {\n resourceTemplates: MCPResourceTemplate[];\n nextCursor?: string | undefined;\n}\n\nexport interface MCPReadResourceResult {\n contents: MCPResourceContents[];\n}\n\nexport interface MCPListPromptsResult {\n prompts: MCPPrompt[];\n nextCursor?: string | undefined;\n}\n\nexport interface MCPGetPromptResult {\n description?: string | undefined;\n messages: MCPPromptMessage[];\n}\n\nfunction record(value: unknown, label: string): Record<string, unknown> {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error(`Malformed MCP ${label}: expected object`);\n }\n return value as Record<string, unknown>;\n}\n\nfunction requiredString(value: unknown, label: string): string {\n if (typeof value !== 'string' || value.length === 0) {\n throw new Error(`Malformed MCP ${label}: expected non-empty string`);\n }\n return value;\n}\n\nfunction optionalString(value: unknown, label: string): string | undefined {\n if (value === undefined) return undefined;\n if (typeof value !== 'string') throw new Error(`Malformed MCP ${label}: expected string`);\n return value;\n}\n\nfunction optionalRecord(value: unknown, label: string): Record<string, unknown> | undefined {\n if (value === undefined) return undefined;\n return record(value, label);\n}\n\nfunction optionalCursor(value: unknown, label: string): string | undefined {\n return optionalString(value, `${label}.nextCursor`);\n}\n\nexport function parseServerMetadata(value: unknown): MCPServerMetadata {\n const input = record(value, 'initialize result');\n const serverInfo = record(input['serverInfo'], 'initialize.serverInfo');\n const capabilities = record(input['capabilities'], 'initialize.capabilities');\n return {\n protocolVersion: requiredString(input['protocolVersion'], 'initialize.protocolVersion'),\n capabilities: capabilities as MCPServerCapabilities,\n serverInfo: {\n name: requiredString(serverInfo['name'], 'initialize.serverInfo.name'),\n version: requiredString(serverInfo['version'], 'initialize.serverInfo.version'),\n title: optionalString(serverInfo['title'], 'initialize.serverInfo.title'),\n },\n instructions: optionalString(input['instructions'], 'initialize.instructions'),\n };\n}\n\nfunction parseResource(value: unknown, index: number): MCPResource {\n const input = record(value, `resources/list.resources[${index}]`);\n const size = input['size'];\n if (size !== undefined && (typeof size !== 'number' || !Number.isFinite(size) || size < 0)) {\n throw new Error(`Malformed MCP resources/list.resources[${index}].size`);\n }\n return {\n uri: requiredString(input['uri'], `resources/list.resources[${index}].uri`),\n name: requiredString(input['name'], `resources/list.resources[${index}].name`),\n title: optionalString(input['title'], `resources/list.resources[${index}].title`),\n description: optionalString(\n input['description'],\n `resources/list.resources[${index}].description`,\n ),\n mimeType: optionalString(input['mimeType'], `resources/list.resources[${index}].mimeType`),\n size: size as number | undefined,\n annotations: optionalRecord(\n input['annotations'],\n `resources/list.resources[${index}].annotations`,\n ),\n };\n}\n\nexport function parseListResourcesResult(value: unknown): MCPListResourcesResult {\n const input = record(value, 'resources/list result');\n if (!Array.isArray(input['resources'])) {\n throw new Error('Malformed MCP resources/list result: resources must be an array');\n }\n return {\n resources: input['resources'].map(parseResource),\n nextCursor: optionalCursor(input['nextCursor'], 'resources/list'),\n };\n}\n\nexport function parseListResourceTemplatesResult(value: unknown): MCPListResourceTemplatesResult {\n const input = record(value, 'resources/templates/list result');\n const templates = input['resourceTemplates'];\n if (!Array.isArray(templates)) {\n throw new Error(\n 'Malformed MCP resources/templates/list result: resourceTemplates must be an array',\n );\n }\n return {\n resourceTemplates: templates.map((value, index) => {\n const template = record(value, `resources/templates/list.resourceTemplates[${index}]`);\n return {\n uriTemplate: requiredString(\n template['uriTemplate'],\n `resources/templates/list.resourceTemplates[${index}].uriTemplate`,\n ),\n name: requiredString(\n template['name'],\n `resources/templates/list.resourceTemplates[${index}].name`,\n ),\n title: optionalString(\n template['title'],\n `resources/templates/list.resourceTemplates[${index}].title`,\n ),\n description: optionalString(\n template['description'],\n `resources/templates/list.resourceTemplates[${index}].description`,\n ),\n mimeType: optionalString(\n template['mimeType'],\n `resources/templates/list.resourceTemplates[${index}].mimeType`,\n ),\n annotations: optionalRecord(\n template['annotations'],\n `resources/templates/list.resourceTemplates[${index}].annotations`,\n ),\n };\n }),\n nextCursor: optionalCursor(input['nextCursor'], 'resources/templates/list'),\n };\n}\n\nexport function parseReadResourceResult(value: unknown): MCPReadResourceResult {\n const input = record(value, 'resources/read result');\n if (!Array.isArray(input['contents'])) {\n throw new Error('Malformed MCP resources/read result: contents must be an array');\n }\n return {\n contents: input['contents'].map((value, index) => {\n const content = record(value, `resources/read.contents[${index}]`);\n const text = optionalString(content['text'], `resources/read.contents[${index}].text`);\n const blob = optionalString(content['blob'], `resources/read.contents[${index}].blob`);\n if (text === undefined && blob === undefined) {\n throw new Error(`Malformed MCP resources/read.contents[${index}]: expected text or blob`);\n }\n return {\n uri: requiredString(content['uri'], `resources/read.contents[${index}].uri`),\n mimeType: optionalString(content['mimeType'], `resources/read.contents[${index}].mimeType`),\n text,\n blob,\n };\n }),\n };\n}\n\nfunction parsePromptArgument(\n value: unknown,\n promptIndex: number,\n argIndex: number,\n): MCPPromptArgument {\n const input = record(value, `prompts/list.prompts[${promptIndex}].arguments[${argIndex}]`);\n const required = input['required'];\n if (required !== undefined && typeof required !== 'boolean') {\n throw new Error(\n `Malformed MCP prompts/list.prompts[${promptIndex}].arguments[${argIndex}].required`,\n );\n }\n return {\n name: requiredString(\n input['name'],\n `prompts/list.prompts[${promptIndex}].arguments[${argIndex}].name`,\n ),\n description: optionalString(\n input['description'],\n `prompts/list.prompts[${promptIndex}].arguments[${argIndex}].description`,\n ),\n required: required as boolean | undefined,\n };\n}\n\nexport function parseListPromptsResult(value: unknown): MCPListPromptsResult {\n const input = record(value, 'prompts/list result');\n if (!Array.isArray(input['prompts'])) {\n throw new Error('Malformed MCP prompts/list result: prompts must be an array');\n }\n return {\n prompts: input['prompts'].map((value, index) => {\n const prompt = record(value, `prompts/list.prompts[${index}]`);\n const args = prompt['arguments'];\n if (args !== undefined && !Array.isArray(args)) {\n throw new Error(`Malformed MCP prompts/list.prompts[${index}].arguments`);\n }\n return {\n name: requiredString(prompt['name'], `prompts/list.prompts[${index}].name`),\n title: optionalString(prompt['title'], `prompts/list.prompts[${index}].title`),\n description: optionalString(\n prompt['description'],\n `prompts/list.prompts[${index}].description`,\n ),\n arguments: args?.map((arg, argIndex) => parsePromptArgument(arg, index, argIndex)),\n };\n }),\n nextCursor: optionalCursor(input['nextCursor'], 'prompts/list'),\n };\n}\n\nexport function parseGetPromptResult(value: unknown): MCPGetPromptResult {\n const input = record(value, 'prompts/get result');\n if (!Array.isArray(input['messages'])) {\n throw new Error('Malformed MCP prompts/get result: messages must be an array');\n }\n return {\n description: optionalString(input['description'], 'prompts/get.description'),\n messages: input['messages'].map((value, index) => {\n const message = record(value, `prompts/get.messages[${index}]`);\n const role = message['role'];\n if (role !== 'user' && role !== 'assistant') {\n throw new Error(`Malformed MCP prompts/get.messages[${index}].role`);\n }\n if (message['content'] === undefined) {\n throw new Error(`Malformed MCP prompts/get.messages[${index}].content`);\n }\n return { role, content: message['content'] };\n }),\n };\n}\n", "import type { MCPTool } from './client.js';\n\nexport function normalizeMCPTools(value: unknown): MCPTool[] {\n if (!Array.isArray(value)) return [];\n const tools: MCPTool[] = [];\n for (const raw of value) {\n if (!raw || typeof raw !== 'object') continue;\n const t = raw as {\n name?: unknown | undefined;\n description?: unknown | undefined;\n inputSchema?: unknown | undefined;\n };\n if (typeof t.name !== 'string' || t.name.trim().length === 0) continue;\n const inputSchema =\n t.inputSchema && typeof t.inputSchema === 'object' && !Array.isArray(t.inputSchema)\n ? (t.inputSchema as Record<string, unknown>)\n : { type: 'object', properties: {} };\n // Log when a tool's schema is absent or invalid \u2014 this could indicate a\n // broken, misbehaving, or (if the server is untrusted) adversarial MCP\n // server trying to confuse the LLM with misleading type info.\n if (!t.inputSchema || typeof t.inputSchema !== 'object' || Array.isArray(t.inputSchema)) {\n console.warn(\n JSON.stringify({\n level: 'warn',\n event: 'mcp.tool_schema_invalid',\n tool: t.name,\n message: 'no/invalid inputSchema \u2014 defaulting to empty object',\n timestamp: new Date().toISOString(),\n }),\n );\n }\n tools.push({\n name: t.name,\n ...(typeof t.description === 'string' ? { description: t.description } : {}),\n inputSchema,\n });\n }\n return tools;\n}\n", "import { ToolError } from '@wrongstack/core/types';\n\n/**\n * SSE-based MCP transport using native fetch.\n *\n * Communication pattern:\n * - Client connects to SSE endpoint to receive server messages (JSON-RPC events)\n * - Client sends JSON-RPC requests via HTTP POST to the same or separate endpoint\n * - Server sends results/errors via the SSE stream\n *\n * The SSE reader parses the SSE protocol (event:, data:, blank line to dispatch).\n */\n/**\n * Cap on the pending-line buffer. The upstream SSE parser\n * (packages/providers/src/sse.ts) already enforces 256 KB; this\n * reader is used only inside MCP HTTP transports, but defense-in-depth\n * says we should never let a malicious stream pin memory.\n */\nconst SSE_READER_MAX_BUFFER = 256 * 1024;\n/** Max data lines buffered per event before flush. Prevents a malicious\n * server from accumulating unbounded data: lines without a blank-line\n * delimiter would grow this array indefinitely. */\nconst SSE_READER_MAX_DATA_LINES = 1024;\n\nexport class SSEReader {\n private buffer = '';\n private dataLines: string[] = [];\n private listeners: Array<\n (event: {\n jsonrpc?: string | undefined;\n method?: string | undefined;\n params?: unknown | undefined;\n id?: number | undefined;\n }) => void\n > = [];\n\n onMessage(\n cb: (data: {\n jsonrpc?: string | undefined;\n method?: string | undefined;\n params?: unknown | undefined;\n id?: number | undefined;\n }) => void,\n ): () => void {\n this.listeners.push(cb);\n return () => {\n const idx = this.listeners.indexOf(cb);\n if (idx >= 0) this.listeners.splice(idx, 1);\n };\n }\n\n feed(chunk: string): void {\n // Guard against a single chunk that exceeds the buffer cap.\n if (chunk.length > SSE_READER_MAX_BUFFER) {\n throw new ToolError({\n message: `SSE: chunk size ${chunk.length} exceeds max buffer ${SSE_READER_MAX_BUFFER} \u2014 refusing to accumulate`,\n code: 'TOOL_EXECUTION_FAILED',\n toolName: 'mcp_transport_sse_reader',\n context: { phase: 'feed', chunkLength: chunk.length, maxBuffer: SSE_READER_MAX_BUFFER },\n });\n }\n this.buffer += chunk;\n if (this.buffer.length > SSE_READER_MAX_BUFFER) {\n throw new ToolError({\n message: `SSE: pending line exceeds ${SSE_READER_MAX_BUFFER} bytes \u2014 upstream is not framing events`,\n code: 'TOOL_EXECUTION_FAILED',\n toolName: 'mcp_transport_sse_reader',\n context: {\n phase: 'feed',\n bufferLength: this.buffer.length,\n maxBuffer: SSE_READER_MAX_BUFFER,\n },\n });\n }\n // Scan with a moving cursor and slice the retained tail ONCE at the end,\n // instead of `buffer = buffer.slice(idx+1)` per line (which re-copies the\n // whole remaining buffer for every newline \u2014 O(n\u00B2) for many small lines).\n let start = 0;\n let idx = this.buffer.indexOf('\\n', start);\n while (idx !== -1) {\n let end = idx;\n if (end > start && this.buffer.charCodeAt(end - 1) === 13 /* \\r */) end--;\n this.processLine(this.buffer.slice(start, end));\n start = idx + 1;\n idx = this.buffer.indexOf('\\n', start);\n }\n if (start > 0) this.buffer = this.buffer.slice(start);\n }\n\n private processLine(line: string): void {\n if (line === '') {\n this.flush();\n return;\n }\n if (line.startsWith(':')) return;\n\n const colonIdx = line.indexOf(':');\n const field = colonIdx === -1 ? line : line.slice(0, colonIdx);\n let value = colonIdx === -1 ? '' : line.slice(colonIdx + 1);\n if (value.startsWith(' ')) value = value.slice(1);\n\n if (field === 'event') {\n // The current transport only cares about JSON-RPC payloads in data\n // fields. Event names are accepted for spec compatibility.\n } else if (field === 'data') {\n if (this.dataLines.length >= SSE_READER_MAX_DATA_LINES) {\n throw new ToolError({\n message: `SSE: exceeded ${SSE_READER_MAX_DATA_LINES} data lines per event \u2014 upstream is not sending blank-line delimiters`,\n code: 'TOOL_EXECUTION_FAILED',\n toolName: 'mcp_transport_sse_reader',\n context: {\n phase: 'processLine',\n dataLineCount: this.dataLines.length,\n maxDataLines: SSE_READER_MAX_DATA_LINES,\n },\n });\n }\n this.dataLines.push(value);\n }\n }\n\n private flush(): void {\n if (this.dataLines.length === 0) {\n return;\n }\n const data = this.dataLines.join('\\n').trim();\n this.dataLines = [];\n if (!data) return;\n try {\n const parsed = JSON.parse(data) as {\n jsonrpc?: string | undefined;\n method?: string | undefined;\n params?: unknown | undefined;\n id?: number | undefined;\n };\n this.dispatch(parsed);\n } catch {\n // ignore parse errors\n }\n }\n\n private dispatch(msg: {\n jsonrpc?: string | undefined;\n method?: string | undefined;\n params?: unknown | undefined;\n id?: number | undefined;\n }): void {\n for (const cb of this.listeners) {\n try {\n cb(msg);\n } catch {\n /* ignore */\n }\n }\n }\n\n reset(): void {\n this.buffer = '';\n this.dataLines = [];\n this.listeners = [];\n }\n}\n", "import * as https from 'node:https';\nimport { ConfigError } from '@wrongstack/core/types';\nimport type { HttpDispatcher } from '@wrongstack/core/utils';\nimport {\n authorizationHeaderForToken,\n canonicalMcpResource,\n type MCPAuthorizationProvider,\n parseMcpBearerChallenge,\n} from './authorization.js';\nimport type { ConnectionState, MCPTool } from './client.js';\nimport type { MCPServerMetadata } from './protocol.js';\nimport { isTlsUnsafeAllowed, validateTransportUrl } from './transport-security.js';\n\nexport interface HttpTransportOptions {\n name: string;\n url: string;\n headers?: Record<string, string> | undefined;\n startupTimeoutMs?: number | undefined;\n requestTimeoutMs?: number | undefined;\n authorizationProvider?: MCPAuthorizationProvider | undefined;\n /**\n * Per-request TLS configuration. When set, an https.Agent is created\n * and passed to fetch via the `dispatch` option. This avoids globally\n * disabling certificate validation (NODE_TLS_REJECT_UNAUTHORIZED) which\n * would affect all provider API calls in the same process.\n *\n * \u26A0\uFE0F Security gate: `rejectUnauthorized: false` REQUIRES\n * `WRONGSTACK_UNSAFE_MCP_TLS=1` as an explicit opt-in.\n *\n * Without this gate, an active network attacker between the client and the\n * MCP server can read and modify tool calls and responses. Only use this\n * for local development with self-signed certificates; production MCP\n * servers must present a valid certificate.\n */\n tls?: { ca?: string | undefined; rejectUnauthorized?: boolean | undefined };\n}\n\n/**\n * Abort error whose `name` is `'AbortError'` so the core executor's\n * classifyToolError maps it to FATAL / not-retryable (user cancellation).\n */\nexport function makeAbortError(method: string): Error {\n const err = new Error(`MCP request \"${method}\" aborted by client`);\n err.name = 'AbortError';\n return err;\n}\n\nexport function createTimeoutSignal(\n parent: AbortSignal | undefined,\n timeoutMs: number,\n): { signal: AbortSignal; dispose: () => void } {\n const ctrl = new AbortController();\n const onAbort = () => ctrl.abort(parent?.reason);\n if (parent?.aborted) {\n ctrl.abort(parent.reason);\n } else {\n parent?.addEventListener('abort', onAbort, { once: true });\n }\n const timer = setTimeout(\n () => ctrl.abort(new Error(`MCP HTTP request timed out after ${timeoutMs}ms`)),\n timeoutMs,\n );\n return {\n signal: ctrl.signal,\n dispose: () => {\n clearTimeout(timer);\n parent?.removeEventListener('abort', onAbort);\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Shared base class \u2014 consolidates all duplicated fields, constructor logic,\n// and private helpers that are identical between SSETransport and\n// StreamableHTTPTransport.\n// ---------------------------------------------------------------------------\n\n/**\n * Fields and methods shared by all HTTP-based MCP transports.\n * Subclasses override `connect()`, `close()`, `callTool()`, `request()`.\n */\nexport abstract class BaseHTTPTransport {\n protected state: ConnectionState = 'idle';\n protected readonly url: string;\n protected readonly headers: Record<string, string>;\n protected readonly timeout: number;\n protected readonly requestTimeout: number;\n protected readonly name: string;\n protected readonly authorizationProvider?: MCPAuthorizationProvider | undefined;\n protected readonly authorizationResource: string;\n /** Per-request TLS agent \u2014 created once from HttpTransportOptions.tls */\n protected readonly tlsAgent?: https.Agent | undefined;\n protected readonly tools: MCPTool[] = [];\n protected serverMetadata?: MCPServerMetadata | undefined;\n protected abortController?: AbortController | undefined;\n protected readonly disconnectHandlers: Array<() => void> = [];\n protected readonly toolsChangedListeners = new Set<(tools: MCPTool[]) => void>();\n protected readonly resourcesChangedListeners = new Set<() => void>();\n protected readonly promptsChangedListeners = new Set<() => void>();\n protected protocolVersion?: string | undefined;\n\n constructor(opts: HttpTransportOptions, transportName: string) {\n validateTransportUrl(opts.url);\n this.name = opts.name;\n this.url = opts.url;\n this.headers = { ...opts.headers };\n this.authorizationProvider = opts.authorizationProvider;\n this.authorizationResource = canonicalMcpResource(opts.url);\n this.timeout = opts.startupTimeoutMs ?? 10_000;\n this.requestTimeout = opts.requestTimeoutMs ?? 60_000;\n if (opts.tls) {\n if (opts.tls.rejectUnauthorized === false) {\n if (!isTlsUnsafeAllowed()) {\n throw new ConfigError({\n message:\n `[mcp:${transportName}] TLS verification disabled \u2014 set WRONGSTACK_UNSAFE_MCP_TLS=1 ` +\n `to allow. Rejecting insecure configuration for ${this.url}.`,\n code: 'CONFIG_INVALID',\n context: { field: 'tls.rejectUnauthorized', transportName, url: this.url },\n });\n }\n console.error(\n `[mcp:${transportName}] \u26A0\uFE0F TLS verification DISABLED for ${this.url}. ` +\n `Network attacks are possible \u2014 only use on localhost.`,\n );\n }\n this.tlsAgent = new https.Agent({\n ca: opts.tls.ca,\n rejectUnauthorized: opts.tls.rejectUnauthorized,\n });\n }\n }\n\n getState(): ConnectionState {\n return this.state;\n }\n\n protected async fetchWithAuthorization(\n input: string,\n init: RequestInit,\n signal?: AbortSignal | undefined,\n ): Promise<Response> {\n const context = {\n serverName: this.name,\n resource: this.authorizationResource,\n signal,\n };\n const send = async (): Promise<Response> => {\n signal?.throwIfAborted();\n const headers = new Headers(init.headers);\n if (this.protocolVersion) headers.set('MCP-Protocol-Version', this.protocolVersion);\n const token = await this.authorizationProvider?.getAccessToken(context);\n signal?.throwIfAborted();\n if (token) {\n headers.set(\n 'Authorization',\n authorizationHeaderForToken(token, this.authorizationResource),\n );\n }\n return fetch(input, { ...init, headers });\n };\n\n let response = await send();\n if (response.status !== 401 || !this.authorizationProvider?.handleUnauthorized) {\n return response;\n }\n const challenge = parseMcpBearerChallenge(\n response.headers.get('www-authenticate'),\n this.authorizationResource,\n );\n const retry = await this.authorizationProvider.handleUnauthorized(challenge, context);\n if (!retry) return response;\n await response.body?.cancel().catch(() => undefined);\n response = await send();\n return response;\n }\n\n listTools(): MCPTool[] {\n return [...this.tools];\n }\n\n getServerMetadata(): MCPServerMetadata | undefined {\n const metadata = this.serverMetadata;\n if (!metadata) return undefined;\n return {\n ...metadata,\n capabilities: { ...metadata.capabilities },\n serverInfo: { ...metadata.serverInfo },\n };\n }\n\n onDisconnect(cb: () => void): () => void {\n this.disconnectHandlers.push(cb);\n return () => {\n const idx = this.disconnectHandlers.indexOf(cb);\n if (idx >= 0) this.disconnectHandlers.splice(idx, 1);\n };\n }\n\n onToolsChanged(cb: (tools: MCPTool[]) => void): () => void {\n this.toolsChangedListeners.add(cb);\n return () => {\n this.toolsChangedListeners.delete(cb);\n };\n }\n\n onResourcesChanged(cb: () => void): () => void {\n this.resourcesChangedListeners.add(cb);\n return () => this.resourcesChangedListeners.delete(cb);\n }\n\n onPromptsChanged(cb: () => void): () => void {\n this.promptsChangedListeners.add(cb);\n return () => this.promptsChangedListeners.delete(cb);\n }\n\n /**\n * Fire all disconnect handlers. Subclasses call this when the connection\n * drops so the registry can schedule reconnects.\n */\n protected notifyDisconnect(): void {\n for (const cb of this.disconnectHandlers) {\n try {\n cb();\n } catch {\n /* ignore */\n }\n }\n }\n\n protected notifyResourcesChanged(): void {\n for (const cb of this.resourcesChangedListeners) {\n try {\n cb();\n } catch {\n /* ignore */\n }\n }\n }\n\n protected notifyPromptsChanged(): void {\n for (const cb of this.promptsChangedListeners) {\n try {\n cb();\n } catch {\n /* ignore */\n }\n }\n }\n\n /**\n * Apply the pinned TLS agent (if configured) to a `RequestInit` object.\n * Uses `HttpDispatcher` from `@wrongstack/core`'s dispatcher-types shim,\n * which declares `https.Agent` compatible with `RequestInit.dispatcher`.\n * Verified safe: https.Agent implements the `dispatch(req, opts)` method\n * that fetch requires at runtime.\n */\n protected applyTlsAgent(fetchOpts: RequestInit): void {\n if (this.tlsAgent) {\n // The global `RequestInit.dispatcher` type now accepts `HttpDispatcher`\n // (see dispatcher-types.d.ts). The cast through `unknown` is the standard\n // pattern for \"I know this is compatible at runtime.\"\n fetchOpts.dispatcher = this.tlsAgent as never as HttpDispatcher;\n }\n }\n\n /** Generate the next JSON-RPC request id. Subclasses provide the counter. */\n protected abstract genId(): number;\n}\n", "import * as net from 'node:net';\nimport { ConfigError } from '@wrongstack/core/types';\n\nexport function isTlsUnsafeAllowed(): boolean {\n return process.env['WRONGSTACK_UNSAFE_MCP_TLS'] === '1';\n}\n\n/**\n * Validate that an MCP transport URL is not targeting private/internal\n * addresses. This is a defense-in-depth SSRF check \u2014 MCP servers are\n * typically local or LAN, but config manipulation could point to metadata\n * endpoints (169.254.169.254) or internal services.\n *\n * The check is intentionally lighter than fetch.ts's assertNotPrivate:\n * MCP URLs are admin-configured, not LLM-supplied, so we only block\n * the most obvious attack vectors.\n */\nexport function validateTransportUrl(rawUrl: string): void {\n let url: URL;\n try {\n url = new URL(rawUrl);\n } catch {\n throw new ConfigError({\n message: `MCP transport: invalid URL \"${rawUrl}\"`,\n code: 'CONFIG_INVALID',\n context: { field: 'url', rawUrl },\n });\n }\n\n if (url.protocol !== 'http:' && url.protocol !== 'https:') {\n throw new ConfigError({\n message: `MCP transport: unsupported protocol \"${url.protocol}\" \u2014 only http/https allowed`,\n code: 'CONFIG_INVALID',\n context: { field: 'url', rawUrl, protocol: url.protocol },\n });\n }\n\n const hostname = url.hostname;\n // URL.hostname keeps the brackets on IPv6 literals; strip them so net.isIP\n // and prefix checks see the bare address.\n const host =\n hostname.startsWith('[') && hostname.endsWith(']') ? hostname.slice(1, -1) : hostname;\n\n // Block cloud metadata endpoints (IMDS) \u2014 these are never valid MCP servers\n const ipVersion = net.isIP(host);\n if (ipVersion === 4) {\n const parts = host.split('.').map(Number);\n // 169.254.x.x (link-local / IMDS)\n if (parts[0] === 169 && parts[1] === 254) {\n throw new ConfigError({\n message: `MCP transport: blocked link-local/IMDS address \"${hostname}\" \u2014 likely not a valid MCP server`,\n code: 'CONFIG_INVALID',\n context: { field: 'url', rawUrl, hostname },\n });\n }\n } else if (ipVersion === 6) {\n const lower = host.toLowerCase();\n // fe80::/10 link-local (first hextet fe80\u2013febf) and the AWS IPv6 IMDS\n // address fd00:ec2::254 \u2014 the IPv6 counterparts of the IPv4 block above.\n const linkLocal = /^fe[89ab]/.test(lower);\n if (linkLocal || lower === 'fd00:ec2::254') {\n throw new ConfigError({\n message: `MCP transport: blocked link-local/IMDS address \"${hostname}\" \u2014 likely not a valid MCP server`,\n code: 'CONFIG_INVALID',\n context: { field: 'url', rawUrl, hostname },\n });\n }\n }\n\n // Plaintext http: is only permitted for loopback addresses where the\n // attacker would already need machine-level access. Remote HTTP MCP servers\n // must use TLS so an active network attacker cannot read or modify tool\n // calls and responses.\n if (url.protocol === 'http:') {\n const isLoopback =\n hostname === 'localhost' ||\n hostname === '127.0.0.1' ||\n hostname === '::1' ||\n hostname === '[::1]';\n if (!isLoopback) {\n throw new ConfigError({\n message: `MCP transport: http:// is only allowed for loopback addresses; use https:// for \"${hostname}\"`,\n code: 'CONFIG_INVALID',\n context: { field: 'url', rawUrl, hostname, protocol: url.protocol },\n });\n }\n }\n}\n", "import { ToolError } from '@wrongstack/core/types';\n\nexport type JsonRpcResult = {\n jsonrpc: '2.0';\n id: number;\n result?: unknown | undefined;\n error?: { code: number | undefined; message: string; data?: unknown | undefined } | undefined;\n};\n\ntype JsonRpcMethodEnvelope = {\n jsonrpc: '2.0';\n id?: number | string | undefined;\n method: string;\n params?: unknown | undefined;\n};\n\ntype JsonRpcEnvelope = JsonRpcResult | JsonRpcMethodEnvelope;\n\nexport function isJsonRpcResult(v: unknown): v is JsonRpcResult {\n if (typeof v !== 'object' || v === null) return false;\n const r = v as Record<string, unknown>;\n if (r['jsonrpc'] !== '2.0' || typeof r['id'] !== 'number') return false;\n if (Object.hasOwn(r, 'method')) return false;\n\n const hasResult = Object.hasOwn(r, 'result');\n const hasError = Object.hasOwn(r, 'error');\n if (hasResult === hasError) return false;\n if (hasError) {\n const error = r['error'];\n return (\n typeof error === 'object' &&\n error !== null &&\n typeof (error as Record<string, unknown>)['code'] === 'number' &&\n typeof (error as Record<string, unknown>)['message'] === 'string'\n );\n }\n return true;\n}\n\nfunction isJsonRpcMethodEnvelope(v: unknown): v is JsonRpcMethodEnvelope {\n if (typeof v !== 'object' || v === null) return false;\n const envelope = v as Record<string, unknown>;\n if (envelope['jsonrpc'] !== '2.0' || typeof envelope['method'] !== 'string') return false;\n const id = envelope['id'];\n return id === undefined || typeof id === 'number' || typeof id === 'string';\n}\n\n/**\n * Extract JSON-RPC envelopes from a streamable-http response body. Handles BOTH\n * plain NDJSON (one JSON object per line) AND SSE framing\n * (`event: message\\ndata: {...}` blocks) \u2014 modern MCP servers (e.g. Context7)\n * reply with `text/event-stream` even on a single POST, so the data must be\n * un-prefixed before parsing. Multi-line `data:` values within one event are\n * joined per the SSE spec.\n */\nexport function extractJsonRpcEnvelopes(text: string): JsonRpcEnvelope[] {\n const out: JsonRpcEnvelope[] = [];\n let dataBuf: string[] = [];\n const flush = () => {\n if (dataBuf.length === 0) return;\n const joined = dataBuf.join('\\n').trim();\n dataBuf = [];\n if (!joined) return;\n try {\n const parsed = JSON.parse(joined);\n if (isJsonRpcResult(parsed) || isJsonRpcMethodEnvelope(parsed)) out.push(parsed);\n } catch {\n /* ignore non-JSON event data */\n }\n };\n for (const raw of text.split('\\n')) {\n const line = raw.replace(/\\r$/, '');\n if (line === '') {\n flush(); // blank line ends an SSE event\n continue;\n }\n if (line.startsWith(':')) continue; // SSE comment\n if (line.startsWith('data:')) {\n let v = line.slice(5);\n if (v.startsWith(' ')) v = v.slice(1);\n dataBuf.push(v);\n continue;\n }\n if (line.startsWith('event:') || line.startsWith('id:') || line.startsWith('retry:')) {\n continue; // other SSE fields\n }\n // Plain NDJSON line (no SSE framing).\n const trimmed = line.trim();\n if (trimmed.startsWith('{') || trimmed.startsWith('[')) {\n try {\n const parsed = JSON.parse(trimmed);\n if (isJsonRpcResult(parsed) || isJsonRpcMethodEnvelope(parsed)) out.push(parsed);\n } catch {\n /* ignore */\n }\n }\n }\n flush();\n return out;\n}\n\n/** Extract only response envelopes; notifications and server requests are not responses. */\nexport function extractJsonRpcResults(text: string): JsonRpcResult[] {\n return extractJsonRpcEnvelopes(text).filter(isJsonRpcResult);\n}\n\nexport function assertMatchingJsonRpcResult(\n data: unknown,\n expectedId: number,\n method: string,\n): JsonRpcResult {\n if (!isJsonRpcResult(data)) {\n throw new ToolError({\n message: 'Invalid JSON-RPC response: not a JSON-RPC 2.0 envelope',\n code: 'TOOL_EXECUTION_FAILED',\n toolName: 'mcp_transport_jsonrpc',\n context: { method, expectedId, reason: 'not-jsonrpc-envelope' },\n });\n }\n if (data.id !== expectedId) {\n throw new ToolError({\n message: `Invalid JSON-RPC response: id mismatch for ${method} (expected ${expectedId}, got ${data.id})`,\n code: 'TOOL_EXECUTION_FAILED',\n toolName: 'mcp_transport_jsonrpc',\n context: { method, expectedId, actualId: data.id, reason: 'id-mismatch' },\n });\n }\n return data;\n}\n", "import { randomBytes } from 'node:crypto';\nimport { ToolError } from '@wrongstack/core/types';\nimport type { JsonRpcResponse, ToolCallResult } from './client.js';\nimport { MCP_CONSTANTS } from './constants.js';\nimport { parseServerMetadata } from './protocol.js';\nimport { readBodyCapped } from './read-body.js';\nimport { SSEReader } from './sse-reader.js';\nimport { normalizeMCPTools } from './tool-schema.js';\nimport {\n BaseHTTPTransport,\n createTimeoutSignal,\n type HttpTransportOptions,\n makeAbortError,\n} from './transport-base.js';\nimport { assertMatchingJsonRpcResult, type JsonRpcResult } from './transport-jsonrpc.js';\n\n// ---------------------------------------------------------------------------\n// SSE Transport\n// ---------------------------------------------------------------------------\n\n/**\n * SSE transport for MCP over HTTP.\n *\n * Uses native fetch API with ReadableStream to consume SSE events.\n * HTTP POST is used to send JSON-RPC requests.\n */\nexport class SSETransport extends BaseHTTPTransport {\n private _nextId = 1;\n private readerDone = false;\n private readLoopAbort?: AbortController | undefined;\n private reader?: globalThis.ReadableStreamDefaultReader<string> | undefined;\n\n constructor(opts: HttpTransportOptions) {\n super(opts, 'SSETransport');\n }\n\n protected override genId(): number {\n return this._nextId++;\n }\n\n /** Refresh tool list when server sends notifications/tools/list_changed. */\n private async handleToolsListChanged(): Promise<void> {\n try {\n const res = await this.httpPost('tools/list', {});\n if (!res.error) {\n this.tools.splice(\n 0,\n this.tools.length,\n ...normalizeMCPTools((res.result as { tools?: unknown | undefined } | undefined)?.tools),\n );\n for (const cb of this.toolsChangedListeners) {\n try {\n cb([...this.tools]);\n } catch {\n /* ignore */\n }\n }\n }\n } catch {\n /* ignore transient failures */\n }\n }\n\n async connect(): Promise<void> {\n this.state = 'connecting';\n this.serverMetadata = undefined;\n this.abortController = new AbortController();\n const signal = this.abortController.signal;\n const startupTimer = setTimeout(() => this.abortController?.abort(), this.timeout);\n\n try {\n const sseUrl = this.buildSSEUrl();\n const fetchOpts: RequestInit = {\n headers: this.headers,\n signal,\n };\n this.applyTlsAgent(fetchOpts);\n const response = await this.fetchWithAuthorization(sseUrl, fetchOpts, signal);\n\n if (!response.ok) {\n throw new ToolError({\n message: `SSE connect HTTP ${response.status}: ${response.statusText}`,\n code: 'TOOL_EXECUTION_FAILED',\n toolName: 'mcp_transport_sse_connect',\n context: { url: sseUrl, status: response.status, statusText: response.statusText },\n });\n }\n\n if (!response.body) {\n throw new ToolError({\n message: 'SSE response has no body',\n code: 'TOOL_EXECUTION_FAILED',\n toolName: 'mcp_transport_sse_connect',\n context: { url: sseUrl, reason: 'missing-body' },\n });\n }\n\n const textDecoder = new TextDecoder();\n const sseReader = new SSEReader();\n this.readLoopAbort = new AbortController();\n\n sseReader.onMessage((msg) => {\n // Server-initiated notifications (no id). Handle list_changed for L2-C.\n if (msg.method && !msg.id) {\n if (msg.method === 'notifications/tools/list_changed') {\n void this.handleToolsListChanged();\n } else if (msg.method === 'notifications/resources/list_changed') {\n this.notifyResourcesChanged();\n } else if (msg.method === 'notifications/prompts/list_changed') {\n this.notifyPromptsChanged();\n }\n }\n });\n\n const reader = response.body.getReader();\n this.reader = {\n cancel: () => reader.cancel(),\n releaseLock: () => reader.releaseLock(),\n } as globalThis.ReadableStreamDefaultReader<string>;\n\n this.readSSEBody(reader, textDecoder, sseReader);\n\n const initRes = await this.httpPost('initialize', {\n protocolVersion: MCP_CONSTANTS.PROTOCOL_VERSION,\n capabilities: { tools: {} },\n clientInfo: MCP_CONSTANTS.CLIENT_INFO,\n });\n\n if (initRes.error) {\n throw new ToolError({\n message: `initialize failed: ${initRes.error.message}`,\n code: 'TOOL_EXECUTION_FAILED',\n toolName: 'mcp_transport_initialize',\n context: { transport: 'sse', url: this.url },\n });\n }\n this.serverMetadata = parseServerMetadata(initRes.result);\n this.protocolVersion = this.serverMetadata.protocolVersion;\n\n try {\n await this.httpPost('notifications/initialized', {});\n } catch {\n // servers may not require it\n }\n\n const toolsRes = await this.httpPost('tools/list', {});\n if (toolsRes.error) {\n this.tools.splice(0, this.tools.length);\n } else {\n const result = toolsRes.result as { tools?: unknown | undefined } | undefined;\n this.tools.splice(0, this.tools.length, ...normalizeMCPTools(result?.tools));\n }\n\n this.state = 'connected';\n clearTimeout(startupTimer);\n } catch (err) {\n clearTimeout(startupTimer);\n this.state = 'failed';\n this.abortController.abort();\n throw err;\n }\n }\n\n private async readSSEBody(\n reader: globalThis.ReadableStreamDefaultReader<Uint8Array>,\n decoder: InstanceType<typeof TextDecoder>,\n sseReader: SSEReader,\n ): Promise<void> {\n try {\n while (!this.readerDone) {\n const { done, value } = await reader.read();\n if (done) break;\n const chunk = decoder.decode(value, { stream: true });\n sseReader.feed(chunk);\n }\n } catch {\n // SSE read error \u2014 connection lost. Transition to disconnected so\n // callTool and health checks see the correct state, then notify\n // disconnect handlers so the registry can schedule a reconnect.\n if (this.state !== 'disconnected' && this.state !== 'failed') {\n this.state = 'disconnected';\n this.notifyDisconnect();\n }\n }\n }\n\n private buildSSEUrl(): string {\n try {\n const url = new URL(this.url);\n // Cryptographically random session ID instead of timestamp \u2014\n // prevents an attacker on the same LAN from guessing the session\n // param and reconnecting to the SSE stream.\n url.searchParams.set('session', randomBytes(16).toString('hex'));\n return url.toString();\n } catch {\n return this.url;\n }\n }\n\n private async httpPost(\n method: string,\n params: unknown,\n opts?: { signal?: AbortSignal | undefined },\n ): Promise<JsonRpcResult> {\n const id = this.genId();\n const body = JSON.stringify({ jsonrpc: '2.0', id, method, params });\n\n const external = opts?.signal;\n const parent =\n external && this.abortController\n ? AbortSignal.any([this.abortController.signal, external])\n : (external ?? this.abortController?.signal);\n const timeoutSignal = createTimeoutSignal(parent, this.requestTimeout);\n const fetchOpts: RequestInit = {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...this.headers,\n },\n body,\n signal: timeoutSignal.signal,\n };\n this.applyTlsAgent(fetchOpts);\n // fetch lives INSIDE the try so dispose() runs on every exit path \u2014 a\n // rejected fetch must not leak the timeout timer / abort listener.\n try {\n const res = await this.fetchWithAuthorization(this.url, fetchOpts, timeoutSignal.signal);\n if (!res.ok) {\n // Cap the body \u2014 a misbehaving server could return megabytes of\n // HTML and that's not useful in an error message anyway.\n const body = await res.text();\n const cap = MCP_CONSTANTS.REQUEST_LOG_CAP;\n const snippet =\n body.length > cap ? `${body.slice(0, cap)}\u2026 [${body.length} bytes total]` : body;\n throw new ToolError({\n message: `HTTP ${res.status}: ${snippet}`,\n code: 'TOOL_EXECUTION_FAILED',\n toolName: method,\n context: { transport: 'sse', url: this.url, status: res.status },\n });\n }\n\n let data: unknown;\n try {\n data = JSON.parse(await readBodyCapped(res));\n } catch (err) {\n throw new ToolError({\n message: `Invalid JSON-RPC response: ${err instanceof Error ? err.message : 'parse failed'}`,\n code: 'TOOL_EXECUTION_FAILED',\n toolName: method,\n context: { transport: 'sse', url: this.url, phase: 'parse-json' },\n cause: err,\n });\n }\n return assertMatchingJsonRpcResult(data, id, method);\n } catch (err) {\n if (external?.aborted && !method.startsWith('notifications/')) {\n // MCP spec cancellation: tell the server to stop the in-flight\n // request. Best-effort fire-and-forget \u2014 the caller is already\n // unwinding on the abort.\n void this.httpPost('notifications/cancelled', {\n requestId: id,\n reason: 'client aborted',\n }).catch(() => {});\n throw makeAbortError(method);\n }\n throw err;\n } finally {\n timeoutSignal.dispose();\n }\n }\n\n async callTool(\n name: string,\n input: unknown,\n opts?: { signal?: AbortSignal | undefined },\n ): Promise<ToolCallResult> {\n if (this.state !== 'connected') {\n throw new ToolError({\n message: `SSE transport not connected (state=${this.state})`,\n code: 'TOOL_EXECUTION_FAILED',\n toolName: name,\n context: { transport: 'sse', state: this.state },\n });\n }\n const res = await this.httpPost('tools/call', { name, arguments: input }, opts);\n if (res.error) {\n return { content: res.error.message, isError: true };\n }\n const result = res.result as\n | { content?: unknown | undefined; isError?: boolean | undefined }\n | undefined;\n return {\n content: result?.content ?? '',\n isError: Boolean(result?.isError),\n };\n }\n\n /** Generic JSON-RPC request \u2014 used by MCPClient.request() for SSE transports. */\n async request(\n method: string,\n params: unknown,\n timeoutMs?: number,\n opts?: { signal?: AbortSignal | undefined },\n ): Promise<JsonRpcResponse> {\n const id = this.genId();\n const body = JSON.stringify({ jsonrpc: '2.0', id, method, params });\n\n const external = opts?.signal;\n const parent =\n external && this.abortController\n ? AbortSignal.any([this.abortController.signal, external])\n : (external ?? this.abortController?.signal);\n const timeoutSignal = createTimeoutSignal(parent, timeoutMs ?? this.requestTimeout);\n const fetchOpts: RequestInit = {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...this.headers,\n },\n body,\n signal: timeoutSignal.signal,\n };\n this.applyTlsAgent(fetchOpts);\n // dispose() clears the timeout timer and the parent-abort listener. It must\n // run on EVERY exit path (fetch rejection, !res.ok, JSON parse error,\n // mismatched result) \u2014 not just success \u2014 or the timer keeps ticking and the\n // abort listener leaks for the full timeout on each failed request.\n try {\n const res = await this.fetchWithAuthorization(this.url, fetchOpts, timeoutSignal.signal);\n\n if (!res.ok) {\n throw new ToolError({\n message: `HTTP ${res.status}: ${res.statusText}`,\n code: 'TOOL_EXECUTION_FAILED',\n toolName: method,\n context: {\n transport: 'sse',\n url: this.url,\n status: res.status,\n statusText: res.statusText,\n },\n });\n }\n\n let data: unknown;\n try {\n data = JSON.parse(await readBodyCapped(res));\n } catch (err) {\n throw new ToolError({\n message: `Invalid JSON-RPC response: ${err instanceof Error ? err.message : 'parse failed'}`,\n code: 'TOOL_EXECUTION_FAILED',\n toolName: method,\n context: { transport: 'sse', url: this.url, phase: 'parse-json' },\n cause: err,\n });\n }\n const result = assertMatchingJsonRpcResult(data, id, method);\n return { jsonrpc: '2.0', id, result: result.result, error: result.error };\n } catch (err) {\n if (external?.aborted && !method.startsWith('notifications/')) {\n void this.httpPost('notifications/cancelled', {\n requestId: id,\n reason: 'client aborted',\n }).catch(() => {});\n throw makeAbortError(method);\n }\n throw err;\n } finally {\n timeoutSignal.dispose();\n }\n }\n\n async close(): Promise<void> {\n // Idempotent \u2014 safe to call multiple times.\n if (this.state === 'disconnected') return;\n this.readerDone = true;\n this.readLoopAbort?.abort();\n try {\n this.reader?.cancel();\n } catch {\n /* ignore */\n }\n try {\n this.reader?.releaseLock();\n } catch {\n /* ignore */\n }\n this.abortController?.abort();\n this.disconnectHandlers.splice(0, this.disconnectHandlers.length);\n this.state = 'disconnected';\n }\n}\n", "import { ToolError } from '@wrongstack/core/types';\n\n/**\n * Hard cap on a buffered HTTP response body, matching the stdio transport's\n * 16 MiB rx cap. The stdio path and the SSE stream reader are both bounded, but\n * the streamable-http / SSE request-response paths buffered the whole body with\n * `res.text()` / `res.json()`. A malicious or buggy server (or a MITM when\n * `WRONGSTACK_UNSAFE_MCP_TLS=1` disables cert checks) could return a multi-GB\n * body and OOM-crash the host.\n */\nexport const MAX_MCP_HTTP_BODY_BYTES = 16 * 1024 * 1024;\n\ninterface ReadableResponse {\n body: ReadableStream<Uint8Array> | null;\n text(): Promise<string>;\n}\n\n/**\n * Read a response body to text, refusing to buffer more than `maxBytes`. Falls\n * back to `res.text()` when the body is not a web stream (empty bodies, test\n * fakes) \u2014 those paths are small and controlled.\n */\nexport async function readBodyCapped(\n res: ReadableResponse,\n maxBytes: number = MAX_MCP_HTTP_BODY_BYTES,\n): Promise<string> {\n const body = res.body;\n if (!body || typeof body.getReader !== 'function') {\n return await res.text();\n }\n const reader = body.getReader();\n const chunks: Uint8Array[] = [];\n let total = 0;\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n if (!value) continue;\n total += value.byteLength;\n if (total > maxBytes) {\n await reader.cancel().catch(() => undefined);\n throw new ToolError({\n message: `MCP response body exceeded ${maxBytes} bytes \u2014 refusing to buffer`,\n code: 'TOOL_EXECUTION_FAILED',\n toolName: 'mcp_transport',\n context: { maxBytes, received: total },\n });\n }\n chunks.push(value);\n }\n } finally {\n reader.releaseLock?.();\n }\n return Buffer.concat(chunks).toString('utf8');\n}\n", "import type { JsonRpcResponse, ToolCallResult } from './client.js';\nimport { MCP_CONSTANTS } from './constants.js';\nimport { parseServerMetadata } from './protocol.js';\nimport { readBodyCapped } from './read-body.js';\nimport { normalizeMCPTools } from './tool-schema.js';\nimport {\n BaseHTTPTransport,\n createTimeoutSignal,\n type HttpTransportOptions,\n makeAbortError,\n} from './transport-base.js';\nimport {\n assertMatchingJsonRpcResult,\n extractJsonRpcEnvelopes,\n extractJsonRpcResults,\n isJsonRpcResult,\n type JsonRpcResult,\n} from './transport-jsonrpc.js';\n\n// ---------------------------------------------------------------------------\n// Streamable HTTP Transport\n// ---------------------------------------------------------------------------\n\n/**\n * Streamable HTTP transport for MCP.\n *\n * Uses session-based HTTP with NDJSON responses.\n */\nexport class StreamableHTTPTransport extends BaseHTTPTransport {\n private _nextId = 1;\n private sessionId?: string | undefined;\n\n constructor(opts: HttpTransportOptions) {\n super(opts, 'StreamableHTTP');\n }\n\n protected override genId(): number {\n return this._nextId++;\n }\n\n private consumeResponseText(text: string, requestId: number): JsonRpcResult | undefined {\n const envelopes = extractJsonRpcEnvelopes(text);\n for (const envelope of envelopes) {\n if ('method' in envelope && envelope.id === undefined) {\n this.handleNotification(envelope.method);\n }\n }\n const responses = envelopes.filter(isJsonRpcResult);\n return responses.find((envelope) => envelope.id === requestId) ?? responses[0];\n }\n\n private handleNotification(method: string): void {\n if (method === 'notifications/resources/list_changed') {\n this.notifyResourcesChanged();\n } else if (method === 'notifications/prompts/list_changed') {\n this.notifyPromptsChanged();\n } else if (method === 'notifications/tools/list_changed') {\n void this.refreshTools();\n }\n }\n\n private async refreshTools(): Promise<void> {\n try {\n const response = await this.postRaw('tools/list', {});\n if (response.error) return;\n const tools = normalizeMCPTools(\n (response.result as { tools?: unknown | undefined } | undefined)?.tools,\n );\n this.tools.splice(0, this.tools.length, ...tools);\n for (const listener of this.toolsChangedListeners) {\n try {\n listener([...tools]);\n } catch {\n /* ignore */\n }\n }\n } catch {\n /* keep the last known tool catalog */\n }\n }\n\n async connect(): Promise<void> {\n this.state = 'connecting';\n this.serverMetadata = undefined;\n this.abortController = new AbortController();\n const signal = this.abortController.signal;\n const startupTimer = setTimeout(() => this.abortController?.abort(), this.timeout);\n\n try {\n const initFetchOpts: RequestInit = {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'application/json, text/event-stream',\n ...this.headers,\n },\n body: JSON.stringify({\n jsonrpc: '2.0',\n id: this.genId(),\n method: 'initialize',\n params: {\n protocolVersion: MCP_CONSTANTS.PROTOCOL_VERSION,\n capabilities: { tools: {} },\n clientInfo: MCP_CONSTANTS.CLIENT_INFO,\n },\n }),\n signal,\n };\n this.applyTlsAgent(initFetchOpts);\n const initRes = await this.fetchWithAuthorization(this.url, initFetchOpts, signal);\n\n if (!initRes.ok) {\n throw new Error(`initialize HTTP ${initRes.status}: ${initRes.statusText}`);\n }\n\n const contentType = initRes.headers.get('content-type') ?? '';\n let data: JsonRpcResult | undefined;\n\n if (contentType.includes('application/json')) {\n const parsed = await initRes.json();\n if (isJsonRpcResult(parsed)) data = parsed;\n } else {\n // text/event-stream or NDJSON \u2014 handle SSE `data:` framing.\n data = extractJsonRpcResults(await initRes.text())[0];\n }\n\n if (!data) {\n throw new Error('Could not parse initialize response');\n }\n data = assertMatchingJsonRpcResult(data, this._nextId - 1, 'initialize');\n\n if (data.error) {\n throw new Error(`initialize failed: ${data.error.message}`);\n }\n this.serverMetadata = parseServerMetadata(data.result);\n this.protocolVersion = this.serverMetadata.protocolVersion;\n\n // MCP Streamable HTTP spec: the server assigns a session via the\n // `Mcp-Session-Id` response header, which the client must echo on every\n // subsequent request. (Header lookups are case-insensitive.)\n this.sessionId = initRes.headers.get('mcp-session-id') ?? undefined;\n await this.postRaw('notifications/initialized', {});\n\n const toolsRes = await this.postRaw('tools/list', {});\n if (toolsRes.error) {\n this.tools.splice(0, this.tools.length);\n } else {\n const result = toolsRes.result as { tools?: unknown | undefined } | undefined;\n this.tools.splice(0, this.tools.length, ...normalizeMCPTools(result?.tools));\n }\n\n this.state = 'connected';\n clearTimeout(startupTimer);\n } catch (err) {\n clearTimeout(startupTimer);\n this.state = 'failed';\n this.abortController.abort();\n throw err;\n }\n }\n\n private async postRaw(\n method: string,\n params: unknown,\n opts?: { signal?: AbortSignal | undefined },\n ): Promise<JsonRpcResult> {\n const id = this.genId();\n const body = JSON.stringify({ jsonrpc: '2.0', id, method, params });\n\n const external = opts?.signal;\n const parent =\n external && this.abortController\n ? AbortSignal.any([this.abortController.signal, external])\n : (external ?? this.abortController?.signal);\n const timeoutSignal = createTimeoutSignal(parent, this.requestTimeout);\n const fetchOpts: RequestInit = {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'application/json, text/event-stream',\n ...(this.sessionId ? { 'Mcp-Session-Id': this.sessionId } : {}),\n ...this.headers,\n },\n body,\n signal: timeoutSignal.signal,\n };\n this.applyTlsAgent(fetchOpts);\n // fetch lives INSIDE the try so dispose() runs on every exit path \u2014 a\n // rejected fetch must not leak the timeout timer / abort listener.\n try {\n const res = await this.fetchWithAuthorization(this.url, fetchOpts, timeoutSignal.signal);\n if (!res.ok) {\n throw new Error(`HTTP ${res.status}: ${res.statusText}`);\n }\n\n // Notifications get no JSON-RPC reply (the server returns 202 / empty body).\n if (method.startsWith('notifications/')) {\n await res.text().catch(() => undefined);\n return { jsonrpc: '2.0', id };\n }\n\n const match = this.consumeResponseText(await readBodyCapped(res), id);\n if (match) {\n return assertMatchingJsonRpcResult(match, id, method);\n }\n throw new Error('Could not parse response as JSON-RPC');\n } catch (err) {\n if (external?.aborted && !method.startsWith('notifications/')) {\n // MCP spec cancellation: tell the server to stop the in-flight\n // request. Best-effort fire-and-forget.\n void this.postRaw('notifications/cancelled', {\n requestId: id,\n reason: 'client aborted',\n }).catch(() => {});\n throw makeAbortError(method);\n }\n throw err;\n } finally {\n timeoutSignal.dispose();\n }\n }\n\n /** Generic JSON-RPC request \u2014 used by MCPClient.request() for SSE/streamable-http transports. */\n async request(\n method: string,\n params: unknown,\n timeoutMs?: number,\n opts?: { signal?: AbortSignal | undefined },\n ): Promise<JsonRpcResponse> {\n const id = this.genId();\n const body = JSON.stringify({ jsonrpc: '2.0', id, method, params });\n\n const external = opts?.signal;\n const parent =\n external && this.abortController\n ? AbortSignal.any([this.abortController.signal, external])\n : (external ?? this.abortController?.signal);\n const timeoutSignal = createTimeoutSignal(parent, timeoutMs ?? this.requestTimeout);\n const fetchOpts: RequestInit = {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'application/json, text/event-stream',\n ...(this.sessionId ? { 'Mcp-Session-Id': this.sessionId } : {}),\n ...this.headers,\n },\n body,\n signal: timeoutSignal.signal,\n };\n this.applyTlsAgent(fetchOpts);\n try {\n const res = await this.fetchWithAuthorization(this.url, fetchOpts, timeoutSignal.signal);\n if (!res.ok) {\n throw new Error(`HTTP ${res.status}: ${res.statusText}`);\n }\n\n if (method.startsWith('notifications/')) {\n await res.text().catch(() => undefined);\n return { jsonrpc: '2.0', id };\n }\n\n const parsed = this.consumeResponseText(await readBodyCapped(res), id);\n if (parsed) {\n // Convert JsonRpcResult to JsonRpcResponse\n return {\n jsonrpc: '2.0',\n id,\n result: parsed.result,\n error: parsed.error,\n };\n }\n throw new Error('Could not parse response as JSON-RPC');\n } catch (err) {\n if (external?.aborted && !method.startsWith('notifications/')) {\n void this.postRaw('notifications/cancelled', {\n requestId: id,\n reason: 'client aborted',\n }).catch(() => {});\n throw makeAbortError(method);\n }\n throw err;\n } finally {\n timeoutSignal.dispose();\n }\n }\n\n async callTool(\n name: string,\n input: unknown,\n opts?: { signal?: AbortSignal | undefined },\n ): Promise<ToolCallResult> {\n if (this.state !== 'connected') {\n throw new Error(`streamable-http transport not connected (state=${this.state})`);\n }\n const res = await this.postRaw('tools/call', { name, arguments: input }, opts);\n if (res.error) {\n return { content: res.error.message, isError: true };\n }\n const result = res.result as\n | { content?: unknown | undefined; isError?: boolean | undefined }\n | undefined;\n return {\n content: result?.content ?? '',\n isError: Boolean(result?.isError),\n };\n }\n\n async close(): Promise<void> {\n if (this.state === 'disconnected') return;\n this.state = 'disconnected';\n this.abortController?.abort();\n // Intentionally do NOT fire disconnect handlers \u2014 those trigger\n // reconnection in the registry, which would fight an explicit close().\n this.disconnectHandlers.splice(0, this.disconnectHandlers.length);\n }\n}\n", "import type {\n MCPGetPromptResult,\n MCPPromptMessage,\n MCPReadResourceResult,\n MCPResourceContents,\n} from './protocol.js';\n\nexport const DEFAULT_MCP_INSERTION_MAX_BYTES = 256 * 1024;\nexport const DEFAULT_MCP_RESOURCE_SCHEMES = [\n 'file',\n 'git',\n 'http',\n 'https',\n 'mcp',\n 'mem',\n 'repo',\n 'resource',\n] as const;\n\nexport interface MCPInsertionPolicy {\n maxBytes?: number | undefined;\n allowedUriSchemes?: readonly string[] | undefined;\n}\n\nexport interface MCPContentProvenance {\n origin: 'mcp';\n serverName: string;\n capability: 'resource' | 'prompt';\n resourceUri?: string | undefined;\n promptName?: string | undefined;\n promptArgumentNames?: string[] | undefined;\n}\n\nexport interface MCPResourceInsertion {\n kind: 'resource';\n untrusted: true;\n byteSize: number;\n provenance: MCPContentProvenance;\n contents: MCPResourceContents[];\n}\n\nexport interface MCPPromptInsertion {\n kind: 'prompt';\n untrusted: true;\n byteSize: number;\n provenance: MCPContentProvenance;\n description?: string | undefined;\n messages: MCPPromptMessage[];\n}\n\nexport function prepareResourceInsertion(\n serverName: string,\n requestedUri: string,\n result: MCPReadResourceResult,\n policy: MCPInsertionPolicy = {},\n): MCPResourceInsertion {\n requireIdentity(serverName, 'server name');\n validateUri(requestedUri, policy);\n if (result.contents.length > 64) {\n throw new Error('MCP resource insertion exceeds the limit of 64 content blocks');\n }\n let byteSize = 0;\n for (const content of result.contents) {\n validateUri(content.uri, policy);\n if (content.text !== undefined) byteSize += utf8Bytes(content.text);\n if (content.blob !== undefined) byteSize += base64DecodedBytes(content.blob);\n enforceSize(byteSize, policy);\n }\n return {\n kind: 'resource',\n untrusted: true,\n byteSize,\n provenance: {\n origin: 'mcp',\n serverName,\n capability: 'resource',\n resourceUri: requestedUri,\n },\n contents: structuredClone(result.contents),\n };\n}\n\nexport function preparePromptInsertion(\n serverName: string,\n promptName: string,\n args: Record<string, string> | undefined,\n result: MCPGetPromptResult,\n policy: MCPInsertionPolicy = {},\n): MCPPromptInsertion {\n requireIdentity(serverName, 'server name');\n requireIdentity(promptName, 'prompt name');\n if (result.messages.length > 128) {\n throw new Error('MCP prompt insertion exceeds the limit of 128 messages');\n }\n for (const message of result.messages) validateEmbeddedUris(message.content, policy, 0);\n let serialized: string;\n try {\n serialized = JSON.stringify(result.messages);\n } catch {\n throw new Error('MCP prompt insertion contains non-serializable content');\n }\n const byteSize = utf8Bytes(serialized);\n enforceSize(byteSize, policy);\n return {\n kind: 'prompt',\n untrusted: true,\n byteSize,\n provenance: {\n origin: 'mcp',\n serverName,\n capability: 'prompt',\n promptName,\n promptArgumentNames: Object.keys(args ?? {}).sort(),\n },\n description: result.description,\n messages: structuredClone(result.messages),\n };\n}\n\nfunction validateEmbeddedUris(value: unknown, policy: MCPInsertionPolicy, depth: number): void {\n if (depth > 32) throw new Error('MCP prompt insertion exceeds the nesting depth limit');\n if (Array.isArray(value)) {\n for (const item of value) validateEmbeddedUris(item, policy, depth + 1);\n return;\n }\n if (!value || typeof value !== 'object') return;\n for (const [key, nested] of Object.entries(value as Record<string, unknown>)) {\n if (key === 'uri' && typeof nested === 'string') validateUri(nested, policy);\n validateEmbeddedUris(nested, policy, depth + 1);\n }\n}\n\nfunction validateUri(uri: string, policy: MCPInsertionPolicy): void {\n if (uri.length === 0 || uri.length > 8_192) {\n throw new Error('MCP insertion URI must contain 1\u20138192 characters');\n }\n let parsed: URL;\n try {\n parsed = new URL(uri);\n } catch {\n throw new Error('MCP insertion URI must be absolute');\n }\n const scheme = parsed.protocol.slice(0, -1).toLowerCase();\n const allowed = new Set(\n (policy.allowedUriSchemes ?? DEFAULT_MCP_RESOURCE_SCHEMES).map((value) => value.toLowerCase()),\n );\n if (!allowed.has(scheme)) {\n throw new Error(`MCP insertion URI scheme \"${scheme}\" is not allowed`);\n }\n if ((scheme === 'http' || scheme === 'https') && (parsed.username || parsed.password)) {\n throw new Error('MCP insertion URI must not contain credentials');\n }\n}\n\nfunction enforceSize(byteSize: number, policy: MCPInsertionPolicy): void {\n const maxBytes = policy.maxBytes ?? DEFAULT_MCP_INSERTION_MAX_BYTES;\n if (!Number.isSafeInteger(maxBytes) || maxBytes <= 0) {\n throw new Error('MCP insertion maxBytes must be a positive safe integer');\n }\n if (byteSize > maxBytes) {\n throw new Error(`MCP insertion exceeds the ${maxBytes}-byte content limit`);\n }\n}\n\nfunction base64DecodedBytes(blob: string): number {\n if (!/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(blob)) {\n throw new Error('MCP resource insertion contains invalid base64 content');\n }\n const padding = blob.endsWith('==') ? 2 : blob.endsWith('=') ? 1 : 0;\n return (blob.length / 4) * 3 - padding;\n}\n\nfunction utf8Bytes(value: string): number {\n return new TextEncoder().encode(value).byteLength;\n}\n\nfunction requireIdentity(value: string, label: string): void {\n if (value.length === 0 || value.length > 256) {\n throw new Error(`MCP insertion ${label} must contain 1\u2013256 characters`);\n }\n}\n", "/**\n * Shared, surface-agnostic MCP server management.\n *\n * One source of truth for add / update / remove / enable / disable / restart /\n * discover / list. Every surface delegates here so the REPL (`/mcp`), the TUI,\n * and BOTH WebUI servers behave identically and never drift:\n *\n * - REPL / TUI : packages/cli/src/slash-commands/mcp-utils.ts (colored strings)\n * - WebUI : packages/webui/src/server/mcp-handlers.ts (WS events)\n *\n * The functions are pure with respect to rendering \u2014 they mutate the config\n * file on disk and the live {@link MCPRegistry}, then return structured results.\n * Callers translate those results into whatever their surface needs.\n *\n * MCP records live in two places:\n * - persistent : active profile `config.json` \u2192 `mcpServers`\n * - live state : the in-process {@link MCPRegistry}\n */\nimport { randomBytes } from 'node:crypto';\nimport * as fs from 'node:fs/promises';\nimport type { MCPHealthConfig, MCPServerConfig, Permission } from '@wrongstack/core/types';\nimport type { MCPRegistry } from './registry.js';\n\n/** Transport values accepted from UI surfaces (UI also offers a bare \"http\"). */\ntype TransportInput = 'stdio' | 'sse' | 'streamable-http' | 'http';\n\n/** Loosely-typed server input as it arrives from a UI or command surface. */\nexport interface McpServerInput {\n name: string;\n transport?: TransportInput | string | undefined;\n description?: string | undefined;\n enabled?: boolean | undefined;\n command?: string | undefined;\n args?: string[] | undefined;\n env?: Record<string, string> | undefined;\n url?: string | undefined;\n headers?: Record<string, string> | undefined;\n allowedTools?: string[] | undefined;\n permission?: Permission | undefined;\n /** Lazy connect \u2014 spawn the process only on first tool call (see config). */\n lazy?: boolean | undefined;\n /** Env var names to forward from parent process at spawn time. */\n passthroughEnv?: string[] | undefined;\n /** Operational-health thresholds (optional; omitted means no threshold checks). */\n health?: MCPHealthConfig | undefined;\n}\n\n/** Projected view of one server, merging disk config with live registry state. */\nexport interface McpServerInfo {\n name: string;\n transport: MCPServerConfig['transport'];\n description?: string | undefined;\n enabled: boolean;\n /** Raw registry state ('connected' | 'connecting' | \u2026 | 'failed'), or 'stopped' when not running. */\n status: string;\n /** Real tool names discovered from the live server (empty when not connected). */\n tools: string[];\n url?: string | undefined;\n command?: string | undefined;\n args?: string[] | undefined;\n env?: Record<string, string> | undefined;\n /** Lazy-connect opt-in (spawn on first tool call). */\n lazy?: boolean | undefined;\n}\n\nexport interface McpOpResult {\n ok: boolean;\n message: string;\n /** The affected server's projected view, when applicable. */\n server?: McpServerInfo | undefined;\n /** Raw registry state after a start/restart attempt. */\n state?: string | undefined;\n /** Real tool names after a start/restart attempt. */\n tools?: string[] | undefined;\n /** Set when a config change persisted but the registry start/stop failed. */\n registryError?: string | undefined;\n}\n\nexport interface McpManageDeps {\n /** Absolute path to the active profile config.json that owns `mcpServers`. */\n configPath: string;\n /** Live registry for runtime start/stop/restart. */\n registry: MCPRegistry;\n /** Built-in presets (from core `allServers()`), used by name-only `add`. */\n presets?: Record<string, MCPServerConfig> | undefined;\n}\n\n// \u2500\u2500 config IO (atomic) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nasync function readConfig(path: string): Promise<Record<string, unknown>> {\n try {\n return JSON.parse(await fs.readFile(path, 'utf8')) as Record<string, unknown>;\n } catch {\n return {};\n }\n}\n\nasync function writeConfig(path: string, cfg: Record<string, unknown>): Promise<void> {\n const raw = JSON.stringify(cfg, null, 2);\n // Unique temp name (pid + random) so two concurrent writers (e.g. WebUI and\n // REPL editing MCP config at once) don't clobber a shared `${path}.tmp` and\n // corrupt the config. Clean up the temp file if the rename fails.\n const tmp = `${path}.${process.pid}.${randomBytes(6).toString('hex')}.tmp`;\n await fs.writeFile(tmp, raw, 'utf8');\n try {\n await fs.rename(tmp, path);\n } catch (err) {\n await fs.rm(tmp, { force: true });\n throw err;\n }\n}\n\nfunction isMcpServerRecord(value: unknown): value is Record<string, MCPServerConfig> {\n return !!value && typeof value === 'object' && !Array.isArray(value);\n}\n\nasync function readServers(configPath: string): Promise<{\n full: Record<string, unknown>;\n servers: Record<string, MCPServerConfig>;\n}> {\n const full = await readConfig(configPath);\n const servers = isMcpServerRecord(full.mcpServers) ? { ...full.mcpServers } : {};\n return { full, servers };\n}\n\nasync function persist(\n configPath: string,\n full: Record<string, unknown>,\n servers: Record<string, MCPServerConfig>,\n): Promise<void> {\n full.mcpServers = servers;\n await writeConfig(configPath, full);\n}\n\n// \u2500\u2500 helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Normalise UI transport values; UI offers a bare \"http\" \u2192 streamable-http. */\nfunction normalizeTransport(t: string | undefined): MCPServerConfig['transport'] {\n if (t === 'sse') return 'sse';\n if (t === 'http' || t === 'streamable-http') return 'streamable-http';\n return 'stdio';\n}\n\n/**\n * Build a clean MCPServerConfig from loose input, omitting undefined keys so\n * `exactOptionalPropertyTypes` stays satisfied and we never write `null`-ish\n * holes into config.json. `base` lets `update` merge onto an existing entry.\n */\nfunction buildConfig(input: McpServerInput, base?: MCPServerConfig | undefined): MCPServerConfig {\n const cfg: MCPServerConfig = {\n name: input.name,\n transport: input.transport\n ? normalizeTransport(String(input.transport))\n : (base?.transport ?? 'stdio'),\n };\n const description = input.description ?? base?.description;\n if (description !== undefined) cfg.description = description;\n const command = input.command ?? base?.command;\n if (command !== undefined) cfg.command = command;\n const args = input.args ?? base?.args;\n if (args !== undefined) cfg.args = args;\n const env = input.env ?? base?.env;\n if (env !== undefined) cfg.env = env;\n const url = input.url ?? base?.url;\n if (url !== undefined) cfg.url = url;\n const headers = input.headers ?? base?.headers;\n if (headers !== undefined) cfg.headers = headers;\n const allowedTools = input.allowedTools ?? base?.allowedTools;\n if (allowedTools !== undefined) cfg.allowedTools = allowedTools;\n const permission = input.permission ?? base?.permission;\n if (permission !== undefined) cfg.permission = permission;\n const enabled = input.enabled ?? base?.enabled;\n if (enabled !== undefined) cfg.enabled = enabled;\n const lazy = input.lazy ?? base?.lazy;\n if (lazy !== undefined) cfg.lazy = lazy;\n const passthroughEnv = input.passthroughEnv ?? base?.passthroughEnv;\n if (passthroughEnv !== undefined) cfg.passthroughEnv = passthroughEnv;\n const health = input.health ?? base?.health;\n if (health !== undefined) cfg.health = health;\n return cfg;\n}\n\n/** Project a config entry + live registry state into a wire-friendly view. */\nfunction projectServer(name: string, cfg: MCPServerConfig, registry: MCPRegistry): McpServerInfo {\n const live = registry.list().find((s) => s.name === name);\n const info: McpServerInfo = {\n name,\n transport: cfg.transport,\n enabled: cfg.enabled !== false,\n status: live ? live.state : 'stopped',\n tools: live?.tools ?? [],\n };\n if (cfg.description !== undefined) info.description = cfg.description;\n if (cfg.url !== undefined) info.url = cfg.url;\n if (cfg.command !== undefined) info.command = cfg.command;\n if (cfg.args !== undefined) info.args = cfg.args;\n if (cfg.env !== undefined) info.env = cfg.env;\n if (cfg.lazy !== undefined) info.lazy = cfg.lazy;\n return info;\n}\n\nfunction liveState(name: string, registry: MCPRegistry): { state: string; tools: string[] } {\n const live = registry.list().find((s) => s.name === name);\n return { state: live?.state ?? 'stopped', tools: live?.tools ?? [] };\n}\n\nfunction errMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\n// \u2500\u2500 operations \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** List all configured servers, merged with live registry status + tool names. */\nexport async function listMcp(deps: McpManageDeps): Promise<McpServerInfo[]> {\n const { servers } = await readServers(deps.configPath);\n return Object.entries(servers).map(([name, cfg]) =>\n projectServer(name, { ...cfg, name }, deps.registry),\n );\n}\n\n/**\n * Add a new server. `input` may be a fully-specified config, or just a `name`\n * matching a known preset (`deps.presets`). Fails if the server already exists.\n * When enabled, the server is started immediately via the registry.\n */\nexport async function addMcp(input: McpServerInput, deps: McpManageDeps): Promise<McpOpResult> {\n if (!input.name) return { ok: false, message: 'Server name is required' };\n\n const { full, servers } = await readServers(deps.configPath);\n if (servers[input.name]) {\n return { ok: false, message: `Server \"${input.name}\" already exists` };\n }\n\n // Name-only add resolves a preset; an explicit transport/command means the\n // caller supplied the full config and the preset (if any) is just a base.\n const preset = deps.presets?.[input.name];\n const hasExplicitConfig = !!(input.transport || input.command || input.url);\n const cfg = hasExplicitConfig\n ? buildConfig(input, preset)\n : preset\n ? buildConfig({ ...input, name: input.name }, preset)\n : buildConfig(input);\n\n if (!hasExplicitConfig && !preset) {\n const known = Object.keys(deps.presets ?? {}).join(', ');\n return {\n ok: false,\n message: known\n ? `Unknown server \"${input.name}\". Available presets: ${known}`\n : `No configuration provided for \"${input.name}\"`,\n };\n }\n\n cfg.enabled = input.enabled ?? false;\n servers[input.name] = cfg;\n await persist(deps.configPath, full, servers);\n\n if (cfg.enabled) {\n return startServer(input.name, cfg, deps, `Server \"${input.name}\" added`);\n }\n trackDisabled(deps.registry, cfg);\n return {\n ok: true,\n message: `Server \"${input.name}\" added (disabled)`,\n server: projectServer(input.name, cfg, deps.registry),\n };\n}\n\n/** Update an existing server's config, then re-apply it to the live registry. */\nexport async function updateMcp(input: McpServerInput, deps: McpManageDeps): Promise<McpOpResult> {\n if (!input.name) return { ok: false, message: 'Server name is required' };\n\n const { full, servers } = await readServers(deps.configPath);\n const existing = servers[input.name];\n if (!existing) return { ok: false, message: `Server \"${input.name}\" not found` };\n\n const cfg = buildConfig(input, { ...existing, name: input.name });\n servers[input.name] = cfg;\n await persist(deps.configPath, full, servers);\n\n // Re-apply to the registry so edits take effect without a manual restart.\n if (cfg.enabled !== false) {\n return startServer(input.name, cfg, deps, `Server \"${input.name}\" updated`, { restart: true });\n }\n await safeStop(input.name, deps);\n trackDisabled(deps.registry, cfg);\n return {\n ok: true,\n message: `Server \"${input.name}\" updated`,\n server: projectServer(input.name, cfg, deps.registry),\n };\n}\n\n/** Remove a server from config and stop it if running. */\nexport async function removeMcp(name: string, deps: McpManageDeps): Promise<McpOpResult> {\n if (!name) return { ok: false, message: 'Server name is required' };\n const { full, servers } = await readServers(deps.configPath);\n if (!servers[name]) return { ok: false, message: `Server \"${name}\" not found` };\n\n await safeStop(name, deps);\n forgetRegistryState(deps.registry, name);\n delete servers[name];\n await persist(deps.configPath, full, servers);\n return { ok: true, message: `Server \"${name}\" removed` };\n}\n\n/** Enable a server in config and start it. */\nexport async function enableMcp(name: string, deps: McpManageDeps): Promise<McpOpResult> {\n if (!name) return { ok: false, message: 'Server name is required' };\n const { full, servers } = await readServers(deps.configPath);\n const cfg = servers[name];\n if (!cfg) {\n return { ok: false, message: `Server \"${name}\" is not in config. Add it first.` };\n }\n cfg.enabled = true;\n servers[name] = cfg;\n await persist(deps.configPath, full, servers);\n return startServer(name, cfg, deps, `Server \"${name}\" enabled`, { restart: true });\n}\n\n/** Disable a server in config and stop it. */\nexport async function disableMcp(name: string, deps: McpManageDeps): Promise<McpOpResult> {\n if (!name) return { ok: false, message: 'Server name is required' };\n const { full, servers } = await readServers(deps.configPath);\n const cfg = servers[name];\n if (!cfg) return { ok: false, message: `Server \"${name}\" is not in config.` };\n\n await safeStop(name, deps);\n cfg.enabled = false;\n trackDisabled(deps.registry, { ...cfg, name });\n servers[name] = cfg;\n await persist(deps.configPath, full, servers);\n return {\n ok: true,\n message: `Server \"${name}\" disabled`,\n server: projectServer(name, cfg, deps.registry),\n };\n}\n\n/** Restart a running server (or start it from config if registered but stopped). */\nexport async function restartMcp(name: string, deps: McpManageDeps): Promise<McpOpResult> {\n if (!name) return { ok: false, message: 'Server name is required' };\n const registered = deps.registry.list().some((s) => s.name === name);\n if (registered) {\n try {\n await deps.registry.restart(name);\n const { state, tools } = liveState(name, deps.registry);\n return { ok: true, message: `Server \"${name}\" restarted`, state, tools };\n } catch (err) {\n return { ok: false, message: `Failed to restart \"${name}\": ${errMessage(err)}` };\n }\n }\n // Not in the registry yet \u2014 start it from config if it exists and is enabled.\n const { servers } = await readServers(deps.configPath);\n const cfg = servers[name];\n if (!cfg) return { ok: false, message: `Server \"${name}\" is not in config.` };\n return startServer(name, { ...cfg, name }, deps, `Server \"${name}\" started`, { restart: true });\n}\n\n/**\n * Discover a server's tools. Tools are discovered on connect, so this ensures\n * the server is running and returns its live tool list.\n */\nexport async function discoverMcp(name: string, deps: McpManageDeps): Promise<McpOpResult> {\n if (!name) return { ok: false, message: 'Server name is required' };\n const result = await restartMcp(name, deps);\n if (!result.ok) return result;\n const { state, tools } = liveState(name, deps.registry);\n return {\n ok: true,\n message: `Discovered ${tools.length} tool${tools.length === 1 ? '' : 's'} from \"${name}\"`,\n state,\n tools,\n };\n}\n\n// \u2500\u2500 registry helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Start (or restart) a server in the registry. Config has already been\n * persisted by the caller; a registry failure is reported but not fatal \u2014 the\n * config change stands so the user can retry/restart.\n */\nasync function startServer(\n name: string,\n cfg: MCPServerConfig,\n deps: McpManageDeps,\n okMessage: string,\n opts?: { restart?: boolean },\n): Promise<McpOpResult> {\n try {\n const alreadyRegistered = deps.registry.list().some((s) => s.name === name);\n if (alreadyRegistered && opts?.restart) {\n await deps.registry.restart(name);\n } else if (alreadyRegistered) {\n await deps.registry.restart(name);\n } else {\n await deps.registry.start({ ...cfg, enabled: true });\n }\n const { state, tools } = liveState(name, deps.registry);\n return {\n ok: true,\n message: okMessage,\n server: projectServer(name, cfg, deps.registry),\n state,\n tools,\n };\n } catch (err) {\n const message = errMessage(err);\n return {\n ok: true, // config persisted \u2014 surface a soft warning, not a hard failure\n message: `${okMessage} in config, but failed to start: ${message}`,\n server: projectServer(name, cfg, deps.registry),\n registryError: message,\n };\n }\n}\n\n/** Stop a server, swallowing \"not running\" errors. */\nasync function safeStop(name: string, deps: McpManageDeps): Promise<void> {\n try {\n await deps.registry.stop(name);\n } catch {\n // Server may not be running \u2014 ignore.\n }\n}\n\nfunction trackDisabled(registry: MCPRegistry, cfg: MCPServerConfig): void {\n if (typeof registry.markDisabled === 'function') registry.markDisabled(cfg);\n}\n\nfunction forgetRegistryState(registry: MCPRegistry, name: string): void {\n if (typeof registry.forget === 'function') registry.forget(name);\n}\n", "/**\n * On-disk cache of MCP server capability manifests.\n *\n * Lazy-connect needs to register a server's tools WITHOUT spawning it. That is\n * only possible once we have seen the tool list at least once \u2014 so the first\n * successful connect persists the discovered `tools/list` here, and later boots\n * register resolver-backed wrappers straight from this cache.\n *\n * A `configHash` (over the connection-defining fields) is stored alongside the\n * tools so that changing a server's command/args/url/transport invalidates the\n * stale manifest and forces a fresh discovery connect.\n *\n * All operations are best-effort: a read miss or IO error simply means \"no\n * cache\", which falls back to a normal connect.\n */\nimport { createHash, randomBytes } from 'node:crypto';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type { MCPTool } from './client.js';\nimport {\n type MCPPrompt,\n type MCPResource,\n type MCPResourceTemplate,\n type MCPServerMetadata,\n parseListPromptsResult,\n parseListResourcesResult,\n parseListResourceTemplatesResult,\n parseServerMetadata,\n} from './protocol.js';\n\ninterface ManifestFile {\n version?: number | undefined;\n configHash: string;\n tools: MCPTool[];\n serverMetadata?: MCPServerMetadata | undefined;\n resources?: MCPResource[] | undefined;\n resourceTemplates?: MCPResourceTemplate[] | undefined;\n prompts?: MCPPrompt[] | undefined;\n}\n\nexport interface MCPCapabilityManifest {\n tools: MCPTool[];\n serverMetadata?: MCPServerMetadata | undefined;\n resources?: MCPResource[] | undefined;\n resourceTemplates?: MCPResourceTemplate[] | undefined;\n prompts?: MCPPrompt[] | undefined;\n}\n\n/** Stable hash of the fields that define how/where we connect to a server. */\nexport function manifestConfigHash(cfg: {\n transport: string;\n command?: string | undefined;\n args?: string[] | undefined;\n url?: string | undefined;\n}): string {\n const basis = JSON.stringify({\n transport: cfg.transport,\n command: cfg.command ?? null,\n args: cfg.args ?? null,\n url: cfg.url ?? null,\n });\n return createHash('sha256').update(basis).digest('hex').slice(0, 16);\n}\n\n/** Filesystem-safe file name for a server within the manifest cache dir. */\nfunction manifestFile(cacheDir: string, name: string): string {\n const safe = name.replace(/[^a-zA-Z0-9._-]/g, '_');\n return path.join(cacheDir, 'mcp-tools', `${safe}.json`);\n}\n\n/**\n * Read a server's cached tools. Returns null when there is no cache or when the\n * stored `configHash` no longer matches (server config changed \u2192 stale).\n */\nexport async function readManifest(\n cacheDir: string,\n name: string,\n configHash: string,\n): Promise<MCPTool[] | null> {\n const manifest = await readCapabilityManifest(cacheDir, name, configHash);\n return manifest?.tools ?? null;\n}\n\n/**\n * Read a complete capability manifest. Legacy tools-only files are accepted and\n * upgraded in memory, so existing lazy caches remain valid.\n */\nexport async function readCapabilityManifest(\n cacheDir: string,\n name: string,\n configHash: string,\n): Promise<MCPCapabilityManifest | null> {\n try {\n const raw = await fs.readFile(manifestFile(cacheDir, name), 'utf8');\n const parsed = JSON.parse(raw) as ManifestFile;\n if (parsed.configHash !== configHash || !Array.isArray(parsed.tools)) return null;\n return {\n tools: parsed.tools,\n serverMetadata:\n parsed.serverMetadata === undefined\n ? undefined\n : parseServerMetadata(parsed.serverMetadata),\n resources:\n parsed.resources === undefined\n ? undefined\n : parseListResourcesResult({ resources: parsed.resources }).resources,\n resourceTemplates:\n parsed.resourceTemplates === undefined\n ? undefined\n : parseListResourceTemplatesResult({ resourceTemplates: parsed.resourceTemplates })\n .resourceTemplates,\n prompts:\n parsed.prompts === undefined\n ? undefined\n : parseListPromptsResult({ prompts: parsed.prompts }).prompts,\n };\n } catch {\n return null;\n }\n}\n\n/** Persist a server's discovered tools. Best-effort \u2014 IO errors are swallowed. */\nexport async function writeManifest(\n cacheDir: string,\n name: string,\n configHash: string,\n tools: MCPTool[],\n): Promise<void> {\n const previous = await readCapabilityManifest(cacheDir, name, configHash);\n await writeCapabilityManifest(cacheDir, name, configHash, {\n ...previous,\n tools,\n });\n}\n\n/** Persist a complete capability manifest using an atomic replace. */\nexport async function writeCapabilityManifest(\n cacheDir: string,\n name: string,\n configHash: string,\n manifest: MCPCapabilityManifest,\n): Promise<void> {\n try {\n const file = manifestFile(cacheDir, name);\n await fs.mkdir(path.dirname(file), { recursive: true });\n const body: ManifestFile = { version: 2, configHash, ...manifest };\n // Process-unique temp name so two WrongStack processes (e.g. CLI + TUI, or\n // parallel sessions) writing the same server's manifest can't share one\n // `${file}.tmp` and rename each other's half-written file into place.\n const tmp = `${file}.${process.pid}.${randomBytes(6).toString('hex')}.tmp`;\n try {\n await fs.writeFile(tmp, JSON.stringify(body, null, 2), 'utf8');\n await fs.rename(tmp, file);\n } catch (err) {\n // Clean up our own temp file on failure; a unique name is never reused.\n await fs.rm(tmp, { force: true });\n throw err;\n }\n } catch {\n // best-effort cache \u2014 a write failure just means a cold discovery next boot\n }\n}\n", "import type { MCPHealthThresholds } from '@wrongstack/core/types';\nimport type { ConnectionState } from './client.js';\n\n/** Operator-facing health state. Intentionally separate from transport lifecycle state. */\nexport type MCPHealthState =\n | 'disabled'\n | 'dormant'\n | 'connecting'\n | 'healthy'\n | 'degraded'\n | 'failed';\n\nexport type MCPFailureKind = 'transport' | 'protocol' | 'tool';\n\nexport type MCPOperationKind =\n | 'connect'\n | 'reconnect'\n | 'discover'\n | 'call'\n | 'wake'\n | 'sleep'\n | 'restart'\n | 'stop'\n | 'failure';\n\n/**\n * Safe lifecycle event. `reason` is a bounded code owned by WrongStack, never\n * a server error message, command, URL, tool name, argument, or token.\n */\nexport interface MCPOperationEvent {\n serverName: string;\n kind: MCPOperationKind;\n at: number;\n connectionState: ConnectionState;\n healthState: MCPHealthState;\n reason?: string | undefined;\n failureKind?: MCPFailureKind | undefined;\n durationMs?: number | undefined;\n}\n\nexport interface MCPLatencySummary {\n count: number;\n lastMs?: number | undefined;\n minMs?: number | undefined;\n maxMs?: number | undefined;\n p50Ms?: number | undefined;\n p95Ms?: number | undefined;\n}\n\nexport interface MCPServerOperationalHealth {\n name: string;\n connectionState: ConnectionState;\n healthState: MCPHealthState;\n lastSuccessAt?: number | undefined;\n lastFailureAt?: number | undefined;\n lastFailureKind?: MCPFailureKind | undefined;\n lastReason?: string | undefined;\n consecutiveFailures: number;\n failures: Record<MCPFailureKind, number>;\n reconnectCount: number;\n wakeCount: number;\n sleepCount: number;\n restartCount: number;\n connectionLatency: MCPLatencySummary;\n discoveryLatency: MCPLatencySummary;\n callLatency: MCPLatencySummary;\n inFlightCalls: number;\n peakInFlightCalls: number;\n recentEvents: MCPOperationEvent[];\n /** Last evaluation of configured health thresholds; empty if none configured. */\n healthChecks: MCPHealthCheckResult[];\n}\n\n/** Result of comparing one operational metric against its configured threshold. */\nexport interface MCPHealthCheckResult {\n name: string;\n passed: boolean;\n value?: number | undefined;\n threshold?: number | undefined;\n}\n\nexport type MCPOperationListener = (event: Readonly<MCPOperationEvent>) => void;\n\nexport const MCP_OPERATION_LIMITS = Object.freeze({\n LATENCY_SAMPLES: 128,\n RECENT_EVENTS: 32,\n REASON_CHARS: 64,\n});\n\nconst SAFE_OPERATION_REASONS = new Set([\n 'automatic',\n 'complete',\n 'connect-attempt-failed',\n 'connected',\n 'http-disconnect',\n 'http-disconnect-lazy',\n 'idle-timeout',\n 'lazy-demand',\n 'manual',\n 'ok',\n 'process-exit',\n 'process-exit-lazy',\n 'prompt-discovery-failed',\n 'reconnect-exhausted',\n 'resource-discovery-failed',\n 'resource-template-discovery-failed',\n 'started',\n 'tool-call-failed',\n]);\n\nexport interface MCPServerOperationState {\n lastSuccessAt?: number | undefined;\n lastFailureAt?: number | undefined;\n lastFailureKind?: MCPFailureKind | undefined;\n lastReason?: string | undefined;\n consecutiveFailures: number;\n failures: Record<MCPFailureKind, number>;\n reconnectCount: number;\n wakeCount: number;\n sleepCount: number;\n restartCount: number;\n connectionSamples: number[];\n discoverySamples: number[];\n callSamples: number[];\n inFlightCalls: number;\n peakInFlightCalls: number;\n recentEvents: MCPOperationEvent[];\n}\n\nexport function createMCPServerOperationState(): MCPServerOperationState {\n return {\n consecutiveFailures: 0,\n failures: { transport: 0, protocol: 0, tool: 0 },\n reconnectCount: 0,\n wakeCount: 0,\n sleepCount: 0,\n restartCount: 0,\n connectionSamples: [],\n discoverySamples: [],\n callSamples: [],\n inFlightCalls: 0,\n peakInFlightCalls: 0,\n recentEvents: [],\n };\n}\n\nexport function healthStateFor(\n connectionState: ConnectionState,\n operations: MCPServerOperationState,\n enabled = true,\n): MCPHealthState {\n if (!enabled) return 'disabled';\n if (connectionState === 'dormant') return 'dormant';\n if (\n connectionState === 'connecting' ||\n connectionState === 'reconnecting' ||\n connectionState === 'idle'\n ) {\n return 'connecting';\n }\n if (connectionState === 'failed') return 'failed';\n if (connectionState === 'disconnected' || operations.consecutiveFailures > 0) return 'degraded';\n return 'healthy';\n}\n\n/**\n * Compare bounded latency/in-flight samples against configured thresholds.\n * Returns one check per configured threshold. All thresholds are optional;\n * omitted thresholds produce no check and cannot mark a server degraded.\n */\nexport function evaluateHealthThresholds(\n operations: MCPServerOperationState,\n thresholds: MCPHealthThresholds | undefined,\n): MCPHealthCheckResult[] {\n if (!thresholds) return [];\n const checks: MCPHealthCheckResult[] = [];\n if (thresholds.connectionLatencyP95Ms !== undefined && operations.connectionSamples.length > 0) {\n const value = percentile(\n [...operations.connectionSamples].sort((a, b) => a - b),\n 0.95,\n );\n checks.push({\n name: 'connection-latency-p95',\n passed: value <= thresholds.connectionLatencyP95Ms,\n value,\n threshold: thresholds.connectionLatencyP95Ms,\n });\n }\n if (thresholds.discoveryLatencyP95Ms !== undefined && operations.discoverySamples.length > 0) {\n const value = percentile(\n [...operations.discoverySamples].sort((a, b) => a - b),\n 0.95,\n );\n checks.push({\n name: 'discovery-latency-p95',\n passed: value <= thresholds.discoveryLatencyP95Ms,\n value,\n threshold: thresholds.discoveryLatencyP95Ms,\n });\n }\n if (thresholds.callLatencyP95Ms !== undefined && operations.callSamples.length > 0) {\n const value = percentile(\n [...operations.callSamples].sort((a, b) => a - b),\n 0.95,\n );\n checks.push({\n name: 'call-latency-p95',\n passed: value <= thresholds.callLatencyP95Ms,\n value,\n threshold: thresholds.callLatencyP95Ms,\n });\n }\n if (thresholds.inFlightCalls !== undefined) {\n checks.push({\n name: 'in-flight-calls',\n passed: operations.peakInFlightCalls <= thresholds.inFlightCalls,\n value: operations.peakInFlightCalls,\n threshold: thresholds.inFlightCalls,\n });\n }\n return checks;\n}\n\n/**\n * Apply threshold checks to a lifecycle-derived health state. Only `healthy`\n * can be downgraded to `degraded`; existing degraded/failed states are kept\n * so the original lifecycle reason remains authoritative.\n */\nexport function applyHealthThresholds(\n state: MCPHealthState,\n checks: readonly MCPHealthCheckResult[],\n): MCPHealthState {\n if (state !== 'healthy') return state;\n return checks.some((c) => !c.passed) ? 'degraded' : 'healthy';\n}\n\nexport function summarizeLatency(samples: readonly number[]): MCPLatencySummary {\n if (samples.length === 0) return { count: 0 };\n const sorted = [...samples].sort((a, b) => a - b);\n return {\n count: samples.length,\n lastMs: samples[samples.length - 1],\n minMs: sorted[0],\n maxMs: sorted[sorted.length - 1],\n p50Ms: percentile(sorted, 0.5),\n p95Ms: percentile(sorted, 0.95),\n };\n}\n\nexport function pushBounded<T>(target: T[], value: T, limit: number): void {\n target.push(value);\n if (target.length > limit) target.splice(0, target.length - limit);\n}\n\nexport function safeOperationReason(reason: string): string {\n const normalized = reason.toLowerCase().replace(/[^a-z0-9_.:-]+/g, '-');\n const bounded = normalized.slice(0, MCP_OPERATION_LIMITS.REASON_CHARS);\n return SAFE_OPERATION_REASONS.has(bounded) ? bounded : 'other';\n}\n\nfunction percentile(sorted: readonly number[], ratio: number): number {\n return sorted[Math.min(sorted.length - 1, Math.max(0, Math.ceil(sorted.length * ratio) - 1))]!;\n}\n", "import type { EventBus } from '@wrongstack/core/kernel';\nimport type { ToolRegistry } from '@wrongstack/core/registry';\nimport type { Logger, MCPServerConfig, Tool } from '@wrongstack/core/types';\nimport { expectDefined } from '@wrongstack/core/utils';\nimport type { MCPAuthorizationProvider } from './authorization.js';\nimport type {\n MCPAuthorizationManager,\n MCPAuthorizationStartResult,\n MCPAuthorizationStatus,\n} from './authorization-manager.js';\nimport { type ConnectionState, MCPClient, type MCPTool } from './client.js';\nimport { MCP_CONSTANTS } from './constants.js';\nimport {\n type MCPInsertionPolicy,\n type MCPPromptInsertion,\n type MCPResourceInsertion,\n preparePromptInsertion,\n prepareResourceInsertion,\n} from './content-selection.js';\nimport {\n manifestConfigHash,\n readCapabilityManifest,\n writeCapabilityManifest,\n} from './manifest-cache.js';\nimport {\n applyHealthThresholds,\n createMCPServerOperationState,\n evaluateHealthThresholds,\n healthStateFor,\n MCP_OPERATION_LIMITS,\n type MCPFailureKind,\n type MCPOperationEvent,\n type MCPOperationKind,\n type MCPOperationListener,\n type MCPServerOperationalHealth,\n type MCPServerOperationState,\n pushBounded,\n safeOperationReason,\n summarizeLatency,\n} from './operations.js';\nimport type {\n MCPGetPromptResult,\n MCPPrompt,\n MCPReadResourceResult,\n MCPResource,\n MCPResourceTemplate,\n MCPServerMetadata,\n} from './protocol.js';\nimport { wrapMCPTool } from './wrap-tool.js';\n\ninterface ServerSlot {\n cfg: MCPServerConfig;\n client?: MCPClient | undefined;\n state: ConnectionState;\n /** Tools currently registered in toolRegistry (empty in lazy mode). */\n toolNames: string[];\n /** Cached tools when lazyMode is active (not registered in toolRegistry). */\n lazyTools: Tool[];\n serverMetadata?: MCPServerMetadata | undefined;\n resources?: MCPResource[] | undefined;\n resourceTemplates?: MCPResourceTemplate[] | undefined;\n prompts?: MCPPrompt[] | undefined;\n /** Serializes replacements so rapid list-change notifications cannot restore stale data. */\n manifestWrite?: Promise<void> | undefined;\n attempts: number;\n /** Set when a reconnect cycle is already running for this slot. */\n reconnectPending: boolean;\n /**\n * Handle to the pending backoff timer scheduled by `scheduleReconnect`.\n * Stored so `stop` / `stopAll` / `sleepIdle` / exhaustion paths can cancel\n * it \u2014 a stale timer that fires after the slot has been torn down would\n * resurrect the server via `attemptReconnect` (which doesn't gate on\n * `slot.state`).\n */\n reconnectTimer?: NodeJS.Timeout | undefined;\n /**\n * L2-B: number of full reconnect *cycles* (where one cycle = one\n * `attemptConnect` invocation, which itself can try multiple times\n * before giving up). After `MAX_RECONNECT_CYCLES`, the slot stays\n * `failed` until a manual `restart()` resets it.\n */\n reconnectCycles: number;\n /**\n * Slot-scoped, bound disconnect callback. Stored so the matching\n * `removeDisconnectListener` call can hand back the *same* reference \u2014\n * a fresh arrow `() => onTransportDisconnect(slot.cfg.name)` would\n * not match the one we added and the set-based listener registry\n * would silently keep the old handler, causing duplicate reconnect\n * cycles after a few transport flaps.\n */\n onDisconnect?: (() => void) | undefined;\n /**\n * Lazy-connect: the server process is not spawned at boot. Tools are\n * registered from a cached manifest and the process only spawns on the first\n * tool call (via {@link MCPRegistry.ensureConnected}), then auto-sleeps.\n */\n lazy: boolean;\n /** Epoch ms of the last tool call \u2014 drives idle auto-sleep. */\n lastUsed: number;\n /** Single-flight guard so concurrent first-calls trigger only one connect. */\n connecting?: Promise<MCPClient> | undefined;\n /** Whether this lazy server's resolver wrappers are registered (register once). */\n registeredLazy: boolean;\n /** Bounded, payload-free operational telemetry for this server. */\n operations: MCPServerOperationState;\n}\n\nexport interface MCPRegistryOptions {\n toolRegistry: ToolRegistry;\n events: EventBus;\n log: Logger;\n /**\n * Directory for the on-disk tool-manifest cache (lazy-connect). Without it,\n * `lazy` servers cannot register tools cold and fall back to eager connect.\n * Typically `wpaths.cacheDir` (`~/.wrongstack/cache`).\n */\n cacheDir?: string | undefined;\n /**\n * Idle window (ms) after which a connected lazy server is auto-stopped and\n * re-woken on the next tool call. 0 disables idle auto-sleep.\n * Default: {@link MCP_CONSTANTS.IDLE.DEFAULT_TIMEOUT_MS}.\n */\n idleTimeoutMs?: number | undefined;\n /**\n * Lazy mode: when true, MCP server tools are NOT registered into the\n * tool registry on connect. They are cached internally and can be\n * activated on demand via `activateServer(name)`. This is used in\n * token-saving mode to avoid bloating the system prompt with 50-100+\n * MCP tool descriptions. The model uses `mcp_control({ action: \"activate\", server: \"...\" })`\n * to temporarily enable tools when needed.\n * Default: false.\n */\n lazyMode?: boolean | undefined;\n /** Resolve host-owned, vault-backed OAuth state for an HTTP server. */\n authorizationProviderFactory?:\n | ((server: Readonly<MCPServerConfig>) => MCPAuthorizationProvider | undefined)\n | undefined;\n /** Coordinate manual/headless OAuth start, completion, status, and logout. */\n authorizationManager?: MCPAuthorizationManager | undefined;\n}\n\nexport interface MCPRegistryCatalog {\n name: string;\n state: ConnectionState;\n serverMetadata?: MCPServerMetadata | undefined;\n resources?: MCPResource[] | undefined;\n resourceTemplates?: MCPResourceTemplate[] | undefined;\n prompts?: MCPPrompt[] | undefined;\n}\n\nexport class MCPRegistry {\n private readonly servers = new Map<string, ServerSlot>();\n /** Configured-off servers are tracked without creating a transport/client. */\n private readonly disabledServers = new Map<string, MCPServerConfig>();\n private readonly toolRegistry: ToolRegistry;\n private readonly events: EventBus;\n private readonly log: Logger;\n private readonly lazyMode: boolean;\n private readonly cacheDir?: string | undefined;\n private readonly idleTimeoutMs: number;\n private readonly authorizationProviderFactory?: MCPRegistryOptions['authorizationProviderFactory'];\n private readonly authorizationManager?: MCPAuthorizationManager | undefined;\n private readonly operationListeners = new Set<MCPOperationListener>();\n /** Single shared idle sweep timer (started lazily; unref'd; cleared on stopAll). */\n private idleTimer?: ReturnType<typeof setInterval> | undefined;\n\n constructor(opts: MCPRegistryOptions) {\n this.toolRegistry = opts.toolRegistry;\n this.events = opts.events;\n this.log = opts.log;\n this.lazyMode = opts.lazyMode ?? false;\n this.cacheDir = opts.cacheDir;\n this.idleTimeoutMs = opts.idleTimeoutMs ?? MCP_CONSTANTS.IDLE.DEFAULT_TIMEOUT_MS;\n this.authorizationProviderFactory = opts.authorizationProviderFactory;\n this.authorizationManager = opts.authorizationManager;\n }\n\n private requireSlot(name: string): ServerSlot {\n const slot = this.servers.get(name);\n if (!slot) throw new Error(`MCP server \"${name}\" not registered`);\n return slot;\n }\n\n async beginAuthorization(\n name: string,\n input: {\n clientId: string;\n redirectUri: string;\n scopes?: readonly string[] | undefined;\n challengeHeader?: string | null | undefined;\n signal?: AbortSignal | undefined;\n },\n ): Promise<MCPAuthorizationStartResult> {\n const manager = this.requireAuthorizationManager();\n const cfg = this.requireHttpServerConfig(name);\n return manager.begin({\n serverName: name,\n resource: cfg.url!,\n ...input,\n });\n }\n\n async completeAuthorization(\n name: string,\n callbackUrl: string,\n signal?: AbortSignal | undefined,\n ): Promise<MCPAuthorizationStatus> {\n const manager = this.requireAuthorizationManager();\n const cfg = this.requireHttpServerConfig(name);\n return manager.complete({ serverName: name, resource: cfg.url!, callbackUrl, signal });\n }\n\n async authorizationStatus(name: string): Promise<MCPAuthorizationStatus> {\n const manager = this.requireAuthorizationManager();\n const cfg = this.requireHttpServerConfig(name);\n return manager.status(name, cfg.url!);\n }\n\n async disconnectAuthorization(name: string): Promise<boolean> {\n const manager = this.requireAuthorizationManager();\n const cfg = this.requireHttpServerConfig(name);\n return manager.disconnect(name, cfg.url!);\n }\n\n private requireAuthorizationManager(): MCPAuthorizationManager {\n if (!this.authorizationManager) {\n throw new Error('MCP authorization management is not configured for this host');\n }\n return this.authorizationManager;\n }\n\n private requireHttpServerConfig(name: string): MCPServerConfig {\n const cfg = this.servers.get(name)?.cfg ?? this.disabledServers.get(name);\n if (!cfg) throw new Error(`MCP server \"${name}\" not registered`);\n if (cfg.transport === 'stdio' || !cfg.url) {\n throw new Error(`MCP server \"${name}\" does not use an HTTP transport`);\n }\n return cfg;\n }\n\n async start(cfg: MCPServerConfig): Promise<void> {\n if (cfg.enabled === false) {\n if (this.servers.has(cfg.name)) {\n await this.stop(cfg.name);\n }\n this.markDisabled(cfg);\n return;\n }\n this.disabledServers.delete(cfg.name);\n // Reject duplicate registrations explicitly. Without this, calling\n // start() twice with the same name would overwrite the slot in\n // `this.servers` and orphan the previous slot's client (still\n // connected, with listeners wired into a slot that's no longer\n // reachable from the registry). Callers that want a clean re-start\n // should use `restart(name)`.\n if (this.servers.has(cfg.name)) {\n throw new Error(\n `MCP server \"${cfg.name}\" is already registered \u2014 use restart() to re-cycle a running server`,\n );\n }\n // Lazy-connect requires a manifest cache dir to register tools cold.\n const lazy = !!cfg.lazy && !!this.cacheDir;\n const slot: ServerSlot = {\n cfg,\n state: 'idle',\n toolNames: [],\n lazyTools: [],\n attempts: 0,\n reconnectPending: false,\n reconnectCycles: 0,\n lazy,\n lastUsed: Date.now(),\n registeredLazy: false,\n operations: createMCPServerOperationState(),\n };\n this.servers.set(cfg.name, slot);\n if (lazy) {\n await this.startLazy(slot);\n } else {\n await this.attemptConnect(slot);\n }\n }\n\n /** Record an intentionally disabled configuration without opening a transport. */\n markDisabled(cfg: MCPServerConfig): void {\n this.servers.delete(cfg.name);\n this.disabledServers.set(cfg.name, { ...cfg, enabled: false });\n }\n\n /** Remove residual operational/configuration state after a management delete. */\n forget(name: string): void {\n this.servers.delete(name);\n this.disabledServers.delete(name);\n }\n\n /**\n * Boot a lazy server WITHOUT spawning it. If a tool manifest is cached (from a\n * prior connect with matching config), register resolver-backed wrappers and\n * go `dormant` \u2014 the process spawns on the first tool call. If there is no\n * cache yet, do a one-time cold discovery connect to learn + cache the tools.\n */\n private async startLazy(slot: ServerSlot): Promise<void> {\n // start() only marks a slot lazy when a cache directory is configured.\n const cacheDir = expectDefined(this.cacheDir);\n const hash = manifestConfigHash(slot.cfg);\n const cached = await readCapabilityManifest(cacheDir, slot.cfg.name, hash);\n if (cached) {\n slot.serverMetadata = cached.serverMetadata;\n slot.resources = cached.resources;\n slot.resourceTemplates = cached.resourceTemplates;\n slot.prompts = cached.prompts;\n this.applyTools(slot, cached.tools);\n slot.state = 'dormant';\n this.ensureIdleSweep();\n this.log.info(\n `MCP server \"${slot.cfg.name}\" registered lazily from cache (${cached.tools.length} tools, dormant)`,\n );\n return;\n }\n // No cache \u2014 must connect once to discover the tool list, then it stays\n // connected and becomes eligible for idle auto-sleep.\n await this.attemptConnect(slot);\n }\n\n /**\n * Ensure a lazy server is connected, spawning it on demand. Single-flight:\n * concurrent first-calls share one connect. Resolver wrappers call this.\n */\n async ensureConnected(name: string): Promise<MCPClient> {\n const slot = this.servers.get(name);\n if (!slot) throw new Error(`MCP server \"${name}\" not registered`);\n slot.lastUsed = Date.now();\n if (slot.client && slot.state === 'connected') return slot.client;\n if (slot.connecting) return slot.connecting;\n const waking = slot.state === 'dormant';\n if (waking) {\n slot.operations.wakeCount++;\n this.recordOperation(slot, 'wake', 'lazy-demand');\n }\n slot.connecting = (async () => {\n try {\n // start fresh budget \u2014 a deliberate wake is not a crash-reconnect.\n slot.attempts = 0;\n slot.reconnectCycles = 0;\n await this.attemptConnect(slot);\n if (!slot.client) {\n throw new Error(`MCP server \"${name}\" failed to connect on demand`);\n }\n slot.lastUsed = Date.now();\n this.ensureIdleSweep();\n return slot.client;\n } finally {\n slot.connecting = undefined;\n }\n })();\n return slot.connecting;\n }\n\n /**\n * Register all cached tools for a given server into the tool registry.\n * No-op if tools are already registered or the server is not connected.\n * The server connection stays alive \u2014 this only toggles tool visibility.\n */\n activateServer(name: string): void {\n const slot = this.servers.get(name);\n if (!slot) return;\n // A dormant lazy server has no client yet \u2014 its resolver wrappers connect on\n // demand, so it can still be activated (registered) without a live process.\n if (!slot.client && !slot.lazy) return;\n if (slot.toolNames.length > 0) return; // already active\n const cached = slot.lazyTools;\n if (cached.length === 0) return;\n for (const tool of cached) {\n try {\n this.toolRegistry.register(tool, `mcp:${name}`);\n slot.toolNames.push(tool.name);\n } catch (err) {\n this.log.warn(`MCP tool \"${tool.name}\" activate failed`, err);\n }\n }\n this.log.info(`MCP server \"${name}\" activated (${slot.toolNames.length} tools)`);\n this.events.emit('mcp.server.connected', { name, toolCount: slot.toolNames.length });\n }\n\n /**\n * Unregister all tools for a given server from the tool registry.\n * The server connection stays alive \u2014 this only toggles tool visibility.\n * Returns the number of tools that were deactivated.\n */\n deactivateServer(name: string): number {\n const slot = this.servers.get(name);\n if (!slot) return 0;\n const count = slot.toolNames.length;\n if (count === 0) return 0;\n for (const t of slot.toolNames) {\n try {\n this.toolRegistry.unregister(t);\n } catch {\n /* ignore */\n }\n }\n slot.toolNames = [];\n this.log.info(`MCP server \"${name}\" deactivated (${count} tools removed)`);\n this.events.emit('mcp.server.disconnected', { name, reason: 'deactivate' });\n return count;\n }\n\n /**\n * Check whether a server's tools are currently registered.\n */\n isActivated(name: string): boolean {\n const slot = this.servers.get(name);\n return slot ? slot.toolNames.length > 0 : false;\n }\n\n async stop(name: string): Promise<void> {\n const slot = this.servers.get(name);\n if (!slot) return;\n slot.reconnectPending = false;\n // Cancel the pending backoff timer. Without this, a disconnect scheduled\n // for reconnection would fire its `attemptReconnect` callback after the\n // slot has been torn down and respawn the server we just told to stop.\n if (slot.reconnectTimer) {\n clearTimeout(slot.reconnectTimer);\n slot.reconnectTimer = undefined;\n }\n if (slot.client) {\n slot.client.removeExitListener(this.onChildExit);\n if (slot.onDisconnect) slot.client.removeDisconnectListener(slot.onDisconnect);\n slot.client.removeToolsChangedListener(this.onToolsChanged);\n this.removeCatalogListeners(slot.client);\n await slot.client.close();\n slot.client = undefined;\n }\n slot.onDisconnect = undefined;\n slot.connecting = undefined;\n for (const t of slot.toolNames) this.toolRegistry.unregister(t);\n slot.toolNames = [];\n slot.lazyTools = [];\n slot.serverMetadata = undefined;\n slot.resources = undefined;\n slot.resourceTemplates = undefined;\n slot.prompts = undefined;\n // Full teardown \u2014 a future start()/restart() re-registers lazy wrappers.\n slot.registeredLazy = false;\n slot.state = 'disconnected';\n this.recordOperation(slot, 'stop', 'manual');\n this.events.emit('mcp.server.disconnected', { name, reason: 'stop' });\n }\n\n async restart(name: string): Promise<void> {\n const slot = this.servers.get(name);\n if (!slot) throw new Error(`MCP server \"${name}\" not registered`);\n slot.operations.restartCount++;\n this.recordOperation(slot, 'restart', 'manual');\n await this.stop(name);\n slot.attempts = 0;\n slot.reconnectCycles = 0; // user intent: start fresh\n await this.attemptConnect(slot);\n }\n\n list(): { name: string; state: ConnectionState; toolCount: number; tools: string[] }[] {\n return Array.from(this.servers.values()).map((s) => {\n const tools = this.toolNamesForSlot(s);\n return {\n name: s.cfg.name,\n state: s.state,\n toolCount: tools.length,\n tools,\n };\n });\n }\n\n /**\n * Subscribe to payload-free operational signals. Callers must still avoid\n * using `serverName` as an unbounded metric label.\n */\n onOperation(listener: MCPOperationListener): () => void {\n this.operationListeners.add(listener);\n return () => this.operationListeners.delete(listener);\n }\n\n /** Detailed, defensively-copied operational snapshots for CLI/WebUI/HQ. */\n operationalHealth(): MCPServerOperationalHealth[] {\n const active = Array.from(this.servers.values()).map((slot) => {\n const op = slot.operations;\n const baseHealth = healthStateFor(slot.state, op, slot.cfg.enabled !== false);\n const checks = evaluateHealthThresholds(op, slot.cfg.health?.thresholds);\n return {\n name: slot.cfg.name,\n connectionState: slot.state,\n healthState: applyHealthThresholds(baseHealth, checks),\n lastSuccessAt: op.lastSuccessAt,\n lastFailureAt: op.lastFailureAt,\n lastFailureKind: op.lastFailureKind,\n lastReason: op.lastReason,\n consecutiveFailures: op.consecutiveFailures,\n failures: { ...op.failures },\n reconnectCount: op.reconnectCount,\n wakeCount: op.wakeCount,\n sleepCount: op.sleepCount,\n restartCount: op.restartCount,\n connectionLatency: summarizeLatency(op.connectionSamples),\n discoveryLatency: summarizeLatency(op.discoverySamples),\n callLatency: summarizeLatency(op.callSamples),\n inFlightCalls: op.inFlightCalls,\n peakInFlightCalls: op.peakInFlightCalls,\n recentEvents: op.recentEvents.map((event) => ({ ...event })),\n healthChecks: checks,\n };\n });\n const disabled = Array.from(this.disabledServers.values()).map((cfg) => {\n const operations = createMCPServerOperationState();\n return {\n name: cfg.name,\n connectionState: 'idle' as const,\n healthState: 'disabled' as const,\n consecutiveFailures: 0,\n failures: { ...operations.failures },\n reconnectCount: 0,\n wakeCount: 0,\n sleepCount: 0,\n restartCount: 0,\n connectionLatency: summarizeLatency([]),\n discoveryLatency: summarizeLatency([]),\n callLatency: summarizeLatency([]),\n inFlightCalls: 0,\n peakInFlightCalls: 0,\n recentEvents: [],\n healthChecks: [],\n };\n });\n return [...active, ...disabled];\n }\n\n getCatalog(name: string): MCPRegistryCatalog | undefined {\n const slot = this.servers.get(name);\n if (!slot) return undefined;\n return catalogSnapshot(slot);\n }\n\n async listResources(name: string, opts: { refresh?: boolean } = {}): Promise<MCPResource[]> {\n const slot = this.requireSlot(name);\n if (!opts.refresh && slot.resources) return cloneRecords(slot.resources);\n const client = await this.ensureConnected(name);\n if (!client.getServerMetadata()?.capabilities.resources) return [];\n slot.resources = await collectPages(\n (cursor) => client.listResources(cursor ? { cursor } : {}),\n (page) => page.resources,\n );\n await this.persistCapabilityManifest(slot);\n return cloneRecords(slot.resources);\n }\n\n async listResourceTemplates(\n name: string,\n opts: { refresh?: boolean } = {},\n ): Promise<MCPResourceTemplate[]> {\n const slot = this.requireSlot(name);\n if (!opts.refresh && slot.resourceTemplates) return cloneRecords(slot.resourceTemplates);\n const client = await this.ensureConnected(name);\n if (!client.getServerMetadata()?.capabilities.resources) return [];\n slot.resourceTemplates = await collectPages(\n (cursor) => client.listResourceTemplates(cursor ? { cursor } : {}),\n (page) => page.resourceTemplates,\n );\n await this.persistCapabilityManifest(slot);\n return cloneRecords(slot.resourceTemplates);\n }\n\n async readResource(name: string, uri: string): Promise<MCPReadResourceResult> {\n return (await this.ensureConnected(name)).readResource(uri);\n }\n\n async selectResourceForInsertion(\n name: string,\n uri: string,\n policy?: MCPInsertionPolicy | undefined,\n ): Promise<MCPResourceInsertion> {\n return prepareResourceInsertion(name, uri, await this.readResource(name, uri), policy);\n }\n\n async subscribeResource(name: string, uri: string): Promise<void> {\n await (await this.ensureConnected(name)).subscribeResource(uri);\n }\n\n async unsubscribeResource(name: string, uri: string): Promise<void> {\n await (await this.ensureConnected(name)).unsubscribeResource(uri);\n }\n\n async listPrompts(name: string, opts: { refresh?: boolean } = {}): Promise<MCPPrompt[]> {\n const slot = this.requireSlot(name);\n if (!opts.refresh && slot.prompts) return cloneRecords(slot.prompts);\n const client = await this.ensureConnected(name);\n if (!client.getServerMetadata()?.capabilities.prompts) return [];\n slot.prompts = await collectPages(\n (cursor) => client.listPrompts(cursor ? { cursor } : {}),\n (page) => page.prompts,\n );\n await this.persistCapabilityManifest(slot);\n return cloneRecords(slot.prompts);\n }\n\n async getPrompt(\n serverName: string,\n promptName: string,\n args?: Record<string, string> | undefined,\n ): Promise<MCPGetPromptResult> {\n return (await this.ensureConnected(serverName)).getPrompt(promptName, args);\n }\n\n async selectPromptForInsertion(\n serverName: string,\n promptName: string,\n args?: Record<string, string> | undefined,\n policy?: MCPInsertionPolicy | undefined,\n ): Promise<MCPPromptInsertion> {\n return preparePromptInsertion(\n serverName,\n promptName,\n args,\n await this.getPrompt(serverName, promptName, args),\n policy,\n );\n }\n\n /**\n * Resolve the live tool names for a slot \u2014 the registered names in normal\n * mode, or the cached lazy-tool names when running in lazy mode (where\n * tools are connected but intentionally not registered).\n */\n private toolNamesForSlot(s: ServerSlot): string[] {\n return s.toolNames.length > 0 ? s.toolNames.slice() : (s.lazyTools ?? []).map((t) => t.name);\n }\n\n /**\n * Wrap + register (or cache) a server's tools. Lazy servers get resolver-backed\n * wrappers that spawn the process on first use; eager servers bind the live\n * client directly. Honours token-saving `lazyMode` (cache, don't register) and\n * a register-once guard for lazy resolver wrappers (so a wake/reconnect reuses\n * the existing registrations rather than churning the tool list).\n */\n private applyTools(slot: ServerSlot, tools: MCPTool[], client?: MCPClient | undefined): void {\n // Resolver wrappers survive sleep/wake \u2014 only register them once.\n if (slot.lazy && slot.registeredLazy && !this.lazyMode) return;\n const allowed = slot.cfg.allowedTools;\n const filtered = tools.filter((t) => !allowed || allowed.includes(t.name));\n const clientArg = slot.lazy ? () => this.ensureConnected(slot.cfg.name) : expectDefined(client);\n const wrapped = filtered.map((t) =>\n wrapMCPTool(slot.cfg.name, t, clientArg, slot.cfg.permission ?? 'confirm', {\n onStart: () => {\n slot.operations.inFlightCalls++;\n slot.operations.peakInFlightCalls = Math.max(\n slot.operations.peakInFlightCalls,\n slot.operations.inFlightCalls,\n );\n this.recordOperation(slot, 'call', 'started', undefined, undefined, false);\n },\n onFinish: ({ durationMs, ok }) => {\n slot.operations.inFlightCalls = Math.max(0, slot.operations.inFlightCalls - 1);\n pushBounded(\n slot.operations.callSamples,\n durationMs,\n MCP_OPERATION_LIMITS.LATENCY_SAMPLES,\n );\n if (ok) {\n this.recordSuccess(slot);\n this.recordOperation(slot, 'call', 'ok', undefined, durationMs, false);\n } else {\n this.recordFailure(slot, 'tool', 'tool-call-failed', durationMs);\n }\n },\n }),\n );\n if (this.lazyMode) {\n // Token-saving mode: cache without registering (mcp_use activates on demand).\n slot.lazyTools = wrapped;\n return;\n }\n for (const tool of wrapped) {\n try {\n this.toolRegistry.register(tool, `mcp:${slot.cfg.name}`);\n slot.toolNames.push(tool.name);\n } catch (err) {\n this.log.warn(`MCP tool \"${tool.name}\" not registered`, err);\n }\n }\n if (slot.lazy && wrapped.length > 0) slot.registeredLazy = true;\n }\n\n private async discoverCapabilities(slot: ServerSlot, client: MCPClient): Promise<void> {\n const startedAt = Date.now();\n slot.serverMetadata = client.getServerMetadata();\n const capabilities = slot.serverMetadata?.capabilities;\n if (capabilities?.resources) {\n try {\n slot.resources = await collectPages(\n (cursor) => client.listResources(cursor ? { cursor } : {}),\n (page) => page.resources,\n );\n } catch (err) {\n slot.resources = undefined;\n this.recordFailure(slot, 'protocol', 'resource-discovery-failed');\n this.log.warn(`MCP server \"${slot.cfg.name}\" resource discovery failed`, err);\n }\n try {\n slot.resourceTemplates = await collectPages(\n (cursor) => client.listResourceTemplates(cursor ? { cursor } : {}),\n (page) => page.resourceTemplates,\n );\n } catch (err) {\n slot.resourceTemplates = undefined;\n this.recordFailure(slot, 'protocol', 'resource-template-discovery-failed');\n this.log.warn(`MCP server \"${slot.cfg.name}\" resource template discovery failed`, err);\n }\n } else {\n slot.resources = undefined;\n slot.resourceTemplates = undefined;\n }\n if (capabilities?.prompts) {\n try {\n slot.prompts = await collectPages(\n (cursor) => client.listPrompts(cursor ? { cursor } : {}),\n (page) => page.prompts,\n );\n } catch (err) {\n slot.prompts = undefined;\n this.recordFailure(slot, 'protocol', 'prompt-discovery-failed');\n this.log.warn(`MCP server \"${slot.cfg.name}\" prompt discovery failed`, err);\n }\n } else {\n slot.prompts = undefined;\n }\n const durationMs = Date.now() - startedAt;\n pushBounded(slot.operations.discoverySamples, durationMs, MCP_OPERATION_LIMITS.LATENCY_SAMPLES);\n this.recordOperation(slot, 'discover', 'complete', undefined, durationMs, false);\n }\n\n private async persistCapabilityManifest(slot: ServerSlot): Promise<void> {\n if (!slot.lazy || !this.cacheDir) return;\n const cacheDir = this.cacheDir;\n const previous = slot.manifestWrite ?? Promise.resolve();\n const pending = previous.then(() =>\n writeCapabilityManifest(cacheDir, slot.cfg.name, manifestConfigHash(slot.cfg), {\n tools: slot.client?.listTools() ?? [],\n serverMetadata: slot.serverMetadata,\n resources: slot.resources,\n resourceTemplates: slot.resourceTemplates,\n prompts: slot.prompts,\n }),\n );\n slot.manifestWrite = pending;\n await pending;\n if (slot.manifestWrite === pending) slot.manifestWrite = undefined;\n }\n\n /** Start the shared idle sweep timer once (unref'd so it never holds the process). */\n private ensureIdleSweep(): void {\n if (this.idleTimer || this.idleTimeoutMs <= 0) return;\n this.idleTimer = setInterval(() => {\n void this.sweepIdle();\n }, MCP_CONSTANTS.IDLE.SWEEP_INTERVAL_MS);\n // Node-only: don't keep the event loop alive just for the sweep.\n this.idleTimer.unref?.();\n }\n\n /** Auto-sleep connected lazy servers that have been idle past the timeout. */\n private async sweepIdle(): Promise<void> {\n if (this.idleTimeoutMs <= 0) return;\n const now = Date.now();\n for (const slot of this.servers.values()) {\n if (\n slot.lazy &&\n slot.state === 'connected' &&\n slot.client &&\n now - slot.lastUsed > this.idleTimeoutMs\n ) {\n await this.sleepIdle(slot);\n }\n }\n }\n\n /**\n * Soft stop: close the server process but KEEP its resolver wrappers and\n * cached manifest registered, so the next tool call transparently re-wakes it.\n * Distinct from {@link stop} (full teardown for disable/remove).\n */\n private async sleepIdle(slot: ServerSlot): Promise<void> {\n slot.reconnectPending = false;\n // Defense-in-depth: a connect-failure retry timer from an earlier\n // failed cycle shouldn't outlive a fresh sleep.\n if (slot.reconnectTimer) {\n clearTimeout(slot.reconnectTimer);\n slot.reconnectTimer = undefined;\n }\n if (slot.client) {\n // Remove the exit listener BEFORE close so the teardown isn't seen as a crash.\n slot.client.removeExitListener(this.onChildExit);\n if (slot.onDisconnect) slot.client.removeDisconnectListener(slot.onDisconnect);\n slot.client.removeToolsChangedListener(this.onToolsChanged);\n this.removeCatalogListeners(slot.client);\n await slot.client.close();\n slot.client = undefined;\n }\n slot.onDisconnect = undefined;\n slot.state = 'dormant';\n slot.operations.sleepCount++;\n this.recordOperation(slot, 'sleep', 'idle-timeout');\n this.log.info(`MCP server \"${slot.cfg.name}\" idle \u2014 sleeping (tools stay registered)`);\n this.events.emit('mcp.server.disconnected', { name: slot.cfg.name, reason: 'idle-sleep' });\n }\n\n /**\n * Catalog of every server ever registered with this registry \u2014 includes\n * servers that are stopped, failed, or not yet started.\n * Useful for the `mcp_control` tool to show all known servers without\n * triggering connections.\n */\n describe(): {\n name: string;\n state: ConnectionState;\n toolCount: number;\n enabled: boolean;\n tools: string[];\n }[] {\n const active = Array.from(this.servers.values()).map((s) => {\n const tools = this.toolNamesForSlot(s);\n return {\n name: s.cfg.name,\n state: s.state,\n toolCount: tools.length,\n enabled: s.cfg.enabled !== false,\n tools,\n };\n });\n const disabled = Array.from(this.disabledServers.values()).map((cfg) => ({\n name: cfg.name,\n state: 'idle' as const,\n toolCount: 0,\n enabled: false,\n tools: [],\n }));\n return [...active, ...disabled];\n }\n\n async stopAll(): Promise<void> {\n if (this.idleTimer) {\n clearInterval(this.idleTimer);\n this.idleTimer = undefined;\n }\n for (const name of Array.from(this.servers.keys())) {\n await this.stop(name);\n }\n this.disabledServers.clear();\n }\n\n /**\n * Health check \u2014 returns 'ok' for connected servers, the current state otherwise.\n * For HTTP-based transports this could also ping the server.\n */\n health(): { name: string; alive: boolean; latencyMs?: number | undefined }[] {\n return Array.from(this.servers.values()).map((s) => ({\n name: s.cfg.name,\n alive: s.state === 'connected',\n }));\n }\n\n /**\n * L2-C: handle `notifications/tools/list_changed` from the server.\n * Unregister the previous wrapper set, then re-register the fresh\n * tool list. The client has already refreshed its cache before\n * dispatching \u2014 we just need to re-wrap and re-register.\n * In lazy mode, only update the internal cache without registering.\n */\n private readonly onToolsChanged = (name: string, _tools: { name: string }[]): void => {\n const slot = this.servers.get(name);\n if (!slot?.client) return;\n // Unregister any previously registered tools, then re-apply the fresh set.\n for (const t of slot.toolNames) {\n try {\n this.toolRegistry.unregister(t);\n } catch {\n /* ignore */\n }\n }\n slot.toolNames = [];\n slot.registeredLazy = false;\n const discovered = slot.client.listTools();\n // Refresh the lazy manifest so a future cold boot sees the new tool set.\n this.applyTools(slot, discovered, slot.client);\n void this.persistCapabilityManifest(slot);\n this.events.emit('mcp.server.connected', {\n name: slot.cfg.name,\n toolCount: slot.toolNames.length,\n });\n this.log.info(\n `MCP server \"${slot.cfg.name}\" tools refreshed (${this.toolNamesForSlot(slot).length} active)`,\n );\n };\n\n private readonly onResourcesChanged = (name: string): void => {\n const slot = this.servers.get(name);\n if (!slot) return;\n slot.resources = undefined;\n slot.resourceTemplates = undefined;\n void this.persistCapabilityManifest(slot);\n this.log.info(`MCP server \"${name}\" resource catalog invalidated`);\n };\n\n private readonly onPromptsChanged = (name: string): void => {\n const slot = this.servers.get(name);\n if (!slot) return;\n slot.prompts = undefined;\n void this.persistCapabilityManifest(slot);\n this.log.info(`MCP server \"${name}\" prompt catalog invalidated`);\n };\n\n private addCatalogListeners(client: MCPClient): void {\n client.addResourcesChangedListener(this.onResourcesChanged);\n client.addPromptsChangedListener(this.onPromptsChanged);\n }\n\n private removeCatalogListeners(client: MCPClient): void {\n client.removeResourcesChangedListener(this.onResourcesChanged);\n client.removePromptsChangedListener(this.onPromptsChanged);\n }\n\n private readonly onChildExit = (\n name: string,\n code: number | null,\n _signal: string | null,\n ): void => {\n const slot = this.servers.get(name);\n if (!slot) return;\n if (slot.lazy) {\n // Lazy server died \u2014 go dormant (keep resolver wrappers); the next tool\n // call re-spawns it. No reconnect storm for an on-demand server.\n slot.client = undefined;\n slot.state = 'dormant';\n this.recordFailure(slot, 'transport', 'process-exit-lazy');\n this.events.emit('mcp.server.disconnected', {\n name,\n reason: `exit:${code ?? 'unknown'} (dormant)`,\n });\n return;\n }\n for (const t of slot.toolNames) {\n try {\n this.toolRegistry.unregister(t);\n } catch {\n /* ignore */\n }\n }\n slot.toolNames = [];\n slot.lazyTools = [];\n slot.serverMetadata = undefined;\n slot.resources = undefined;\n slot.resourceTemplates = undefined;\n slot.prompts = undefined;\n slot.state = 'disconnected';\n this.recordFailure(slot, 'transport', 'process-exit');\n this.events.emit('mcp.server.disconnected', { name, reason: `exit:${code ?? 'unknown'}` });\n this.scheduleReconnect(slot);\n };\n\n /** Handles SSE / streamable-http disconnect \u2014 same recovery as stdio child exit. */\n private readonly onTransportDisconnect = (name: string): void => {\n const slot = this.servers.get(name);\n if (!slot) return;\n if (slot.lazy) {\n slot.client = undefined;\n slot.state = 'dormant';\n this.recordFailure(slot, 'transport', 'http-disconnect-lazy');\n this.events.emit('mcp.server.disconnected', { name, reason: 'http-disconnect (dormant)' });\n return;\n }\n for (const t of slot.toolNames) {\n try {\n this.toolRegistry.unregister(t);\n } catch {\n /* ignore */\n }\n }\n slot.toolNames = [];\n slot.lazyTools = [];\n slot.serverMetadata = undefined;\n slot.resources = undefined;\n slot.resourceTemplates = undefined;\n slot.prompts = undefined;\n slot.state = 'disconnected';\n this.recordFailure(slot, 'transport', 'http-disconnect');\n this.events.emit('mcp.server.disconnected', { name, reason: 'http-disconnect' });\n this.scheduleReconnect(slot);\n };\n\n /**\n * L2-B: maximum number of reconnect cycles before staying `failed`.\n * One cycle = one full `attemptConnect` (which itself may try up to 3\n * times). Caps total reconnect storm at ~5 cycles, then the slot\n * needs an explicit `restart()` to re-engage.\n */\n private static readonly MAX_RECONNECT_CYCLES = MCP_CONSTANTS.RECONNECT.MAX_CYCLES;\n /** Base delay between cycles, in ms. Real delay adds jitter. */\n private static readonly BASE_RECONNECT_DELAY_MS = MCP_CONSTANTS.RECONNECT.BASE_DELAY_MS;\n /** Hard ceiling on the inter-cycle delay so the user doesn't wait minutes. */\n private static readonly MAX_RECONNECT_DELAY_MS = 30_000;\n\n private scheduleReconnect(slot: ServerSlot): void {\n if (slot.reconnectPending) return;\n if (slot.reconnectCycles >= MCPRegistry.MAX_RECONNECT_CYCLES) {\n slot.state = 'failed';\n this.recordFailure(slot, 'transport', 'reconnect-exhausted');\n this.log.error(\n `MCP server \"${slot.cfg.name}\" giving up after ${slot.reconnectCycles} reconnect cycles. Use \\`/mcp restart ${slot.cfg.name}\\` to retry.`,\n );\n this.events.emit('mcp.server.disconnected', {\n name: slot.cfg.name,\n reason: `reconnect-exhausted:${slot.reconnectCycles}`,\n });\n return;\n }\n slot.reconnectPending = true;\n // Cancel any previously-scheduled timer for this slot. Defensive \u2014 the\n // `reconnectPending` early-return above normally prevents re-scheduling\n // while one is outstanding, but if the slot was torn down mid-flight\n // and re-started (`restart()`), a stale handle from the prior cycle\n // could otherwise fire and resurrect the wrong client.\n if (slot.reconnectTimer) {\n clearTimeout(slot.reconnectTimer);\n slot.reconnectTimer = undefined;\n }\n // Exponential backoff with light jitter: 1s, 2s, 4s, 8s, 16s, capped\n // at 30s. The \u00B120% jitter avoids reconnect stampedes when many\n // servers crash together.\n const base = Math.min(\n MCPRegistry.BASE_RECONNECT_DELAY_MS * 2 ** slot.reconnectCycles,\n MCPRegistry.MAX_RECONNECT_DELAY_MS,\n );\n const jitter = base * MCP_CONSTANTS.RECONNECT.JITTER_FACTOR * (Math.random() * 2 - 1);\n const delay = Math.max(100, Math.round(base + jitter));\n slot.reconnectTimer = setTimeout(() => {\n slot.reconnectTimer = undefined;\n void this.attemptReconnect(slot);\n }, delay);\n }\n\n private async attemptReconnect(slot: ServerSlot): Promise<void> {\n slot.reconnectPending = false;\n slot.reconnectCycles++;\n slot.operations.reconnectCount++;\n this.recordOperation(slot, 'reconnect', 'automatic');\n await this.attemptConnect(slot);\n }\n\n private recordSuccess(slot: ServerSlot, resetFailures = true): void {\n const operations = this.operationsFor(slot);\n operations.lastSuccessAt = Date.now();\n if (resetFailures) operations.consecutiveFailures = 0;\n }\n\n private recordFailure(\n slot: ServerSlot,\n failureKind: MCPFailureKind,\n reason: string,\n durationMs?: number | undefined,\n ): void {\n const operations = this.operationsFor(slot);\n const safeReason = safeOperationReason(reason);\n operations.lastFailureAt = Date.now();\n operations.lastFailureKind = failureKind;\n operations.lastReason = safeReason;\n operations.consecutiveFailures++;\n operations.failures[failureKind]++;\n this.recordOperation(slot, 'failure', safeReason, failureKind, durationMs);\n }\n\n private recordOperation(\n slot: ServerSlot,\n kind: MCPOperationKind,\n reason?: string | undefined,\n failureKind?: MCPFailureKind | undefined,\n durationMs?: number | undefined,\n retain = true,\n ): void {\n const operations = this.operationsFor(slot);\n const baseHealth = healthStateFor(slot.state, operations, slot.cfg.enabled !== false);\n const checks = evaluateHealthThresholds(operations, slot.cfg.health?.thresholds);\n const event: MCPOperationEvent = {\n serverName: slot.cfg.name,\n kind,\n at: Date.now(),\n connectionState: slot.state,\n healthState: applyHealthThresholds(baseHealth, checks),\n };\n if (reason !== undefined) event.reason = safeOperationReason(reason);\n if (failureKind !== undefined) event.failureKind = failureKind;\n if (durationMs !== undefined) event.durationMs = Math.max(0, Math.round(durationMs));\n if (retain) {\n pushBounded(operations.recentEvents, event, MCP_OPERATION_LIMITS.RECENT_EVENTS);\n }\n for (const listener of this.operationListeners) {\n try {\n listener({ ...event });\n } catch {\n // Observability must never affect MCP execution.\n }\n }\n }\n\n /** Keeps private-method unit fixtures from needing to duplicate every slot field. */\n private operationsFor(slot: ServerSlot): MCPServerOperationState {\n if (!slot.operations) slot.operations = createMCPServerOperationState();\n return slot.operations;\n }\n\n private async attemptConnect(slot: ServerSlot): Promise<void> {\n const MAX_ATTEMPTS = MCP_CONSTANTS.RECONNECT.MAX_ATTEMPTS;\n let attempt = 0;\n while (attempt < MAX_ATTEMPTS) {\n attempt++;\n const startedAt = Date.now();\n slot.state = attempt === 1 ? 'connecting' : 'reconnecting';\n slot.attempts = attempt;\n let client: MCPClient | undefined;\n let boundDisconnect: (() => void) | undefined;\n try {\n client = new MCPClient({\n name: slot.cfg.name,\n transport: slot.cfg.transport,\n command: slot.cfg.command,\n args: slot.cfg.args,\n env: slot.cfg.env,\n url: slot.cfg.url,\n headers: slot.cfg.headers,\n startupTimeoutMs: slot.cfg.startupTimeoutMs,\n requestTimeoutMs: slot.cfg.requestTimeoutMs,\n passthroughEnv: slot.cfg.passthroughEnv,\n authorizationProvider: this.authorizationProviderFactory?.(slot.cfg),\n });\n if (slot.cfg.transport === 'stdio') {\n client.addExitListener(this.onChildExit);\n } else {\n // SSE / streamable-http \u2014 wire transport disconnect to registry reconnect.\n // Capture the bound function so we can hand the same reference to\n // removeDisconnectListener on cleanup paths.\n boundDisconnect = () => this.onTransportDisconnect(slot.cfg.name);\n client.addDisconnectListener(boundDisconnect);\n }\n // L2-C: react to server-side tool changes by re-registering wrappers.\n client.addToolsChangedListener(this.onToolsChanged);\n this.addCatalogListeners(client);\n await client.connect();\n // Close any prior client before swapping refs so the old transport\n // can release its abort controller, child process, and listeners\n // instead of being held until GC.\n if (slot.client && slot.client !== client) {\n const prior = slot.client;\n const priorDisconnect = slot.onDisconnect;\n slot.client.removeExitListener(this.onChildExit);\n if (priorDisconnect) prior.removeDisconnectListener(priorDisconnect);\n prior.removeToolsChangedListener(this.onToolsChanged);\n this.removeCatalogListeners(prior);\n prior.close().catch(() => {\n /* best-effort */\n });\n }\n slot.client = client;\n slot.onDisconnect = boundDisconnect;\n const isReconnect = slot.reconnectCycles > 0 || attempt > 1;\n slot.state = 'connected';\n // L2-B: a healthy connect resets the cycle counter so future\n // crashes get the full reconnect budget again.\n slot.reconnectCycles = 0;\n const mc = client as MCPClient;\n const discovered = mc.listTools();\n await this.discoverCapabilities(slot, mc);\n // Lazy servers persist their manifest so later boots can register cold.\n await this.persistCapabilityManifest(slot);\n this.applyTools(slot, discovered, mc);\n const durationMs = Date.now() - startedAt;\n pushBounded(\n slot.operations.connectionSamples,\n durationMs,\n MCP_OPERATION_LIMITS.LATENCY_SAMPLES,\n );\n this.recordSuccess(slot, (slot.operations.lastFailureAt ?? 0) < startedAt);\n this.recordOperation(\n slot,\n isReconnect ? 'reconnect' : 'connect',\n 'connected',\n undefined,\n durationMs,\n );\n slot.lastUsed = Date.now();\n if (slot.lazy) this.ensureIdleSweep();\n this.events.emit(isReconnect ? 'mcp.server.reconnected' : 'mcp.server.connected', {\n name: slot.cfg.name,\n toolCount: slot.toolNames.length,\n });\n return; // success\n } catch (err) {\n this.recordFailure(slot, 'transport', 'connect-attempt-failed', Date.now() - startedAt);\n this.log.warn(`MCP server \"${slot.cfg.name}\" connect attempt ${attempt} failed`, err);\n if (client) {\n client.removeExitListener(this.onChildExit);\n if (boundDisconnect) client.removeDisconnectListener(boundDisconnect);\n client.removeToolsChangedListener(this.onToolsChanged);\n this.removeCatalogListeners(client);\n await client.close().catch(() => {\n /* ignore */\n });\n }\n if (attempt >= MAX_ATTEMPTS) {\n this.log.error(\n `MCP server \"${slot.cfg.name}\" connect exhausted after ${MAX_ATTEMPTS} attempts`,\n err,\n );\n slot.state = 'failed';\n slot.client = undefined;\n // The connect() loop itself doesn't schedule a backoff timer (it\n // only awaits inline setTimeouts within the `while`), but a\n // prior `scheduleReconnect` cycle may have left one outstanding.\n // Drop it so the user can `restart()` without waiting on a stale\n // fire that would race the fresh `attemptConnect`.\n if (slot.reconnectTimer) {\n clearTimeout(slot.reconnectTimer);\n slot.reconnectTimer = undefined;\n }\n slot.reconnectPending = false;\n this.events.emit('mcp.server.disconnected', {\n name: slot.cfg.name,\n reason: err instanceof Error ? err.message : 'unknown',\n });\n return;\n }\n const delay = 500 * 2 ** attempt;\n await new Promise((r) => setTimeout(r, delay));\n }\n }\n }\n}\n\nconst MAX_CATALOG_PAGES = 100;\nconst MAX_CATALOG_ITEMS = 10_000;\n\nasync function collectPages<Page extends { nextCursor?: string | undefined }, Item>(\n load: (cursor?: string | undefined) => Promise<Page>,\n select: (page: Page) => Item[],\n): Promise<Item[]> {\n const items: Item[] = [];\n const seenCursors = new Set<string>();\n let cursor: string | undefined;\n for (let pageNumber = 0; pageNumber < MAX_CATALOG_PAGES; pageNumber++) {\n const page = await load(cursor);\n items.push(...select(page));\n if (items.length > MAX_CATALOG_ITEMS) {\n throw new Error(`MCP catalog exceeds ${MAX_CATALOG_ITEMS} items`);\n }\n const next = page.nextCursor;\n if (!next) return items;\n if (seenCursors.has(next)) throw new Error(`MCP catalog repeated cursor \"${next}\"`);\n seenCursors.add(next);\n cursor = next;\n }\n throw new Error(`MCP catalog exceeds ${MAX_CATALOG_PAGES} pages`);\n}\n\nfunction cloneRecords<T>(records: T[]): T[] {\n return structuredClone(records);\n}\n\nfunction catalogSnapshot(slot: ServerSlot): MCPRegistryCatalog {\n return {\n name: slot.cfg.name,\n state: slot.state,\n serverMetadata: slot.serverMetadata ? structuredClone(slot.serverMetadata) : undefined,\n resources: slot.resources ? cloneRecords(slot.resources) : undefined,\n resourceTemplates: slot.resourceTemplates ? cloneRecords(slot.resourceTemplates) : undefined,\n prompts: slot.prompts ? cloneRecords(slot.prompts) : undefined,\n };\n}\n", "import { ToolCapabilities } from '@wrongstack/core/security';\nimport type { Permission, Tool } from '@wrongstack/core/types';\nimport type { MCPClient, MCPTool } from './client.js';\n\n/**\n * Keywords that indicate a mutating operation.\n * Applied to both the tool name and its inputSchema property names.\n */\nconst MUTATING_RE = /create|update|delete|write|send|set|put|post|patch|remove|rename|move/i;\n\nfunction isMutatingTool(mcpTool: MCPTool): boolean {\n if (MUTATING_RE.test(mcpTool.name)) return true;\n // Check property names in the input schema for mutating intent.\n // e.g. { properties: { createTable: {...}, dropIndex: {...} } }\n const schema = mcpTool.inputSchema;\n if (schema && typeof schema === 'object') {\n const props = (schema as { properties?: Record<string, unknown> }).properties;\n if (props) {\n for (const key of Object.keys(props)) {\n if (MUTATING_RE.test(key)) return true;\n }\n }\n }\n return false;\n}\n\n/**\n * Resolves the live client for a tool call. A plain {@link MCPClient} for eager\n * servers, or a thunk that connects-on-demand for lazy/dormant servers (the\n * registry passes `() => this.ensureConnected(name)`).\n */\nexport type MCPClientResolver = MCPClient | (() => Promise<MCPClient>);\n\nexport interface MCPToolCallObserver {\n onStart(): void;\n onFinish(result: { durationMs: number; ok: boolean }): void;\n}\n\nexport function wrapMCPTool(\n serverName: string,\n mcpTool: MCPTool,\n client: MCPClientResolver,\n permission: Permission = 'confirm',\n observer?: MCPToolCallObserver | undefined,\n): Tool {\n const qualifiedName = `mcp__${serverName}__${mcpTool.name}`;\n return {\n name: qualifiedName,\n description: mcpTool.description ?? `${qualifiedName} (MCP tool)`,\n usageHint: `Tool provided by MCP server \"${serverName}\". ${mcpTool.description ?? ''}`,\n permission,\n mutating: isMutatingTool(mcpTool),\n capabilities: [ToolCapabilities.MCP_PROXY],\n inputSchema: mcpTool.inputSchema ?? { type: 'object', properties: {} },\n async execute(input, _ctx, opts) {\n const startedAt = Date.now();\n observer?.onStart();\n let ok = false;\n try {\n // For a dormant lazy server this spawns the process + handshakes before\n // the first call; for an eager server it resolves to the fixed client.\n const live = typeof client === 'function' ? await client() : client;\n // Propagate the run's abort signal: on Ctrl+C the JSON-RPC request is\n // dropped AND the server is told via `notifications/cancelled` to stop\n // the in-flight work, instead of it running to completion server-side.\n const res = await live.callTool(mcpTool.name, input, { signal: opts.signal });\n if (res.isError) {\n throw new Error(stringify(res.content));\n }\n ok = true;\n return stringify(res.content);\n } finally {\n observer?.onFinish({ durationMs: Date.now() - startedAt, ok });\n }\n },\n };\n}\n\nfunction stringify(c: unknown): string {\n if (typeof c === 'string') return c;\n if (Array.isArray(c)) {\n return c\n .map((item) => {\n if (item && typeof item === 'object') {\n const t = (item as { type?: string | undefined; text?: string | undefined }).type;\n if (t === 'text') return (item as { text?: string | undefined }).text ?? '';\n return JSON.stringify(item);\n }\n return String(item);\n })\n .join('\\n');\n }\n if (c && typeof c === 'object') {\n if ('text' in (c as Record<string, unknown>)) {\n return String((c as Record<string, unknown>).text);\n }\n return JSON.stringify(c);\n }\n return String(c ?? '');\n}\n", "import { createServer, type IncomingMessage, type ServerResponse } from 'node:http';\nimport type { AddressInfo } from 'node:net';\nimport { expectDefined, toErrorMessage } from '@wrongstack/core/utils';\nimport { MCP_CONSTANTS } from './constants.js';\nimport type { MCPPromptArgument, MCPPromptMessage, MCPResourceContents } from './protocol.js';\n/**\n * Server-side MCP. The mirror image of `MCPClient`: instead of consuming a\n * remote MCP server, this lets WrongStack *be* an MCP server \u2014 exposing its\n * tools to any MCP client (Claude Desktop, another agent, an IDE) over a\n * JSON-RPC 2.0 stream.\n *\n * The protocol core (`MCPServer`) is transport-agnostic: feed it a raw JSON\n * line via `handleMessage`, get back a response string (or `null` for\n * notifications). `serveStdio` wires it to stdin/stdout for the canonical\n * stdio transport.\n */\n\n/** A tool descriptor advertised over `tools/list`. */\nexport interface MCPServerTool {\n name: string;\n description?: string | undefined;\n inputSchema: Record<string, unknown>;\n}\n\n/** The result of a `tools/call`, as the host produces it. */\nexport interface MCPServerCallResult {\n /** Text or pre-built MCP content blocks. Strings are wrapped as a text block. */\n content: unknown;\n isError: boolean;\n}\n\n/**\n * Bridges the MCP server to a tool backend (in the CLI, the `ToolRegistry`).\n * Kept narrow so the protocol core has no dependency on `@wrongstack/core`.\n */\nexport interface MCPServerToolHost {\n listTools(): MCPServerTool[] | Promise<MCPServerTool[]>;\n callTool(name: string, args: Record<string, unknown>): Promise<MCPServerCallResult>;\n}\n\nexport interface MCPServerResource {\n uri: string;\n name: string;\n title?: string | undefined;\n description?: string | undefined;\n mimeType?: string | undefined;\n size?: number | undefined;\n contents: MCPResourceContents[];\n}\n\nexport interface MCPServerPrompt {\n name: string;\n title?: string | undefined;\n description?: string | undefined;\n arguments?: MCPPromptArgument[] | undefined;\n /** Static rich messages, or a text template using {{argument}} placeholders. */\n messages?: MCPPromptMessage[] | undefined;\n template?: string | undefined;\n}\n\nexport interface MCPServerLogger {\n warn?(msg: string): void;\n info?(msg: string): void;\n}\n\nexport interface MCPServerOptions {\n host: MCPServerToolHost;\n /** Advertised in the `initialize` handshake. Defaults to the wrongstack identity. */\n serverInfo?: { name: string; version: string };\n logger?: MCPServerLogger | undefined;\n /** Explicit allowlist only; omitted means this server exposes no resources. */\n resources?: MCPServerResource[] | undefined;\n /** Explicit allowlist only; omitted means this server exposes no prompts. */\n prompts?: MCPServerPrompt[] | undefined;\n}\n\ninterface JsonRpcRequest {\n jsonrpc?: string | undefined;\n id?: number | string | null | undefined;\n method?: string | undefined;\n params?: unknown | undefined;\n}\n\n// JSON-RPC 2.0 reserved error codes.\nconst PARSE_ERROR = -32700;\nconst INVALID_REQUEST = -32600;\nconst METHOD_NOT_FOUND = -32601;\nconst INTERNAL_ERROR = -32603;\n\nexport class MCPServer {\n private readonly host: MCPServerToolHost;\n private readonly serverInfo: { name: string; version: string };\n private readonly logger?: MCPServerLogger | undefined;\n private readonly resources: MCPServerResource[];\n private readonly prompts: MCPServerPrompt[];\n\n constructor(opts: MCPServerOptions) {\n this.host = opts.host;\n this.serverInfo = opts.serverInfo ?? {\n name: MCP_CONSTANTS.CLIENT_INFO.name,\n version: MCP_CONSTANTS.CLIENT_INFO.version,\n };\n this.logger = opts.logger;\n this.resources = structuredClone(opts.resources ?? []);\n this.prompts = structuredClone(opts.prompts ?? []);\n }\n\n /**\n * Handle one raw JSON-RPC line. Returns the response JSON string for\n * requests, or `null` for notifications (no `id`) and for blank input \u2014\n * the caller should write the string to its output stream when non-null.\n */\n async handleMessage(raw: string): Promise<string | null> {\n const line = raw.trim();\n if (!line) return null;\n\n let msg: JsonRpcRequest;\n try {\n msg = JSON.parse(line) as JsonRpcRequest;\n } catch {\n return this.encodeError(null, PARSE_ERROR, 'Parse error');\n }\n\n if (typeof msg !== 'object' || msg === null || typeof msg.method !== 'string') {\n const id = msg && typeof msg === 'object' ? (msg.id ?? null) : null;\n return this.encodeError(id ?? null, INVALID_REQUEST, 'Invalid Request');\n }\n\n const isNotification = msg.id === undefined || msg.id === null;\n\n // Notifications never get a response. We still dispatch known ones for\n // side effects, but `notifications/initialized` is purely a handshake ack.\n if (isNotification) {\n return null;\n }\n\n try {\n const result = await this.dispatch(msg.method, msg.params);\n if (result === METHOD_NOT_FOUND_SENTINEL) {\n return this.encodeError(\n expectDefined(msg.id),\n METHOD_NOT_FOUND,\n `Method not found: ${msg.method}`,\n );\n }\n return JSON.stringify({ jsonrpc: '2.0', id: msg.id, result });\n } catch (err) {\n const message = toErrorMessage(err);\n this.logger?.warn?.(`MCP server: method \"${msg.method}\" threw: ${message}`);\n return this.encodeError(expectDefined(msg.id), INTERNAL_ERROR, message);\n }\n }\n\n private async dispatch(method: string, params: unknown): Promise<unknown> {\n switch (method) {\n case 'initialize':\n return {\n protocolVersion: MCP_CONSTANTS.PROTOCOL_VERSION,\n capabilities: {\n tools: { listChanged: false },\n ...(this.resources.length > 0\n ? { resources: { subscribe: false, listChanged: false } }\n : {}),\n ...(this.prompts.length > 0 ? { prompts: { listChanged: false } } : {}),\n },\n serverInfo: this.serverInfo,\n };\n case 'ping':\n return {};\n case 'tools/list': {\n const tools = await this.host.listTools();\n return { tools };\n }\n case 'tools/call': {\n const p = (params ?? {}) as { name?: unknown | undefined; arguments?: unknown | undefined };\n if (typeof p.name !== 'string') {\n throw new Error('tools/call requires a string \"name\"');\n }\n const args =\n p.arguments && typeof p.arguments === 'object' && !Array.isArray(p.arguments)\n ? (p.arguments as Record<string, unknown>)\n : {};\n const res = await this.host.callTool(p.name, args);\n return { content: toContentBlocks(res.content), isError: res.isError };\n }\n case 'resources/list': {\n if (this.resources.length === 0) return METHOD_NOT_FOUND_SENTINEL;\n const page = paginate(this.resources, params);\n return {\n resources: page.items.map(({ contents: _contents, ...resource }) => resource),\n ...(page.nextCursor ? { nextCursor: page.nextCursor } : {}),\n };\n }\n case 'resources/templates/list':\n if (this.resources.length === 0) return METHOD_NOT_FOUND_SENTINEL;\n return { resourceTemplates: [] };\n case 'resources/read': {\n if (this.resources.length === 0) return METHOD_NOT_FOUND_SENTINEL;\n const uri = requiredParamString(params, 'uri', 'resources/read');\n const resource = this.resources.find((candidate) => candidate.uri === uri);\n if (!resource) throw new Error(`Resource not found: ${uri}`);\n return { contents: structuredClone(resource.contents) };\n }\n case 'prompts/list': {\n if (this.prompts.length === 0) return METHOD_NOT_FOUND_SENTINEL;\n const page = paginate(this.prompts, params);\n return {\n prompts: page.items.map(\n ({ messages: _messages, template: _template, ...prompt }) => prompt,\n ),\n ...(page.nextCursor ? { nextCursor: page.nextCursor } : {}),\n };\n }\n case 'prompts/get': {\n if (this.prompts.length === 0) return METHOD_NOT_FOUND_SENTINEL;\n const name = requiredParamString(params, 'name', 'prompts/get');\n const prompt = this.prompts.find((candidate) => candidate.name === name);\n if (!prompt) throw new Error(`Prompt not found: ${name}`);\n const input = paramsRecord(params);\n const args = stringRecord(input['arguments'], 'prompts/get arguments');\n for (const argument of prompt.arguments ?? []) {\n if (argument.required && args[argument.name] === undefined) {\n throw new Error(`Prompt \"${name}\" requires argument \"${argument.name}\"`);\n }\n }\n const messages = prompt.template\n ? [\n {\n role: 'user' as const,\n content: { type: 'text', text: renderPromptTemplate(prompt.template, args) },\n },\n ]\n : structuredClone(prompt.messages ?? []);\n return { description: prompt.description, messages };\n }\n default:\n return METHOD_NOT_FOUND_SENTINEL;\n }\n }\n\n private encodeError(id: number | string | null, code: number, message: string): string {\n return JSON.stringify({ jsonrpc: '2.0', id, error: { code, message } });\n }\n}\n\nconst SERVER_PAGE_SIZE = 100;\n\nfunction paginate<T>(items: T[], params: unknown): { items: T[]; nextCursor?: string | undefined } {\n const cursor = paramsRecord(params)['cursor'];\n let offset = 0;\n if (cursor !== undefined) {\n if (typeof cursor !== 'string' || !/^\\d+$/.test(cursor)) {\n throw new Error('MCP pagination cursor must be a non-negative integer string');\n }\n offset = Number(cursor);\n if (!Number.isSafeInteger(offset)) throw new Error('MCP pagination cursor is too large');\n }\n const page = items.slice(offset, offset + SERVER_PAGE_SIZE);\n const next = offset + page.length;\n return {\n items: page,\n ...(next < items.length ? { nextCursor: String(next) } : {}),\n };\n}\n\nfunction paramsRecord(params: unknown): Record<string, unknown> {\n return params && typeof params === 'object' && !Array.isArray(params)\n ? (params as Record<string, unknown>)\n : {};\n}\n\nfunction requiredParamString(params: unknown, field: string, method: string): string {\n const value = paramsRecord(params)[field];\n if (typeof value !== 'string' || value.length === 0) {\n throw new Error(`${method} requires a non-empty string \"${field}\"`);\n }\n return value;\n}\n\nfunction stringRecord(value: unknown, label: string): Record<string, string> {\n if (value === undefined) return {};\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error(`${label} must be an object`);\n }\n const result: Record<string, string> = {};\n for (const [key, item] of Object.entries(value as Record<string, unknown>)) {\n if (typeof item !== 'string') throw new Error(`${label}.${key} must be a string`);\n result[key] = item;\n }\n return result;\n}\n\nfunction renderPromptTemplate(template: string, args: Record<string, string>): string {\n return template.replace(/\\{\\{([A-Za-z_][A-Za-z0-9_.-]*)\\}\\}/g, (_match, name: string) => {\n const value = args[name];\n if (value === undefined) throw new Error(`Missing prompt template argument \"${name}\"`);\n return value;\n });\n}\n\nconst METHOD_NOT_FOUND_SENTINEL = Symbol('method-not-found');\n\n/** Normalize a host result's content into MCP content blocks. */\nexport function toContentBlocks(content: unknown): Array<{ type: 'text'; text: string }> {\n if (typeof content === 'string') return [{ type: 'text', text: content }];\n if (Array.isArray(content)) {\n // Already-shaped content blocks pass through; otherwise stringify each item.\n const allBlocks = content.every(\n (c) => c && typeof c === 'object' && (c as { type?: unknown | undefined }).type === 'text',\n );\n if (allBlocks) return content as Array<{ type: 'text'; text: string }>;\n return [{ type: 'text', text: content.map((c) => stringifyItem(c)).join('\\n') }];\n }\n if (content === undefined || content === null) return [{ type: 'text', text: '' }];\n return [{ type: 'text', text: stringifyItem(content) }];\n}\n\nfunction stringifyItem(c: unknown): string {\n if (typeof c === 'string') return c;\n try {\n return JSON.stringify(c);\n } catch {\n return String(c);\n }\n}\n\nexport interface ServeStdioHandle {\n /** Stop reading and detach listeners. Does not exit the process. */\n close(): void;\n /** Resolves when the input stream ends (EOF). */\n done: Promise<void>;\n}\n\nexport interface ServeStdioOptions {\n stdin?: NodeJS.ReadableStream | undefined;\n stdout?: NodeJS.WritableStream | undefined;\n}\n\n/**\n * Run an `MCPServer` over stdio: newline-delimited JSON-RPC in on stdin,\n * responses out on stdout. CRITICAL: nothing else may write to stdout while\n * this runs \u2014 it is the JSON-RPC channel. Route all logging to stderr.\n */\nexport function serveStdio(server: MCPServer, opts: ServeStdioOptions = {}): ServeStdioHandle {\n const stdin: NodeJS.ReadableStream = opts.stdin ?? process.stdin;\n const stdout = opts.stdout ?? process.stdout;\n let buffer = '';\n let closed = false;\n let bufferTooLarge = false;\n // Serialize writes so concurrent async handlers don't interleave lines.\n let writeChain: Promise<void> = Promise.resolve();\n\n const writeLine = (s: string) => {\n writeChain = writeChain\n .then(\n () =>\n new Promise<void>((resolve) => {\n stdout.write(`${s}\\n`, () => resolve());\n }),\n )\n .catch((err) => {\n const msg = toErrorMessage(err);\n console.error(\n JSON.stringify({\n level: 'error',\n event: 'mcp_server.stdout_write_failed',\n message: msg,\n timestamp: new Date().toISOString(),\n }),\n );\n });\n };\n\n const onData = (chunk: Buffer | string) => {\n // A misbehaving peer that streams bytes forever without `\\n` would\n // otherwise balloon `buffer` indefinitely. Mirror the HTTP body cap\n // (`HTTP_BODY_CAP` below) \u2014 once exceeded, abandon the line, drop the\n // unread tail, and shut down so the caller can react.\n if (bufferTooLarge) return;\n buffer += typeof chunk === 'string' ? chunk : chunk.toString('utf8');\n if (buffer.length > HTTP_BODY_CAP) {\n bufferTooLarge = true;\n buffer = '';\n console.error(\n JSON.stringify({\n level: 'error',\n event: 'mcp_server.line_buffer_overflow',\n message: `stdio line exceeded ${HTTP_BODY_CAP} bytes without newline \u2014 aborting stream`,\n timestamp: new Date().toISOString(),\n }),\n );\n // Pause and tear down further reads so the caller sees a clean end.\n // `destroy()` is called WITHOUT an error so the stream's 'error' event\n // isn't emitted (PassThrough/mocked streams would otherwise emit\n // unhandled 'error' that callers must drain).\n try {\n (stdin as { pause?: () => void }).pause?.();\n (stdin as { destroy?: () => void }).destroy?.();\n } catch {\n /* ignore */\n }\n onEnd();\n return;\n }\n let idx = buffer.indexOf('\\n');\n while (idx !== -1) {\n const line = buffer.slice(0, idx);\n buffer = buffer.slice(idx + 1);\n idx = buffer.indexOf('\\n');\n if (!line.trim()) continue;\n void server\n .handleMessage(line)\n .then((res) => {\n // Always flush responses for in-flight requests, even after\n // the stream ended: `done` waits on writeChain, so dropping a\n // late response here would mean `done` resolves without that\n // line ever landing on stdout. Stopping new reads is `onEnd`'s\n // job \u2014 not gating writes.\n if (res !== null) writeLine(res);\n })\n .catch((err) => {\n // Malformed JSON from a peer \u2014 log and continue so one bad line\n // doesn't kill the entire session.\n console.error(\n JSON.stringify({\n level: 'error',\n event: 'mcp_server.handle_message_failed',\n message: toErrorMessage(err),\n timestamp: new Date().toISOString(),\n }),\n );\n });\n }\n };\n\n let resolveDone!: () => void;\n // `done` resolves once the stream has closed AND any in-flight writes have\n // drained. Without the writeChain tail-call, a caller that awaits\n // `handle.done` after stdin ends could see `done` resolve before the last\n // response line lands on stdout \u2014 useful, e.g., for closing a wrapper\n // process and being sure the stdout pipe is fully flushed.\n const done = new Promise<void>((resolve) => {\n resolveDone = () => {\n // Chain onto writeChain so `done` only resolves once writes drain.\n void writeChain.then(() => resolve());\n };\n });\n\n const onEnd = () => {\n if (closed) return;\n closed = true;\n stdin.off('data', onData);\n resolveDone();\n };\n\n stdin.on('data', onData);\n stdin.once('end', onEnd);\n stdin.once('close', onEnd);\n if (typeof (stdin as { resume?: () => void }).resume === 'function') {\n (stdin as { resume: () => void }).resume();\n }\n\n return {\n close: () => {\n onEnd();\n },\n done,\n };\n}\n\n// \u2500\u2500 HTTP transport \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst HTTP_BODY_CAP = 4 * 1024 * 1024; // 4 MiB\n\nexport interface ServeHttpOptions {\n /** TCP port. 0 picks an ephemeral port (resolved in the handle). Default 0. */\n port?: number | undefined;\n /** Bind address. Default '127.0.0.1' (loopback only). */\n host?: string | undefined;\n /**\n * Bearer token required on every request (`Authorization: Bearer <token>`).\n * REQUIRED when binding to a non-loopback host \u2014 `serveHttp` refuses to\n * expose tools to the network without one.\n */\n token?: string | undefined;\n logger?: MCPServerLogger | undefined;\n}\n\nexport interface ServeHttpHandle {\n port: number;\n host: string;\n url: string;\n close(): Promise<void>;\n}\n\nfunction isLoopbackHost(host: string): boolean {\n return host === '127.0.0.1' || host === '::1' || host === 'localhost';\n}\n\n/**\n * Run an `MCPServer` over HTTP: POST a single JSON-RPC request, get the JSON\n * response (notifications \u2192 202 with no body). Reuses `handleMessage`, so the\n * protocol is identical to the stdio transport.\n *\n * Security: binds to loopback by default. Binding to any other host (e.g.\n * `0.0.0.0`) REQUIRES a `token` \u2014 otherwise this rejects, because it would\n * otherwise expose tool execution to the whole network unauthenticated.\n */\nexport function serveHttp(\n server: MCPServer,\n opts: ServeHttpOptions = {},\n): Promise<ServeHttpHandle> {\n const host = opts.host ?? '127.0.0.1';\n const port = opts.port ?? 0;\n const token = opts.token;\n const log = opts.logger;\n\n if (!isLoopbackHost(host) && !token) {\n return Promise.reject(\n new Error(\n `serveHttp: refusing to bind to non-loopback host \"${host}\" without a token \u2014 ` +\n 'pass a token to expose tools to the network, or bind to 127.0.0.1.',\n ),\n );\n }\n\n const httpServer = createServer((req: IncomingMessage, res: ServerResponse) => {\n void handleHttpRequest(server, req, res, token, log);\n });\n\n return new Promise<ServeHttpHandle>((resolve, reject) => {\n httpServer.once('error', reject);\n httpServer.listen(port, host, () => {\n httpServer.removeListener('error', reject);\n const boundPort = (httpServer.address() as AddressInfo).port;\n const displayHost = host === '::1' ? '[::1]' : host;\n resolve({\n port: boundPort,\n host,\n url: `http://${displayHost}:${boundPort}/`,\n close: () =>\n new Promise<void>((res2) => {\n httpServer.close(() => res2());\n }),\n });\n });\n });\n}\n\nasync function handleHttpRequest(\n server: MCPServer,\n req: IncomingMessage,\n res: ServerResponse,\n token: string | undefined,\n log: MCPServerLogger | undefined,\n): Promise<void> {\n const send = (status: number, body: string, type = 'application/json') => {\n res.writeHead(status, { 'content-type': type });\n res.end(body);\n };\n\n // Health probe.\n if (req.method === 'GET') {\n return send(200, JSON.stringify({ status: 'ok', server: 'wrongstack-mcp' }));\n }\n if (req.method !== 'POST') {\n return send(405, JSON.stringify({ error: 'method not allowed' }));\n }\n if (token) {\n const auth = req.headers.authorization ?? '';\n const expected = `Bearer ${token}`;\n if (auth !== expected) {\n return send(401, JSON.stringify({ error: 'unauthorized' }));\n }\n }\n\n let body = '';\n req.on('data', (chunk: Buffer) => {\n body += chunk.toString('utf8');\n if (body.length > HTTP_BODY_CAP) {\n send(413, JSON.stringify({ error: 'payload too large' }));\n req.destroy();\n }\n });\n req.on('end', () => {\n void server\n .handleMessage(body)\n .then((out) => {\n // Notifications produce no response body.\n if (out === null) return send(202, '');\n return send(200, out);\n })\n .catch((err) => {\n log?.warn?.(`MCP http handler error: ${toErrorMessage(err)}`);\n send(500, JSON.stringify({ error: 'internal error' }));\n });\n });\n}\n", "import * as fs from 'node:fs/promises';\nimport type { MCPServerConfig, SecretVault } from '@wrongstack/core/types';\nimport { atomicWrite, withFileLock } from '@wrongstack/core/utils';\nimport {\n authorizationHeaderForToken,\n canonicalMcpResource,\n type MCPAuthorizationChallenge,\n type MCPAuthorizationContext,\n type MCPAuthorizationProvider,\n type MCPAuthorizationServerMetadata,\n type MCPTokenSet,\n refreshMcpAccessToken,\n validateMcpAuthorizationServerMetadata,\n} from './authorization.js';\n\nconst TOKEN_STORE_VERSION = 1 as const;\nconst MAX_STORE_BYTES = 1024 * 1024;\nconst MAX_ENTRIES = 256;\nconst DEFAULT_REFRESH_SKEW_MS = 60_000;\n\nexport interface MCPStoredAuthorization {\n serverName: string;\n resource: string;\n clientId: string;\n authorizationServer: MCPAuthorizationServerMetadata;\n tokenSet: MCPTokenSet;\n updatedAt: string;\n}\n\ninterface EncryptedAuthorizationEntry {\n serverName: string;\n resource: string;\n clientId: string;\n authorizationServer: MCPAuthorizationServerMetadata;\n accessToken: string;\n refreshToken?: string | undefined;\n tokenType: string;\n expiresAt?: number | undefined;\n scopes: string[];\n updatedAt: string;\n}\n\ninterface TokenStoreFile {\n version: typeof TOKEN_STORE_VERSION;\n updatedAt: string;\n entries: EncryptedAuthorizationEntry[];\n}\n\nexport interface MCPAuthorizationStateEvent {\n serverName: string;\n state: 'authorized' | 'refreshed' | 'reauth_required' | 'removed';\n resource: string;\n expiresAt?: number | undefined;\n scopes?: string[] | undefined;\n}\n\nexport interface MCPRefreshingAuthorizationProviderOptions {\n serverName: string;\n resource: string;\n store: MCPVaultTokenStore;\n refreshSkewMs?: number | undefined;\n onStateChange?: ((event: MCPAuthorizationStateEvent) => void) | undefined;\n}\n\nexport interface MCPVaultProviderFactoryOptions {\n store: MCPVaultTokenStore;\n refreshSkewMs?: number | undefined;\n onStateChange?: ((event: MCPAuthorizationStateEvent) => void) | undefined;\n}\n\nexport class MCPVaultTokenStore {\n constructor(\n private readonly filePath: string,\n private readonly vault: SecretVault,\n ) {}\n\n async load(serverName: string, resource: string): Promise<MCPStoredAuthorization | undefined> {\n const canonicalResource = canonicalMcpResource(resource);\n return withFileLock(this.filePath, async () => {\n const file = await this.readFile();\n const entry = file.entries.find(\n (candidate) =>\n candidate.serverName === serverName && candidate.resource === canonicalResource,\n );\n return entry ? this.decryptEntry(entry) : undefined;\n });\n }\n\n async save(value: MCPStoredAuthorization): Promise<void> {\n const normalized = normalizeStoredAuthorization(value);\n await withFileLock(this.filePath, async () => {\n const file = await this.readFile();\n const next = file.entries.filter(\n (entry) =>\n !(entry.serverName === normalized.serverName && entry.resource === normalized.resource),\n );\n next.push(this.encryptEntry(normalized));\n if (next.length > MAX_ENTRIES)\n throw new Error(`MCP token store exceeds ${MAX_ENTRIES} entries`);\n await this.writeFile(next);\n });\n }\n\n async remove(serverName: string, resource: string): Promise<boolean> {\n const canonicalResource = canonicalMcpResource(resource);\n return withFileLock(this.filePath, async () => {\n const file = await this.readFile();\n const next = file.entries.filter(\n (entry) => !(entry.serverName === serverName && entry.resource === canonicalResource),\n );\n if (next.length === file.entries.length) return false;\n await this.writeFile(next);\n return true;\n });\n }\n\n private async readFile(): Promise<TokenStoreFile> {\n let raw: string;\n try {\n const stat = await fs.stat(this.filePath);\n if (stat.size > MAX_STORE_BYTES) throw new Error('MCP token store exceeds size limit');\n raw = await fs.readFile(this.filePath, 'utf8');\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return emptyFile();\n throw error;\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw new Error('MCP token store is not valid JSON');\n }\n return validateStoreFile(parsed);\n }\n\n private async writeFile(entries: EncryptedAuthorizationEntry[]): Promise<void> {\n const file: TokenStoreFile = {\n version: TOKEN_STORE_VERSION,\n updatedAt: new Date().toISOString(),\n entries,\n };\n await atomicWrite(this.filePath, `${JSON.stringify(file, null, 2)}\\n`, { mode: 0o600 });\n }\n\n private encryptEntry(value: MCPStoredAuthorization): EncryptedAuthorizationEntry {\n const accessToken = this.vault.encrypt(value.tokenSet.accessToken);\n const refreshToken = value.tokenSet.refreshToken\n ? this.vault.encrypt(value.tokenSet.refreshToken)\n : undefined;\n if (\n !this.vault.isEncrypted(accessToken) ||\n (refreshToken && !this.vault.isEncrypted(refreshToken))\n ) {\n throw new Error('MCP token store requires an encrypting SecretVault');\n }\n return {\n serverName: value.serverName,\n resource: value.resource,\n clientId: value.clientId,\n authorizationServer: value.authorizationServer,\n accessToken,\n refreshToken,\n tokenType: value.tokenSet.tokenType ?? 'Bearer',\n expiresAt: value.tokenSet.expiresAt,\n scopes: [...(value.tokenSet.scopes ?? [])],\n updatedAt: value.updatedAt,\n };\n }\n\n private decryptEntry(entry: EncryptedAuthorizationEntry): MCPStoredAuthorization {\n if (\n !this.vault.isEncrypted(entry.accessToken) ||\n (entry.refreshToken !== undefined && !this.vault.isEncrypted(entry.refreshToken))\n ) {\n throw new Error('MCP token store contains an unencrypted token');\n }\n const value: MCPStoredAuthorization = {\n serverName: entry.serverName,\n resource: entry.resource,\n clientId: entry.clientId,\n authorizationServer: entry.authorizationServer,\n tokenSet: {\n accessToken: this.vault.decrypt(entry.accessToken),\n refreshToken: entry.refreshToken ? this.vault.decrypt(entry.refreshToken) : undefined,\n tokenType: entry.tokenType,\n resource: entry.resource,\n expiresAt: entry.expiresAt,\n scopes: [...entry.scopes],\n },\n updatedAt: entry.updatedAt,\n };\n return normalizeStoredAuthorization(value);\n }\n}\n\nexport class MCPRefreshingAuthorizationProvider implements MCPAuthorizationProvider {\n private refreshPromise?: Promise<MCPStoredAuthorization | undefined> | undefined;\n private readonly resource: string;\n private readonly refreshSkewMs: number;\n\n constructor(private readonly options: MCPRefreshingAuthorizationProviderOptions) {\n this.resource = canonicalMcpResource(options.resource);\n this.refreshSkewMs = options.refreshSkewMs ?? DEFAULT_REFRESH_SKEW_MS;\n }\n\n async getAccessToken(context: MCPAuthorizationContext): Promise<MCPTokenSet | undefined> {\n this.assertContext(context);\n let state = await this.options.store.load(this.options.serverName, this.resource);\n if (!state) return undefined;\n if (\n state.tokenSet.expiresAt !== undefined &&\n state.tokenSet.expiresAt <= Date.now() + this.refreshSkewMs\n ) {\n state = await this.refresh(state, context.signal);\n }\n if (!state) return undefined;\n if (state.tokenSet.expiresAt !== undefined && state.tokenSet.expiresAt <= Date.now()) {\n this.emit('reauth_required', state);\n return undefined;\n }\n authorizationHeaderForToken(state.tokenSet, this.resource);\n return { ...state.tokenSet, scopes: [...(state.tokenSet.scopes ?? [])] };\n }\n\n async handleUnauthorized(\n challenge: MCPAuthorizationChallenge,\n context: MCPAuthorizationContext,\n ): Promise<boolean> {\n this.assertContext(context);\n if (challenge.resource !== this.resource) return false;\n const state = await this.options.store.load(this.options.serverName, this.resource);\n if (!state?.tokenSet.refreshToken) {\n if (state) this.emit('reauth_required', state);\n return false;\n }\n return (await this.refresh(state, context.signal)) !== undefined;\n }\n\n private refresh(\n state: MCPStoredAuthorization,\n signal?: AbortSignal | undefined,\n ): Promise<MCPStoredAuthorization | undefined> {\n if (this.refreshPromise) return this.refreshPromise;\n this.refreshPromise = this.refreshInner(state, signal).finally(() => {\n this.refreshPromise = undefined;\n });\n return this.refreshPromise;\n }\n\n private async refreshInner(\n state: MCPStoredAuthorization,\n signal?: AbortSignal | undefined,\n ): Promise<MCPStoredAuthorization | undefined> {\n const refreshToken = state.tokenSet.refreshToken;\n if (!refreshToken) {\n this.emit('reauth_required', state);\n return undefined;\n }\n const tokenSet = await refreshMcpAccessToken({\n authorizationServer: state.authorizationServer,\n clientId: state.clientId,\n resource: state.resource,\n refreshToken,\n signal,\n });\n const next = normalizeStoredAuthorization({\n ...state,\n tokenSet,\n updatedAt: new Date().toISOString(),\n });\n await this.options.store.save(next);\n this.emit('refreshed', next);\n return next;\n }\n\n private assertContext(context: MCPAuthorizationContext): void {\n if (context.serverName !== this.options.serverName || context.resource !== this.resource) {\n throw new Error('MCP authorization provider context does not match its server/resource');\n }\n }\n\n private emit(state: MCPAuthorizationStateEvent['state'], value: MCPStoredAuthorization): void {\n this.options.onStateChange?.({\n serverName: value.serverName,\n state,\n resource: value.resource,\n expiresAt: value.tokenSet.expiresAt,\n scopes: [...(value.tokenSet.scopes ?? [])],\n });\n }\n}\n\nexport function createVaultBackedMcpAuthorizationProviderFactory(\n options: MCPVaultProviderFactoryOptions,\n): (server: Readonly<MCPServerConfig>) => MCPAuthorizationProvider | undefined {\n const providers = new Map<string, MCPRefreshingAuthorizationProvider>();\n return (server) => {\n if (server.transport === 'stdio' || !server.url) return undefined;\n const resource = canonicalMcpResource(server.url);\n const key = `${server.name}\\0${resource}`;\n let provider = providers.get(key);\n if (!provider) {\n provider = new MCPRefreshingAuthorizationProvider({\n serverName: server.name,\n resource,\n store: options.store,\n refreshSkewMs: options.refreshSkewMs,\n onStateChange: options.onStateChange,\n });\n providers.set(key, provider);\n }\n return provider;\n };\n}\n\nfunction emptyFile(): TokenStoreFile {\n return { version: TOKEN_STORE_VERSION, updatedAt: new Date(0).toISOString(), entries: [] };\n}\n\nfunction validateStoreFile(value: unknown): TokenStoreFile {\n if (\n !isRecord(value) ||\n value['version'] !== TOKEN_STORE_VERSION ||\n !Array.isArray(value['entries'])\n ) {\n throw new Error('MCP token store has an unsupported or malformed structure');\n }\n if (value['entries'].length > MAX_ENTRIES)\n throw new Error('MCP token store has too many entries');\n return {\n version: TOKEN_STORE_VERSION,\n updatedAt: boundedString(value['updatedAt'], 'updatedAt', 128),\n entries: value['entries'].map(validateEncryptedEntry),\n };\n}\n\nfunction validateEncryptedEntry(value: unknown): EncryptedAuthorizationEntry {\n if (!isRecord(value)) throw new Error('MCP token store entry must be an object');\n const resource = canonicalMcpResource(boundedString(value['resource'], 'resource', 4_096));\n const authorizationServer = validateMcpAuthorizationServerMetadata(value['authorizationServer']);\n const scopes = stringArray(value['scopes'], 'scopes', 128);\n const expiresAt = value['expiresAt'];\n if (expiresAt !== undefined && (typeof expiresAt !== 'number' || !Number.isFinite(expiresAt))) {\n throw new Error('MCP token store expiresAt must be a finite number');\n }\n return {\n serverName: boundedString(value['serverName'], 'serverName', 256),\n resource,\n clientId: boundedString(value['clientId'], 'clientId', 4_096),\n authorizationServer,\n accessToken: boundedString(value['accessToken'], 'accessToken', 32_768),\n refreshToken:\n value['refreshToken'] === undefined\n ? undefined\n : boundedString(value['refreshToken'], 'refreshToken', 32_768),\n tokenType: boundedString(value['tokenType'], 'tokenType', 64),\n expiresAt: expiresAt as number | undefined,\n scopes,\n updatedAt: boundedString(value['updatedAt'], 'updatedAt', 128),\n };\n}\n\nfunction normalizeStoredAuthorization(value: MCPStoredAuthorization): MCPStoredAuthorization {\n const serverName = boundedString(value.serverName, 'serverName', 256);\n const resource = canonicalMcpResource(value.resource);\n const authorizationServer = validateMcpAuthorizationServerMetadata(value.authorizationServer);\n if (canonicalMcpResource(value.tokenSet.resource) !== resource) {\n throw new Error('MCP token resource mismatch');\n }\n const tokenSet: MCPTokenSet = {\n ...value.tokenSet,\n resource,\n scopes: stringArray(value.tokenSet.scopes ?? [], 'scopes', 128),\n };\n authorizationHeaderForToken({ ...tokenSet, expiresAt: undefined }, resource);\n return {\n serverName,\n resource,\n clientId: boundedString(value.clientId, 'clientId', 4_096),\n authorizationServer,\n tokenSet,\n updatedAt: boundedString(value.updatedAt, 'updatedAt', 128),\n };\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction boundedString(value: unknown, field: string, maxLength: number): string {\n if (\n typeof value !== 'string' ||\n value.length === 0 ||\n value.length > maxLength ||\n /[\\r\\n]/.test(value)\n ) {\n throw new Error(`MCP token store field \"${field}\" is invalid`);\n }\n return value;\n}\n\nfunction stringArray(value: unknown, field: string, maxItems: number): string[] {\n if (!Array.isArray(value) || value.length > maxItems) {\n throw new Error(`MCP token store field \"${field}\" must be a bounded array`);\n }\n return [...new Set(value.map((entry) => boundedString(entry, field, 256)))];\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["request", "lookup", "record", "record", "requiredString", "optionalString", "value", "https", "ConfigError", "net", "ConfigError", "ToolError", "randomBytes", "ToolError", "ToolError", "ToolError", "randomBytes", "body", "request", "randomBytes", "path", "createHash", "randomBytes", "fs", "createHash", "randomBytes", "expectDefined", "toErrorMessage", "expectDefined", "toErrorMessage", "body", "fs", "stat"]
7
7
  }