import type { Command } from 'commander'; import { getErrorMessage, ok, redactSensitiveErrorMessage, type ResultEnvelope } from 'peaks-loop-shared/result'; import type { ArtifactProvider, GuidedArtifactSetup } from '../services/artifacts/artifact-service.js'; import type { ConfigLayer } from '../services/config/config-service.js'; import type { RecommendationWorkflow } from '../services/recommendations/recommendation-service.js'; export type ProgramIO = { stdout: (text: string) => void; stderr: (text: string) => void; }; /** * `warning` text as it may be PRINTED: control characters replaced with `?`, * never truncated, so a reader sees that something was there and loses nothing. * * A warning's `path`/`message` can carry `gate-evidence-derivation`'s * `gateEvidence.`, whose key is parsed out of the handoff frontmatter — a * quoted YAML key can decode to a newline and forge a line of this command's own * output. Both branches (success, failure) call this, hence its home here. * * LIMITATION, so it is not read as a guarantee: `printResult` is not itself a * sanitizer, so this holds per CALL SITE — a third warning-formatting site, or * any caller passing unvetted text to `printResult`, is raw until it calls this. * `printableToken` in `.husky/pipeline/contract-verdict.mjs` is the same defence. * The two cannot share one implementation TODAY for a packaging reason, not in * principle: `package.json#files` ships `dist/**`, `bin/**` and named `scripts/*` * but not `.husky/**`, and `allowJs` is off — a shared module would have to be * plain JS inside the shipped `src/` tree, which that boundary does not permit. * Until it does, this copy is a latent drift. */ export declare function printableWarningText(value: string): string; export declare function printResult(io: ProgramIO, result: ResultEnvelope, asJson?: boolean): void; export declare function printSuperCommandCatalog(io: ProgramIO): void; export declare function addJsonOption(command: Command): Command; export declare function failUnsupportedNonDryRun(io: ProgramIO, command: string, asJson?: boolean): void; /** CLI shim helper: render a `{ ok: boolean, error?, data? }` envelope * and set `process.exitCode = 1` on failure. * * Library functions MUST return envelopes like `{ ok, error?, data? }` * and MUST NOT mutate `process.exitCode` themselves. The shim (the * Commander `.action()` callback in `register*Commands`) owns the * process-exit side-effect so the library can be re-used from non-CLI * contexts (vitest, programmatic dispatch, plugin loading). * * Output format mirrors the existing `registerSedimentCommands` shim: * a JSON envelope on stdout (one line, parseable), nothing else. */ export interface CliEnvelope { ok: boolean; error?: string; data?: unknown; } export declare function printCliEnvelope(io: ProgramIO, r: CliEnvelope): void; /** * for `src/cli/index.ts`'s 3 raw `console.error(JSON.stringify(...))` * sites, plus `src/cli/program.ts:162`'s default `ProgramIO.stderr` * fallback. * * Replaces the hand-rolled JSON literal with a real `fail()` envelope * from `peaks-loop-shared/result`. The helper: * - mints a fresh `errorId` per call (correlation handle for * downstream logs / LLM-side consumers); * - runs `message` through `redactSensitiveErrorMessage` BEFORE * serializing, so Bearer tokens, API keys, PAT strings, etc. never * reach the terminal; * - writes pretty JSON to stderr (single line is fine for `JSON.stringify` * without `null, 2`, but pretty is friendlier for human readers and * match the shape `peaks --json` already produces); * - sets `process.exitCode = 1` so callers that throw through * Commander's exit-override still observe the correct exit code. * * Human-NL-Choice-Only compliance: the helper does NOT print any * "Run peaks " hints. `nextActions` is rendered verbatim * (e.g. "Run `peaks --help` to list available commands") — those * are LLMs-coordinated actions, never user-typed CLI verbs. * * The original `// TODO(g2): legacy console.error without envelope` * grace comment carried in `src/cli/index.ts` (lines 35/73/87) and * `src/cli/program.ts:162` is hereby resolved by this helper. */ export declare function printErrorEnvelope(io: ProgramIO, command: string, code: string, message: string, data: Record, nextActions: string[]): void; /** * The subcommand path the caller actually invoked, in the same tokens they * typed (`release canary`). Derived from the registered command tree by * consuming leading non-`-` argv tokens, so it never disagrees with what * Commander dispatched on. * * Commander's `CommanderError` carries a code and a message but no command * reference — `missingMandatoryOptionValue` is raised by the leaf command and * throws out of `parseAsync` with nothing naming it. Without this walk the * missing-option envelope could only say `command: "cli"`, which is the field * the caller needs to act on. */ export declare function resolveInvokedCommandPath(program: Command, argv: readonly string[]): string; /** * Render the `MISSING_REQUIRED_OPTION` envelope for a Commander * `commander.missingMandatoryOptionValue`. * * A `.requiredOption()` the caller did not supply is raised as a plain * `Error`-shaped `CommanderError`, so an unhandled `.catch()` used to file it * under `UNHANDLED_ERROR` — "you left out an argument" reported as a crash, * with empty `nextActions`, `command: "cli"` and no way to see WHICH option. * The flags string Commander formats carries both the name and the accepted * values (`--percent <10|50>`), so it is worth extracting rather than * paraphrasing: it is the option's own declaration. * * Exported because it has TWO callers that must not drift: the real wrapper * (`src/cli/index.ts`) and the in-process test runner * (`tests/integration/_cli-helper.ts`), which re-creates the wrapper's * behaviour for tests that call the program directly. That file used to * hand-mirror the pre-fix shape, so every integration test that hit a missing * required option asserted an envelope production no longer emits. Sharing the * builder is what makes the mirror incapable of lying. */ export declare function printMissingRequiredOptionEnvelope(io: ProgramIO, invokedCommand: string, message: string): void; export declare function isRecommendationWorkflow(value: string): value is RecommendationWorkflow; export declare function isArtifactProvider(value: string): value is ArtifactProvider; export declare function isArtifactSetupStep(value: string): value is GuidedArtifactSetup['step']; export declare function isArtifactRepoSegment(value: string): boolean; export declare function parseConfigLayer(value: string | undefined): ConfigLayer | undefined | null; export declare function printInvalidConfigLayer(io: ProgramIO, command: string, asJson?: boolean): void; export declare function multipleOption(value: string, previous: string[]): string[]; export { getErrorMessage, ok, redactSensitiveErrorMessage };