11import type { StandardSchemaV1 } from '@standard-schema/spec' ;
22import type { Tool } from 'ai' ;
3- import type { PadroneRuntime } from '../core/runtime.ts' ;
3+ import type { PadroneProgressIndicator , PadroneRuntime } from '../core/runtime.ts' ;
4+ import type { PadroneLogger } from '../extension/logger.ts' ;
5+ import type { PadroneTracer } from '../extension/tracing.ts' ;
46import type { PadroneMcpPreferences } from '../feature/mcp.ts' ;
57import type { PadroneServePreferences } from '../feature/serve.ts' ;
68import type { WrapConfig , WrapResult } from '../feature/wrap.ts' ;
@@ -385,6 +387,33 @@ export type PadroneBuilderMethods<
385387 TContext ,
386388 TContextProvided
387389 > ;
390+ // Overload for defineCommand.requires() branded callbacks — validates context requirements
391+ < TNameNested extends string , TAliases extends string [ ] = [ ] , TBuilder extends CommandTypesBase = CommandTypesBase , TReq = unknown > (
392+ name : TNameNested | readonly [ TNameNested , ...TAliases ] ,
393+ builderFn : ( ( builder : any ) => TBuilder ) & { '~contextRequires' : ( ctx : TReq ) => void } ,
394+ ) : TContext & TContextProvided extends TReq
395+ ? BuilderOrProgram <
396+ TReturn ,
397+ TProgramName ,
398+ TName ,
399+ TParentName ,
400+ TArgs ,
401+ TRes ,
402+ TCommands extends [ ]
403+ ? [ WithAliases < TBuilder [ '~types' ] [ 'command' ] , TAliases > ]
404+ : AnyPadroneCommand [ ] extends TCommands
405+ ? [ WithAliases < TBuilder [ '~types' ] [ 'command' ] , TAliases > ]
406+ : ReplaceOrAppendCommand <
407+ TCommands ,
408+ TNameNested ,
409+ WithAliases < TBuilder [ '~types' ] [ 'command' ] , ResolvedAliases < TCommands , TNameNested , TAliases > >
410+ > ,
411+ TParentArgs ,
412+ TAsync ,
413+ TContext ,
414+ TContextProvided
415+ >
416+ : DefineCommandRequiresError ;
388417 // Fallback overload: accepts DefineCommand-typed callbacks where the builder type is not structurally compatible
389418 // (e.g., DefineCommand with unknown context used in a parent with specific context)
390419 < TNameNested extends string , TAliases extends string [ ] = [ ] , TBuilder extends CommandTypesBase = CommandTypesBase > (
@@ -723,6 +752,30 @@ export type AnyPadroneProgram = PadroneProgram<string, string, string, any, any,
723752 */
724753export type PadroneExtension < TIn extends CommandTypesBase = CommandTypesBase , TOut extends CommandTypesBase = TIn > = ( builder : TIn ) => TOut ;
725754
755+ /**
756+ * Default context type for commands defined with `defineCommand()`.
757+ * Includes optional context properties provided by common extensions (logger, tracing, progress).
758+ *
759+ * Override globally via module augmentation to add your application's context:
760+ * ```ts
761+ * declare module 'padrone' {
762+ * interface DefineCommandContext {
763+ * db: Database;
764+ * }
765+ * }
766+ * ```
767+ */
768+ export interface DefineCommandContext {
769+ logger ?: PadroneLogger ;
770+ tracing ?: PadroneTracer ;
771+ progress ?: PadroneProgressIndicator ;
772+ }
773+
774+ /** Error brand returned by `.command()` when a `defineCommand.requires()` context requirement is not satisfied. */
775+ export type DefineCommandRequiresError = {
776+ readonly '~error' : 'Required context not satisfied. Ensure required interceptors are registered on the program.' ;
777+ } ;
778+
726779/**
727780 * Type for a command builder callback used with `.command()`.
728781 * Use this when defining commands in separate files where full return type inference isn't needed.
@@ -741,7 +794,27 @@ export type PadroneExtension<TIn extends CommandTypesBase = CommandTypesBase, TO
741794 * ```
742795 */
743796export type DefineCommand < TContext = unknown , TParentArgs extends PadroneSchema = PadroneSchema > = (
744- builder : PadroneBuilder < string , string , string , PadroneSchema < void > , void , [ ] , TParentArgs , false , TContext > ,
797+ builder : PadroneBuilder < string , string , string , PadroneSchema < void > , void , [ ] , TParentArgs , false , TContext , DefineCommandContext > ,
745798) => CommandTypesBase ;
746799
800+ /**
801+ * Builder returned by `defineCommand()` (no-arg form).
802+ * Call `.requires<T>()` to declare context dependencies, then `.command()` to provide the builder callback.
803+ *
804+ * @example
805+ * ```ts
806+ * const adminCommand = defineCommand()
807+ * .requires<{ adminDb: AdminDB }>()
808+ * .define((c) => c.action((_args, ctx) => ctx.context.adminDb.query(...)));
809+ * ```
810+ */
811+ export type DefineCommandBuilder < TContextProvided = DefineCommandContext , TBrand = unknown > = {
812+ /** Declare context types this command requires. Purely type-level — no runtime effect. */
813+ requires : < TRequires > ( ) => DefineCommandBuilder < DefineCommandContext & TRequires , { '~contextRequires' : ( ctx : TRequires ) => void } > ;
814+ /** Provide the command builder callback. */
815+ define : < TContext = unknown , TOut extends CommandTypesBase = CommandTypesBase > (
816+ fn : ( builder : PadroneBuilder < string , string , string , PadroneSchema < void > , void , [ ] , any , false , TContext , TContextProvided > ) => TOut ,
817+ ) => typeof fn & TBrand ;
818+ } ;
819+
747820type DefaultArgs = Record < string , unknown > | void ;
0 commit comments