import type { Command } from "commander"; import { type Choices } from "./optionChoices.js"; import { type Row } from "./render.js"; import { type SetupIssue } from "./status.js"; export declare const EXIT = " exit"; export declare const BACK = " back"; export declare const SEPARATOR = " separator"; /** * Pinned Ask row. A leading space keeps it out of the command namespace, same * as EXIT / BACK. Selecting it runs `ask --continue` (conversation until Esc); * a prose filter query is appended as the first message (` ask:`). */ export declare const ASK = " ask"; export declare const ASK_QUERY_PREFIX = " ask:"; /** The row that reopens the query rather than a record. */ export declare const FILTER = " filter"; /** * The three things the loop does to the outside world. Injected so the tree * walk — which level a choice lands on, what argv a leaf turns into, whether * `back` returns to the parent or leaves — can be tested without a terminal. */ export type NavigateDeps = { pick: (rows: readonly Command[], path: readonly string[]) => Promise; promptArguments: (command: Command) => Promise; run: (argv: readonly string[], capture: boolean, command: Command) => Promise; /** The argv a pinned row runs, when the choice was one. */ pinned?: (value: string) => readonly string[] | undefined; /** * Where the palette is standing, for the one thing that changes it: a * command that creates a project moves the palette into it (see * `paletteCwd.ts`). Injected so the unwind below is testable without a real * chdir; production leaves it unset and reads `process.cwd()`. */ cwd?: () => string; }; /** * A row that is not a command: an intent, pinned above the command list and run * as the argv it names. The palette's rows are otherwise derived from * commander's tree, and these are the deliberate exception — the thing a person * most wants (open a briefed coding agent) is a flag on a command, which no * derivation would ever surface as the first row. * * `argv` runs through the same child process every other row does, so a pinned * row is a shortcut, never a second implementation. */ export type PinnedRow = { value: string; label: string; hint?: string; argv: readonly string[]; }; /** How the root menu is arranged, over and above the command tree itself. */ export type PaletteLayout = { pinned?: readonly PinnedRow[]; /** Root commands the menu does not draw. They stay runnable and in --help. */ hide?: readonly string[]; /** * Root rows in display order, one group per section, with a rule drawn * between them. Anything unlisted follows in tree order. */ sections?: readonly (readonly string[])[]; /** * Root-menu type-ahead placeholder. cargo-ai uses this to say you can ask * as well as filter; cargo-cdk leaves it unset and keeps "type to filter". */ placeholder?: string; }; export type PaletteInput = { /** The program whose command tree the palette navigates. */ program: Command; /** The bin to re-run a chosen command with — normally `process.argv[1]`. */ binPath: string; /** Heading: `cargo-cdk 1.0.53 · CDK testing · 12,480 credits`. */ title: string; /** Shown above the first menu, each already carrying its own fix. */ issues: readonly SetupIssue[]; /** * Re-read after every command, so the setup line reflects what the session * has done to itself. Signing out from inside the palette used to leave the * pre-logout note on screen, which reads exactly like the logout failing. */ refreshIssues?: () => readonly SetupIssue[]; /** * Open the palette part-way down the tree, e.g. `["connection", "action"]`. * Someone who has just said what they are trying to do should land on the * handful of commands that do it, not on twenty groups. An unknown path * opens the root rather than failing: the palette is a convenience, and a * renamed command must not be able to break the entrance to the CLI. */ startPath?: readonly string[]; /** Pinned rows, hidden rows and section order for the root menu. */ layout?: PaletteLayout; /** * Re-read after every command, for the same reason as `refreshIssues`: * signing in or out changes which destinations are worth pinning, and a * menu still offering "Sign in" after a login is the same staleness. * May be async when a pin depends on a network lookup (e.g. unpaid plan). */ refreshLayout?: () => PaletteLayout | Promise; }; /** True when there is a human and a terminal to run a palette for. */ export declare function canRunPalette(): boolean; export declare function runPalette(input: PaletteInput): Promise; /** * The argv the Ask sentinel (or ` ask:`) runs. Exported for tests; * `pinnedArgv` is the only production caller. */ export declare function askArgvFromChoice(value: string): readonly string[] | undefined; /** * The typed filter becomes a question only when it is real prose. * * Exported for tests; `pick` is the only production caller. */ export declare function askQueryFromSearch(search: string, placeholder: string): string | undefined; /** * The setup line after a command has run, and whether it differs from the one * already on screen. A palette session outlives the state it described: * `login` and `logout` both change it, and everything else leaves it alone. * * Exported for tests; `runPalette` is the only production caller. */ export declare function nextIssueLine(refresh: (() => readonly SetupIssue[]) | undefined, previous: string | undefined): { line: string | undefined; changed: boolean; }; /** * The level the palette opens on, and the argv prefix that level implies. Walks * `startPath` from `program`, stopping at the last name that resolves — so a * path naming a command that no longer exists degrades to its closest existing * ancestor instead of opening nothing. * * Exported for tests; `runPalette` is the only production caller. */ export declare function resolveStart(program: Command, startPath: readonly string[] | undefined): { command: Command; path: readonly string[]; }; /** * One level of the command tree. Returns once the user leaves this level: to * the parent, out of the palette entirely, or — when a command moved the * palette — all the way back to the level the session opened on. */ export declare function navigate(command: Command, path: readonly string[], deps: NavigateDeps): Promise<"exit" | "back" | "root">; /** * Root-menu type-ahead: the Ask row stays visible for empty search and for * prose, even when commands also match. A `/` search hides it — that is how * you filter the command tree. Other rows match on label, hint, and value. * * Exported for tests; `pick` is the only production caller. */ export declare function rootAskFilter(search: string, option: { value: string; label?: string; hint?: string; }, askValue: string): boolean; /** * A choice a command offers instead of a flag it insists on. * * Commander can express "this option is required" but not "exactly one of * these", so a command like `login` — which takes `--oauth`, `--email` or * `--token` and enforces the choice in its own handler — looks to the deriver * like a command with no inputs at all. It ran bare and failed on its own error * message. A command that works this way declares the choice here instead, next * to where it is defined, and the palette asks before running it. */ export type ModeChoice = { /** What the reader picks. */ label: string; hint?: string; /** The flag it becomes. */ flag: string; /** Present when the flag needs a value after it. */ value?: { name: string; hint: string; secret?: boolean; }; }; export type DeclaredPrompt = { message: string; choices: readonly ModeChoice[]; }; /** Declares the choice a command makes instead of taking a required option. */ export declare function declarePrompt(command: Command, prompt: DeclaredPrompt): void; /** * Where the answers for an option come from, when the option wants an id. * * Keyed by the flag rather than by the command, because asks the * same question everywhere it appears — and it appears 28 times. Six entries * cover the 84 uuid options this CLI declares, which is why this is a registry * and not a per-command declaration. */ export type SourcePart = { /** The command whose rows become menu entries. */ argv: readonly string[]; /** The row field to hand back as the option's value. */ value: string; /** The row field a person reads. */ label: string; /** A second row field, shown dimmed beside the label. */ hint?: string; /** A constant shown beside every row from this part — "play", "tool". */ kind?: string; }; /** * One option's answers, gathered from one command or several. * * Several, because the thing being identified is not always the thing worth * reading. A workflow row carries a uuid, two timestamps and a `toolUuid` — * nothing a person could choose between — while the plays and tools that own * those workflows carry both a name and the `workflowUuid` it belongs to. So * `--workflow-uuid` is answered by listing plays and tools, not workflows. */ export type InputSource = readonly SourcePart[]; /** * Registers where an option's answers come from. Additive: an option with no * source keeps the free-text prompt, so nothing regresses by being unlisted. * * is fixed for now. When a source needs to depend on an earlier answer * (a column list needs its model), this becomes a function of the answers so * far — a widening that leaves these call sites untouched. */ export declare function declareSources(entries: Record): void; /** One thing a command cannot run without, and how to ask for it. */ export type RequiredInput = { /** The flag the answer rides on, or absent for a positional argument. */ flag?: string; /** What to call it at the prompt. */ name: string; hint: string; /** A closed set the answer must come from, when one can be derived. */ choices?: Choices; /** False for a mandatory boolean flag: the flag itself is the whole answer. */ takesValue: boolean; /** Where its answers come from, when the flag has a registered source. */ source?: InputSource; }; /** * Everything a command will refuse to run without — its required positional * arguments *and* the options declared with `requiredOption`, of which this CLI * has around 270. Deriving only the positionals meant picking one of those * commands ran the child straight into `error: required option '--x' not * specified`, which is a worse answer than the help wall the palette replaced. * * A mandatory option carrying a default is left out: commander is satisfied by * the default, so asking would be inventing a question the command does not have. */ export declare function requiredInputs(command: Command): RequiredInput[]; /** A `plan` writes prose to stdout, a `deploy` prompts on it — those pass through. */ export declare function capturesOutput(command: Command): boolean; /** * The options a read command can be narrowed by — its own, minus the ones that * describe the output rather than the query. `--json` in particular would * change what comes back into something this cannot render. */ export declare function filterable(command: Command): FilterOption[]; export type FilterOption = { flag: string; name: string; hint: string; /** The values it accepts, when the option says what they are. */ choices?: Choices; /** False for a boolean flag with no argument: the flag itself is the filter. */ takesValue: boolean; }; /** The filters this command still has left, given what is already applied. */ export declare function availableFilters(command: Command, argv: readonly string[]): FilterOption[]; /** Flags already on this argv, so the menu does not offer them twice. */ export declare function appliedFlags(argv: readonly string[]): string[]; export type SourceOption = { value: string; label: string; hint?: string; }; /** * Turns a source into menu rows by running the command behind it. * * Undefined on any failure — an unreachable API, a command that changed shape, * an empty workspace — so the caller falls back to the free-text prompt. A * picker that cannot be filled is a worse answer than the field it replaced. */ export declare function toSourceOptions(stdout: string, part: SourcePart): SourceOption[] | undefined; /** The seams the browse loop needs, so "the table stays open" is testable. */ export type BrowseDeps = { pick: () => Promise; show: (row: Row) => void; }; /** * Keeps the table up until the reader is done with it. Showing one row and * returning meant re-running the whole command — required options and all — * to look at a second, and a recording cannot tell the two apart: the menu a * dismissed picker falls back to re-runs the same command and lands on a * table that looks identical. */ export declare function browseRows(rows: readonly Row[], deps: BrowseDeps): Promise<"done" | "filter">; /** The command's own subcommands, minus commander's generated `help`. */ /** A command's subcommands, minus commander's own `help`. */ export declare function children(command: Command): Command[]; /** Stands in for a rule while rows are being arranged. */ export declare const SECTION_BREAK: unique symbol; export type ArrangedRow = Command | typeof SECTION_BREAK; /** * The root menu's rows, in the order a person reads them: the sections a * caller declared, each followed by a rule, then everything it did not mention * in tree order. Hidden rows are dropped — they stay runnable and in `--help`, * they are just not worth a line in a menu of twenty. * * Commander has no opinion about which of its commands matter, and ordering by * registration accident is what put `version` above the whole product. * * Exported for tests; `pick` is the only production caller. */ export declare function arrangeRows(rows: readonly Command[], layout: PaletteLayout | undefined): ArrangedRow[]; /** Descriptions in this CLI run to paragraphs; a menu row gets the first line. */ /** * A row's hint: the first line of its description, clipped to what is left of * the terminal after the label. A hint that wraps pushes every row below it * down and re-flows the list as the cursor moves, which is why this is measured * against the real width rather than a fixed 72. * * Exported for tests; `pick` is the only production caller. */ export declare function firstLine(text: string | undefined, budget?: number): string; //# sourceMappingURL=palette.d.ts.map