/** * Shared Aexol-backend MCP client bootstrap for native extensions. * * Extracted from `aexol-mcp.ts` (behavior-preserving: identical config/ * token resolution, identical tools/list bootstrap and OAuth re-auth flow, * identical diagnostic strings) so other extensions that talk to the same * JSON-RPC MCP backend can reuse one chunk of logic. * * Responsibilities: * 1. Reads ~/.spectral/config.json (written by `spectral login`). * 2. Resolves the effective API URL: SPECTRAL_MCP_URL > stored > default. * 3. Resolves the auth token: teamApiKey > userJwt. * 4. Instantiates AexolMcpClient and performs the initial tools/list call. * 5. On 401/403 from tools/list, runs the OAuth re-auth flow once and * retries the catalog fetch with a fresh token. * * Failure modes are non-fatal: instead of throwing, the factory returns a * discriminated outcome. Transient diagnostics are streamed through an * optional `warn` sink so each caller can render them with its own log * prefix; the terminal failure reason travels in the returned outcome. */ import { AexolMcpClient, type McpContentItem, type McpTool } from "../mcp-client.js"; import { ensureAuthenticated } from "../auth-helper.js"; /** Sink for transient bootstrap diagnostics (line without prefix/newline). */ export type BootstrapWarn = (line: string) => void; export interface CreateAexolBackendClientOptions { /** * Receives transient diagnostics (tools/list failure, re-auth progress). * Defaults to writing `[aexol-backend-client] ` to stderr — extension * callers should pass a sink with their own prefix. */ warn?: BootstrapWarn; } /** * Successfully-bootstrapped client handle. * * NOTE: if the initial tools/list hit a 401/403 and re-auth succeeded, `tools` * comes from a retry client while `client` is still the initially-created one. * This intentionally mirrors the original aexol-mcp.ts behavior (call-time * tools/call kept using the boot-time client). */ export interface AexolBackendClient { /** Ready-to-use JSON-RPC MCP client for tools/call (and tools/list). */ client: AexolMcpClient; /** Effective backend URL (SPECTRAL_MCP_URL > stored config > default). */ apiUrl: string; /** Tool catalog returned by the initial tools/list call. */ tools: McpTool[]; /** * Re-auth helper (OAuth browser flow) for later 401/403 recovery; see * `../auth-helper.js` for semantics (no-op failure in non-UI sessions). * The caller owns rebuilding the client from the returned fresh config. */ ensureAuthenticated: typeof ensureAuthenticated; /** Render backend tool result content into one model-readable string. */ renderContentToString: typeof renderContentToString; } export type AexolBackendBootstrapFailureReason = "no-config" | "no-token" | "catalog-failed"; export interface AexolBackendBootstrapFailure { ok: false; reason: AexolBackendBootstrapFailureReason; /** Fully-formed diagnostic, ready to be prefixed and written by the caller. */ message: string; } export type AexolBackendBootstrap = ({ ok: true; } & AexolBackendClient) | AexolBackendBootstrapFailure; /** * Render a backend tool result into a single string for ext. * * The Aexol backend wraps results as `{ content: [{ type: "json", json: ... }] }` * but may also send `{ type: "text", text: ... }`. We pick the first content * item, prefer JSON when present (pretty-print so the model can read it), * fall back to text, and last-resort stringify the whole content array. */ export declare function renderContentToString(content: McpContentItem[]): string; /** * Bootstrap a connection to the Aexol backend MCP endpoint. * * Non-fatal by design: returns a failure outcome (never throws) when the * config or token is missing, or when the initial tools/list call cannot be * completed even after the OAuth re-auth attempt. */ export declare function createAexolBackendClient(options?: CreateAexolBackendClientOptions): Promise; //# sourceMappingURL=aexol-backend-client.d.ts.map