import type { ExtensionCommandContext, ExtensionContext } from "@earendil-works/pi-coding-agent"; import type { ArgumentDefinitions, CoreRegisteredTypedCommand, FlatArgumentDefinitions, InferArguments, SerializableArgumentValues, TypedCommandFormSymbols, TypedCommandRefinement, TypedParseResult, } from "../types.ts"; /** Handler called after typed arguments have been parsed, defaulted, and validated. */ export type TypedCommandHandler = ( args: InferArguments, ctx: ExtensionCommandContext, ) => Promise | void; type MergeArgumentDefinitions< TShared extends ArgumentDefinitions, TLocal extends ArgumentDefinitions, > = TShared & TLocal; /** Dense-form title, or a callback that derives one from the active extension session. */ export type TypedCommandFormTitle = string | ((ctx: ExtensionContext) => string); export type TypedCommandFormPolicy = "manual" | "missing" | "invalid" | "always"; export type TypedCommandInlineHelp = "auto" | "hidden"; /** Runtime context supplied when resolving opt-in inline ghost text. */ export type TypedCommandGhostTextContext = { readonly ctx: ExtensionContext; readonly commandName: string; readonly subcommand?: string; }; /** Static or synchronously resolved text rendered after an exact command invocation. */ export type TypedCommandGhostText = | string | ((context: TypedCommandGhostTextContext) => string | undefined); export type TypedCommandConfig = { description: string; args: TDefinitions; refine?: TypedCommandRefinement; formTitle?: TypedCommandFormTitle; formSymbols?: TypedCommandFormSymbols; /** Decide when command submission opens the form. Defaults to `missing`. */ formPolicy?: TypedCommandFormPolicy; /** Enable project-scoped recent values and named form presets. */ formPresets?: boolean; /** Control whether the compact live helper is rendered for this command. */ inlineHelp?: TypedCommandInlineHelp; /** Opt into dimmed, visual-only text after the exact command invocation. */ ghostText?: TypedCommandGhostText; }; /** One CLI-style subcommand with arguments and a colocated typed handler. */ export type TypedSubcommandDefinition< TShared extends ArgumentDefinitions, TLocal extends ArgumentDefinitions, > = { description: string; aliases?: readonly string[]; args: TLocal; refine?: TypedCommandRefinement>; formTitle?: TypedCommandFormTitle; formSymbols?: TypedCommandFormSymbols; formPolicy?: TypedCommandFormPolicy; formPresets?: boolean; inlineHelp?: TypedCommandInlineHelp; ghostText?: TypedCommandGhostText; run: TypedCommandHandler>; }; /** Inferred map from each subcommand name to its local argument definitions. */ export type TypedSubcommandDefinitions<_TShared extends ArgumentDefinitions = ArgumentDefinitions> = Readonly>; type TypedSubcommandsFor< TShared extends ArgumentDefinitions, TSubcommands extends TypedSubcommandDefinitions, > = { readonly [TName in keyof TSubcommands]: TypedSubcommandDefinition; }; type SubcommandParseResult< TShared extends ArgumentDefinitions, TName extends PropertyKey, TLocal extends ArgumentDefinitions, > = TypedParseResult> extends infer TResult ? TResult extends object ? TResult & { readonly subcommand: TName } : never : never; /** Parse result for either the root grammar or one selected subcommand grammar. */ export type TypedCommandParseResult< TShared extends ArgumentDefinitions, TSubcommands extends TypedSubcommandDefinitions, > = | TypedParseResult | { [TName in keyof TSubcommands]: SubcommandParseResult; }[keyof TSubcommands]; /** Serializable values for one selected subcommand. */ export type SerializableSubcommandInvocation< TShared extends ArgumentDefinitions, TSubcommands extends TypedSubcommandDefinitions, > = { [TName in keyof TSubcommands]: { readonly subcommand: TName; readonly args: SerializableArgumentValues< MergeArgumentDefinitions >; }; }[keyof TSubcommands]; export type TypedCommandDefinition< TDefinitions extends ArgumentDefinitions, TSubcommands extends TypedSubcommandDefinitions = TypedSubcommandDefinitions, > = TypedCommandConfig & { name: string; /** Root handler used when no subcommand token is present. */ run?: TypedCommandHandler; subcommands?: TypedSubcommandsFor; }; export type DefinedTypedCommand< TDefinitions extends ArgumentDefinitions, TSubcommands extends TypedSubcommandDefinitions = TypedSubcommandDefinitions, > = Readonly> & { parse(rawArgs: string): TypedCommandParseResult; serialize(values: SerializableArgumentValues): string; serializeSubcommand( invocation: SerializableSubcommandInvocation, ): string; formatUsage(): string; formatHelp(): string; }; export type InvocationTarget = | { kind: "extension"; run: TypedCommandHandler; } | { kind: "skill"; render(args: InferArguments, additionalInput?: string): string; }; /** Pi-owned command metadata layered over the framework-independent command snapshot. */ export type RegisteredTypedCommand = CoreRegisteredTypedCommand & { readonly formTitle?: TypedCommandFormTitle; readonly target?: InvocationTarget; readonly registrationId?: symbol; readonly ownerId?: symbol; readonly formSymbols: Required; readonly source?: "extension" | "skill"; readonly formPolicy?: TypedCommandFormPolicy; readonly formPresets?: boolean; readonly inlineHelp?: TypedCommandInlineHelp; readonly ghostText?: TypedCommandGhostText; readonly aliases?: readonly string[]; readonly subcommands?: Readonly>; }; export type PiTypedCommandLookup = { get(name: string): RegisteredTypedCommand | undefined; list(): readonly RegisteredTypedCommand[]; }; export type TypedCommandHandle< TDefinitions extends ArgumentDefinitions, TSubcommands extends TypedSubcommandDefinitions = TypedSubcommandDefinitions, > = { readonly definition: DefinedTypedCommand; readonly invocationName: string; parse(rawArgs: string): TypedCommandParseResult; serialize(values: SerializableArgumentValues): string; serializeSubcommand( invocation: SerializableSubcommandInvocation, ): string; formatUsage(): string; formatHelp(): string; /** Remove wrapper-owned metadata and listeners. Safe to call more than once. */ dispose(): void; };