/** * Copyright (c) 2026, Salesforce, Inc., * All rights reserved. * For full license text, see the LICENSE.txt file */ import { type RetryHint } from "../lib/errors.js"; /** * Shared MCP tool adapter (W-22697673). Wraps an intent invocation so that any * throw becomes a sanitized, category-prefixed error envelope instead of leaking * a raw stack/file path to the MCP host. Categories (message prefix): * - `UserInput:` — bad agent input / spec violations (FR-8.3/8.4, GraphQL Name, * walker navigation). * - `Auth:` — credential resolution failures. * - `Schema:` — introspection / priming / schema-build failures. * - `Internal:` — everything else; message + a truncated stack (the full error * is logged to stderr, off the stdio channel). * * Auth/Schema/UserInput are carried by typed markers (AuthError, SchemaError, * SchemaRefreshError, UserInputError, MutationContextError) classified by * `instanceof`; the message-shape heuristics below are a secondary fallback for * untyped throws. The sanitized message is returned for EVERY category — not * just Internal — because typed Auth/Schema errors embed cache/lock paths and * wrapped jsforce/@salesforce/core causes embed `~/.sfdx/...` paths. * * Retryability hint (W-23148365): a `Schema:` error — and ONLY a `Schema:` error — * additionally ends with a closed-set token telling the host whether to retry: * ` [retry=now]` (retry immediately; no live org round-trip occurred — a priming- * lock timeout, or a refresh where a usable cached schema survives), ` [retry=backoff]` * (the introspection request failed transiently AND already exhausted the * connection layer's one built-in retry — wait briefly), or NO token (permanent: * 4xx, malformed/absent `__schema`, GraphQL errors in the body, no cached schema — * don't retry; fix the request, re-auth, or re-prime). The `: ` prefix is * unchanged. The disposition comes from the typed error's stamped `retry` field, * with a defensive `cause`-chain fallback (`classifyCause`) for untyped throws. */ export type ErrorCategory = "UserInput" | "Auth" | "Schema" | "Internal"; interface ToolTextResult { [key: string]: unknown; content: { type: "text"; text: string; }[]; isError?: boolean; } /** * Markers substituted for redacted local paths. Exported as the single source of * truth so tests assert against these constants instead of re-typing the literals * (closes the drift between the sanitizer and its tests). */ export declare const PATH_MARKERS: { readonly schemaCache: ""; readonly graphitiHome: ""; readonly home: "~"; readonly redacted: ""; }; /** * Escape (not strip) control / format characters in host-visible error text so * reflected caller input cannot inject newlines, ANSI escapes, or bidi overrides * (W-23148363). Escaping mirrors the SUCCESS envelope's JSON.stringify semantics * (`\n` -> `\\x0a`, U+202E -> `\\u202e`) -- the byte stays visible for debugging but * inert. Ordinary Unicode (accented names, CJK labels) is untouched. Astral code * points (e.g. the U+E0000-E007F tag block) render as `\\u{...}`; `CONTROL_CHAR_RE` * carries the `u` flag so they match (and escape) as a single code point. */ export declare function neutralizeControlChars(s: string): string; /** * Redact local filesystem layout from error text so the MCP host never sees the * developer's home dir, OS username, repo checkout location, or schema-cache * path (W-22697673 info-disclosure). Applied to every category's message. Also * neutralizes Cc/Cf control chars (via `neutralizeControlChars`, LAST) so it is * the single primitive the CLI mirror's error path reuses to sanitize a raw * `err.message`/stack before emitting it (W-23336442, N2). */ export declare function sanitizePaths(s: string): string; /** * Classify a thrown error into a category, a Schema-only retry hint, and a * sanitized message text. `retry` is `"no"` for every non-Schema category. */ export declare function classifyError(e: unknown): { category: ErrorCategory; retry: RetryHint; text: string; }; /** * Run an MCP tool's intent invocation. Returns the success envelope * (`JSON.stringify(output)`) or a category-prefixed `{ isError: true }` envelope. * Internal (unexpected) errors are additionally logged in full to stderr, which * is separate from the stdio JSON-RPC channel, so operators keep the real stack. */ export declare function runTool(fn: () => Promise): Promise; export {};