import { SfCommand } from '@salesforce/sf-plugins-core'; import { Messages, SfError } from '@salesforce/core'; import type { Connection } from '@salesforce/core'; import { type IConnectionFacade } from '../adapters/connection-facade.js'; import { SoqlQueryAdapter } from '../adapters/soql/soql-query-adapter.js'; import { RestApiAdapter } from '../adapters/rest/rest-api-adapter.js'; import { ToolingApiAdapter } from '../adapters/tooling/tooling-api-adapter.js'; /** * Connection context returned by {@link CuneiformCommand.initConnection}. * * Contains the connection facade and pre-built adapters that most commands need. */ export type ConnectionContext = { /** The connection facade for the target org */ facade: IConnectionFacade; /** SOQL query adapter wrapping the facade */ soqlAdapter: SoqlQueryAdapter; /** REST API adapter wrapping the facade */ restAdapter: RestApiAdapter; /** Tooling API adapter wrapping the facade */ toolingAdapter: ToolingApiAdapter; }; /** * Creates the standard adapter stack from a connection facade. * * Single source of truth for adapter instantiation. All commands, operations, * and MCP tools should use this instead of constructing adapters inline. * * @param facade - The connection facade for the target org * @returns Object containing all three adapter instances */ export declare function createAdapterStack(facade: IConnectionFacade): { soqlAdapter: SoqlQueryAdapter; restAdapter: RestApiAdapter; toolingAdapter: ToolingApiAdapter; }; /** * Abstract base class for all Cuneiform CLI commands. * * Provides a shared access gate that validates the authenticated user has * the required Cuneiform permission sets and that Global Profiling is enabled * before allowing command execution. * * Subclasses call `this.enforceAccessGate(facade)` at the start of their * `run()` method after obtaining the connection facade. Commands that should * bypass the gate (e.g., `user details`, which IS the diagnostic tool) simply * omit the `enforceAccessGate()` call. * * The `skipAccessGate` static property is used by the UX snapshot test * harness to auto-stub the gate for non-access-gate test scenarios. * * @template T The command result type * * @example * ```typescript * export default class MyCommand extends CuneiformCommand { * public async run(): Promise { * const { flags } = await this.parse(MyCommand); * const { facade, soqlAdapter, restAdapter } = await this.initConnection(flags); * * // Business logic follows — adapters and access gate already handled * const service = new MyService({ soqlAdapter, restAdapter }); * } * } * ``` */ export declare abstract class CuneiformCommand extends SfCommand { /** * Set to `true` in subclasses that should bypass the access gate. * Example: `user details` is exempt because it IS the diagnostic tool. */ protected static skipAccessGate: boolean; /** * Resolves an error code to an i18n message using a command-specific error code map. * * Looks up the error code in the provided map, retrieves the corresponding i18n * message, and returns it. If the message contains a `%s` placeholder, interpolates * the fallback string. Messages with `%d` placeholders return the fallback directly * since numeric interpolation requires context the caller must provide. * * Returns the fallback directly when errorCode is undefined or not in the map. * * @param errorCodeMap - Command-specific mapping of error codes to message bundle keys * @param errorCode - The error code from the operation result * @param fallback - The pre-formatted message from the operation layer * @param msgs - The command's Messages instance for i18n lookup * @returns The resolved user-facing error message */ protected static resolveErrorMessage(errorCodeMap: Record, errorCode: string | undefined, fallback: string, msgs: Messages): string; /** * Normalizes a multi-value string flag: splits on commas, trims whitespace, and * deduplicates. Used by commands that accept comma-separated values in flags * (e.g., `--request-ids`, `--definition-names`). * * @param raw - The raw flag value array from oclif flag parsing * @param options - Optional configuration * @param options.caseInsensitive - When true, deduplicates case-insensitively while preserving the casing of the first occurrence * @returns Deduplicated array of trimmed values, or undefined if input is empty */ protected static parseMultiValueFlag(raw: string[] | undefined, options?: { caseInsensitive?: boolean; }): string[] | undefined; /** * Resolves the user-facing error message for an access gate failure. * * Maps service error codes to message bundle keys for actionable * error messages that guide the user toward resolution. */ private static resolveAccessGateMessage; /** * Sanitizes JSON output by stripping stack traces and error causes. * * Prevents exposing Node.js stack traces and absolute filesystem paths * in `--json` error output. Success JSON output is unaffected since it * never contains `stack` or `cause` properties. */ logJson(json: unknown): void; /** * Intercepts oclif parse errors to fix misleading "Try this" suggestions for * boolean flags declared with `allowNo: true` (CLI-3379). * * When a user passes a value to a boolean flag (e.g., `--skip-empty false`), * oclif rejects the value as an unexpected argument and upstream * `SfCommandError.appendErrorSuggestions` produces a misleading suggestion * like `--skip-empty "--skip-empty false"` — the result of two upstream bugs: * (1) `k.input` is wrongly prepended to args; (2) the suggestion logic has no * awareness of `--[no-]` boolean flags. * * This override pre-processes the raw parse-output token stream BEFORE * delegating to `super.catch`. For each FlagToken→ArgToken pair where the * flag is a boolean with `allowNo: true`, it: * - Pushes the correct `--no-` (for false-y values) or `--` (for true-y values) onto `error.actions`. * - Splices the ArgToken out of `error.parse.output.raw` so upstream's buggy `appendErrorSuggestions` emits no suggestion for that pair. * * Unrecognized values (e.g., `--skip-empty bogus`) and non-boolean flags are * left alone — upstream's behavior is preserved as fallback. */ catch(error: Error | SfError): Promise; /** * Enforces the Cuneiform profiling access gate. * * Validates that the authenticated user has: * 1. Cuneiform for Salesforce installed in the org * 2. Required permission sets assigned * 3. Global Profiling enabled * * Throws an SfError with an actionable, user-friendly error message * from the `cuneiform.access` message bundle if any check fails. * * @param facade - The connection facade for the target org * @throws {SfError} If the user cannot use Cuneiform commands */ enforceAccessGate(facade: IConnectionFacade): Promise; /** * Initializes the connection facade and standard adapters for a command. * * Encapsulates the common 5-line boilerplate shared by 16 of 18 commands: * get connection, create facade, enforce access gate, create adapters. * * Commands that bypass the access gate (e.g., `user details` with * `skipAccessGate = true`) will skip the gate check automatically. * * @param flags - The parsed command flags containing target-org and api-version * @returns Connection context with facade and pre-built adapters * @throws {SfError} If the access gate check fails */ protected initConnection(flags: { 'target-org': { getConnection(apiVersion?: string): Connection; }; 'api-version'?: string; }): Promise; }