import type { RootHelp, RootEntry, BranchHelp, LeafHelp, InputParam, SubTier } from './help.js'; import { CrtrError } from './errors.js'; /** Runtime context passed to a leaf's run function. Includes metadata about * which parameters were explicitly provided vs. defaulted. Used by configured * CLIs to distinguish intentionally-empty stdin from absent stdin. */ export interface LeafRunContext { /** Set of declared parameter names that were explicitly provided by the * caller. For optional parameters, presence in this set means the value was * supplied, even if it is falsy (empty string, 0, false, etc.). Parameters * absent from this set were either defaulted or not provided. For stdin * specifically, presence means it was piped/redirected (non-TTY), supplied * as a positional argument, or explicitly passed; absence means TTY with no * pipe (truly absent). */ readonly providedParams: ReadonlySet; } /** Opt-in flag that surfaces a node as an editor slash command (a pi prompt * template / Claude Code command). When set, the bootstrap auto-writes a * markdown template named `.md` to the host's command dirs on each crtr * run, so `/name` becomes available. The body is thin — it points the agent at * the live `crtr` workflow so the CLI stays the source of truth. */ export interface SlashSpec { /** Command name → `/` and the template filename. */ name: string; /** Frontmatter description shown in the autocomplete dropdown. */ description: string; /** Optional autocomplete hint, e.g. `` or `[topic]`. */ argumentHint?: string; /** Markdown body (no frontmatter). Bootstrap wraps it with frontmatter + a * version marker. Use `$ARGUMENTS` for the invocation's free text. */ body: string; } export interface LeafDef { kind: 'leaf'; name: string; /** Short description for this node's row in its parent's -h. */ description?: string; /** Selection rubric for the parent's listing — plainly states when to reach * for this command (expansive with examples for judgment-heavy ones, concise * for single-purpose). Rendered verbatim, no prefix. */ whenToUse?: string; /** Visibility tier in ancestor listings (see SubTier). Default 'normal'; * 'hidden' keeps an internal leaf out of every listing. */ tier?: SubTier; help: LeafHelp; /** Opt into editor slash-command exposure (see SlashSpec). */ slash?: SlashSpec; run: (input: Record, context?: LeafRunContext) => Promise | void>; /** Optional bespoke renderer: turn the result into instruction-shaped * XML+markdown the agent acts on. Omit to fall back to the schema-driven * generic renderer. Ignored when `--json` is set. */ render?: (result: Record) => string; } export interface BranchDef { kind: 'branch'; name: string; /** Short description for this node's row in its parent's -h. * Unused on a top-level subtree (its root representation is its rootEntry). */ description?: string; /** Selection rubric for the parent's listing — plainly states when to reach * for this command (expansive with examples for judgment-heavy ones, concise * for single-purpose). Rendered verbatim, no prefix. */ whenToUse?: string; /** Visibility tier in ancestor listings (see SubTier). Default 'normal'. */ tier?: SubTier; help: BranchHelp; /** How this subtree represents itself one level up. Present on top-level * subtrees (assembled into root -h by defineRoot); omitted on nested * branches, whose parent representation is the branch's own children list. */ rootEntry?: RootEntry; /** Opt into editor slash-command exposure (see SlashSpec). */ slash?: SlashSpec; /** Opt this branch out of the tree model entirely: every token after this * branch's name is forwarded VERBATIM (raw argv, not the `--json`-filtered * tokens) to an external binary via spawn, with stdio inherited and the * child's exit code propagated. A deliberate, documented exception for * wrapping an external CLI whose own schema crtr cannot and must not * duplicate (the official marketplace's `capture` plugin mounts `crtr * capture` this way) — not a general escape hatch. A * passthrough branch should declare no children. */ passthrough?: { bin: string; installHint: string; }; children: (LeafDef | BranchDef)[]; } export interface RootDef { kind: 'root'; help: RootHelp; subtrees: BranchDef[]; } export declare function defineLeaf(opts: { name: string; description?: string; whenToUse?: string; tier?: SubTier; help: LeafHelp; slash?: SlashSpec; run: (input: Record, context?: LeafRunContext) => Promise | void>; render?: (result: Record) => string; }): LeafDef; export declare function defineBranch(opts: { name: string; description?: string; whenToUse?: string; tier?: SubTier; help: BranchHelp; rootEntry?: RootEntry; slash?: SlashSpec; passthrough?: { bin: string; installHint: string; }; children: (LeafDef | BranchDef)[]; }): BranchDef; /** Walk the whole tree and collect every node's SlashSpec (depth-first). Used * by the bootstrap to discover which commands opted into slash exposure. */ export declare function collectSlashSpecs(root: RootDef): SlashSpec[]; /** Assemble root -h from the subtrees themselves. Root owns only the tagline * and globals; every subtree's concept line, selection rubric, and dynamic * block come from its own RootEntry. A subtree without a rootEntry does not * appear in root -h — declaring the parent-level representation is how a * subtree opts into being listed. */ export declare function defineRoot(opts: { tagline: string; globals: { name: string; desc: string; }[]; subtrees: BranchDef[]; }): RootDef; type AnyNode = RootDef | BranchDef | LeafDef; /** Walk argv tokens to the deepest matched node. * Returns { node, path, remaining } where path is the sequence of matched node * names from root (excluding root itself) and remaining are unconsumed tokens. * -h / --help tokens are NOT consumed here — the caller checks for them. */ export declare function walk(root: RootDef, tokens: string[]): { node: AnyNode; path: string[]; remaining: string[]; }; /** Build a structured unknown-path error. Names valid children of the deepest * matched node and names the entry command per the spec. The entry command is * the full path to the matched node (not just its local name), so the recovery * hint is a command that actually exists. No fuzzy matching. */ export declare function unknownPathError(node: AnyNode, path: string[], bad: string): CrtrError; /** Options for parseArgv. */ export interface ParseArgvOptions { /** Optional collector for tracking which parameters were explicitly provided. * Called once with a ReadonlySet of parameter names that were supplied by * the caller (distinct from defaulted or missing values). */ onProvidedParams?: (provided: ReadonlySet) => void; /** The walked command path (e.g. `['push','final']`), supplied by the * dispatcher. Used only to name the exact leaf in a schema-class error's * `Next:` line, which mandates reading that leaf's `-h`. */ leafPath?: readonly string[]; } /** Parse remaining argv tokens against the leaf's InputParam schema. * Returns a plain object whose keys are camelCase parameter names. * Optionally tracks which parameters were explicitly provided via a callback. */ export declare function parseArgv(params: InputParam[], tokens: string[], options?: ParseArgvOptions): Promise>; /** Optional seams for `runCli`. */ export interface RunCliOptions { /** The ONE unknown-first-token retry seam (amended configured-CLI spec * §5.1, §8). Called EXACTLY once, and ONLY when an unknown FIRST token * misses at root (walk stopped at root, `path` empty, on a real non-help * token) — the sole site absent-store configured-CLI hydration may fire. A * deeper unknown token under a known command (`path` non-empty) never calls * it. Returns a freshly rebuilt root when hydration produced new commands to * re-walk the original argv against, else undefined to surface the plain * `unknown_path` error. crtr's core fast path passes no options, so a * recognized core first token is dispatched with zero configured-CLI I/O. */ onUnknownFirstTokenMiss?: () => Promise; } export declare function runCli(root: RootDef, argv: string[], options?: RunCliOptions): Promise; export {};