@reliverse/rempts-core 1.6.1 → 2.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/README.md +398 -102
  2. package/dist/cli.d.ts +32 -0
  3. package/dist/cli.js +731 -0
  4. package/dist/config-loader.d.ts +42 -0
  5. package/dist/config-loader.js +20 -0
  6. package/dist/config.d.ts +99 -0
  7. package/dist/config.js +188 -0
  8. package/dist/file-loader.d.ts +43 -0
  9. package/dist/file-loader.js +199 -0
  10. package/dist/global-flags.d.ts +36 -0
  11. package/dist/global-flags.js +36 -0
  12. package/dist/mod.d.ts +13 -0
  13. package/dist/mod.js +19 -0
  14. package/dist/parser.d.ts +6 -0
  15. package/dist/parser.js +137 -0
  16. package/dist/plugin/context.d.ts +13 -0
  17. package/dist/plugin/context.js +53 -0
  18. package/dist/plugin/create.d.ts +92 -0
  19. package/dist/plugin/create.js +61 -0
  20. package/dist/plugin/loader.d.ts +12 -0
  21. package/dist/plugin/loader.js +65 -0
  22. package/dist/plugin/manager.d.ts +53 -0
  23. package/dist/plugin/manager.js +135 -0
  24. package/dist/plugin/mod.d.ts +10 -0
  25. package/dist/plugin/mod.js +27 -0
  26. package/dist/plugin/store.d.ts +45 -0
  27. package/dist/plugin/store.js +60 -0
  28. package/dist/plugin/testing.d.ts +38 -0
  29. package/dist/plugin/testing.js +175 -0
  30. package/dist/plugin/types.d.ts +146 -0
  31. package/dist/tui/registry.d.ts +8 -0
  32. package/dist/tui/registry.js +10 -0
  33. package/dist/tui/types.d.ts +58 -0
  34. package/dist/tui/types.js +10 -0
  35. package/dist/types.d.ts +178 -0
  36. package/dist/types.js +25 -0
  37. package/dist/utils/logger.d.ts +10 -0
  38. package/dist/utils/logger.js +27 -0
  39. package/dist/utils/merge.d.ts +13 -0
  40. package/dist/utils/merge.js +25 -0
  41. package/dist/utils/mod.d.ts +6 -0
  42. package/dist/utils/mod.js +2 -0
  43. package/dist/utils/type-helpers.d.ts +41 -0
  44. package/dist/utils/type-helpers.js +0 -0
  45. package/dist/validation.d.ts +30 -0
  46. package/dist/validation.js +121 -0
  47. package/package.json +47 -44
  48. package/src/cli.ts +1049 -0
  49. package/src/config-loader.ts +71 -0
  50. package/src/config.ts +270 -0
  51. package/src/file-loader.ts +346 -0
  52. package/src/global-flags.ts +50 -0
  53. package/src/mod.ts +74 -0
  54. package/src/parser.ts +212 -0
  55. package/src/plugin/context.ts +88 -0
  56. package/src/plugin/create.ts +174 -0
  57. package/src/plugin/loader.ts +111 -0
  58. package/src/plugin/manager.ts +244 -0
  59. package/src/plugin/mod.ts +51 -0
  60. package/src/plugin/store.ts +124 -0
  61. package/src/plugin/testing.ts +236 -0
  62. package/src/plugin/types.ts +206 -0
  63. package/src/tui/registry.ts +22 -0
  64. package/src/tui/types.ts +79 -0
  65. package/src/types.ts +285 -0
  66. package/src/utils/logger.ts +43 -0
  67. package/src/utils/merge.ts +54 -0
  68. package/src/utils/mod.ts +7 -0
  69. package/src/utils/type-helpers.ts +151 -0
  70. package/src/validation.ts +177 -0
  71. package/LICENSE +0 -21
  72. package/bin/core-impl/anykey/anykey-mod.d.ts +0 -12
  73. package/bin/core-impl/anykey/anykey-mod.js +0 -125
  74. package/bin/core-impl/date/date.d.ts +0 -2
  75. package/bin/core-impl/date/date.js +0 -236
  76. package/bin/core-impl/editor/editor-mod.d.ts +0 -25
  77. package/bin/core-impl/editor/editor-mod.js +0 -896
  78. package/bin/core-impl/figures/figures-mod.d.ts +0 -233
  79. package/bin/core-impl/figures/figures-mod.js +0 -286
  80. package/bin/core-impl/figures/figures.test.d.ts +0 -1
  81. package/bin/core-impl/figures/figures.test.js +0 -474
  82. package/bin/core-impl/input/confirm-prompt.d.ts +0 -5
  83. package/bin/core-impl/input/confirm-prompt.js +0 -173
  84. package/bin/core-impl/input/input-prompt.d.ts +0 -16
  85. package/bin/core-impl/input/input-prompt.js +0 -370
  86. package/bin/core-impl/launcher/_parser.d.ts +0 -2
  87. package/bin/core-impl/launcher/_parser.js +0 -122
  88. package/bin/core-impl/launcher/_utils.d.ts +0 -8
  89. package/bin/core-impl/launcher/_utils.js +0 -29
  90. package/bin/core-impl/launcher/args.d.ts +0 -3
  91. package/bin/core-impl/launcher/args.js +0 -89
  92. package/bin/core-impl/launcher/command.d.ts +0 -8
  93. package/bin/core-impl/launcher/command.js +0 -68
  94. package/bin/core-impl/launcher/launcher-mod.d.ts +0 -8
  95. package/bin/core-impl/launcher/launcher-mod.js +0 -34
  96. package/bin/core-impl/launcher/usage.d.ts +0 -3
  97. package/bin/core-impl/launcher/usage.js +0 -104
  98. package/bin/core-impl/msg-fmt/colors.d.ts +0 -30
  99. package/bin/core-impl/msg-fmt/colors.js +0 -42
  100. package/bin/core-impl/msg-fmt/logger.d.ts +0 -17
  101. package/bin/core-impl/msg-fmt/logger.js +0 -106
  102. package/bin/core-impl/msg-fmt/mapping.d.ts +0 -3
  103. package/bin/core-impl/msg-fmt/mapping.js +0 -49
  104. package/bin/core-impl/msg-fmt/messages.d.ts +0 -35
  105. package/bin/core-impl/msg-fmt/messages.js +0 -314
  106. package/bin/core-impl/msg-fmt/terminal.d.ts +0 -15
  107. package/bin/core-impl/msg-fmt/terminal.js +0 -59
  108. package/bin/core-impl/msg-fmt/variants.d.ts +0 -11
  109. package/bin/core-impl/msg-fmt/variants.js +0 -52
  110. package/bin/core-impl/next-steps/next-steps.d.ts +0 -14
  111. package/bin/core-impl/next-steps/next-steps.js +0 -24
  112. package/bin/core-impl/number/number-mod.d.ts +0 -28
  113. package/bin/core-impl/number/number-mod.js +0 -197
  114. package/bin/core-impl/results/results.d.ts +0 -7
  115. package/bin/core-impl/results/results.js +0 -27
  116. package/bin/core-impl/select/multiselect-prompt.d.ts +0 -2
  117. package/bin/core-impl/select/multiselect-prompt.js +0 -341
  118. package/bin/core-impl/select/nummultiselect-prompt.d.ts +0 -6
  119. package/bin/core-impl/select/nummultiselect-prompt.js +0 -105
  120. package/bin/core-impl/select/numselect-prompt.d.ts +0 -7
  121. package/bin/core-impl/select/numselect-prompt.js +0 -115
  122. package/bin/core-impl/select/select-prompt.d.ts +0 -33
  123. package/bin/core-impl/select/select-prompt.js +0 -302
  124. package/bin/core-impl/select/toggle-prompt.d.ts +0 -5
  125. package/bin/core-impl/select/toggle-prompt.js +0 -208
  126. package/bin/core-impl/st-end/end.d.ts +0 -2
  127. package/bin/core-impl/st-end/end.js +0 -42
  128. package/bin/core-impl/st-end/start.d.ts +0 -17
  129. package/bin/core-impl/st-end/start.js +0 -66
  130. package/bin/core-impl/task/progress.d.ts +0 -2
  131. package/bin/core-impl/task/progress.js +0 -57
  132. package/bin/core-impl/task/spinner.d.ts +0 -15
  133. package/bin/core-impl/task/spinner.js +0 -110
  134. package/bin/core-impl/utils/colorize.d.ts +0 -2
  135. package/bin/core-impl/utils/colorize.js +0 -134
  136. package/bin/core-impl/utils/errors.d.ts +0 -1
  137. package/bin/core-impl/utils/errors.js +0 -15
  138. package/bin/core-impl/utils/prevent.d.ts +0 -10
  139. package/bin/core-impl/utils/prevent.js +0 -69
  140. package/bin/core-impl/utils/prompt-end.d.ts +0 -8
  141. package/bin/core-impl/utils/prompt-end.js +0 -33
  142. package/bin/core-impl/utils/stream-text.d.ts +0 -18
  143. package/bin/core-impl/utils/stream-text.js +0 -136
  144. package/bin/core-impl/utils/system.d.ts +0 -6
  145. package/bin/core-impl/utils/system.js +0 -7
  146. package/bin/core-impl/utils/validate.d.ts +0 -22
  147. package/bin/core-impl/utils/validate.js +0 -17
  148. package/bin/core-impl/visual/animate/animate.d.ts +0 -14
  149. package/bin/core-impl/visual/animate/animate.js +0 -64
  150. package/bin/core-impl/visual/ascii-art/ascii-art.d.ts +0 -6
  151. package/bin/core-impl/visual/ascii-art/ascii-art.js +0 -12
  152. package/bin/core-types.d.ts +0 -434
  153. package/bin/main.d.ts +0 -41
  154. package/bin/main.js +0 -96
  155. /package/{bin/core-types.js → dist/plugin/types.js} +0 -0
@@ -0,0 +1,206 @@
1
+ /**
2
+ * Core plugin types and interfaces for Rempts
3
+ */
4
+
5
+ import type { Command, RemptsConfig, ResolvedConfig } from "../types";
6
+ import type { Logger } from "../utils/logger";
7
+ import type { PluginStore } from "./store";
8
+
9
+ // Command definition type for plugins
10
+ export type CommandDefinition = Command<any>;
11
+
12
+ /**
13
+ * Functional plugin hooks with store type
14
+ */
15
+ export interface PluginHooks<TStore = {}> {
16
+ /** Plugin store - Zustand store instance */
17
+ store?: PluginStore<TStore>;
18
+
19
+ /**
20
+ * Setup hook - Called during CLI initialization
21
+ * Can modify configuration and register commands
22
+ */
23
+ setup?: (context: PluginContext) => void | Promise<void>;
24
+
25
+ /**
26
+ * Config resolved hook - Called after all configuration is finalized
27
+ * Config is now immutable
28
+ */
29
+ configResolved?: (config: ResolvedConfig) => void | Promise<void>;
30
+
31
+ /**
32
+ * Before command hook - Called before command execution
33
+ * Can inject context and validate
34
+ * Uses generic constraints to preserve store type information
35
+ */
36
+ beforeCommand?: (context: CommandContext<any>) => void | Promise<void>;
37
+
38
+ /**
39
+ * After command hook - Called after command execution
40
+ * Receives result or error from command
41
+ * Uses generic constraints to preserve store type information
42
+ */
43
+ afterCommand?: (context: CommandContext<any> & CommandResult) => void | Promise<void>;
44
+ }
45
+
46
+ /**
47
+ * Core plugin function that returns hooks
48
+ */
49
+ export type Plugin<TStore = {}> = () => PluginHooks<TStore>;
50
+
51
+ /**
52
+ * Extract store type from plugin hooks
53
+ */
54
+ export type StoreOf<P> = P extends PluginHooks<infer S> ? S : {};
55
+
56
+ /**
57
+ * Merge multiple plugin stores into one type
58
+ */
59
+ export type MergeStores<Plugins extends readonly PluginHooks[]> = Plugins extends readonly []
60
+ ? {}
61
+ : Plugins extends readonly [infer First, ...infer Rest]
62
+ ? First extends PluginHooks
63
+ ? Rest extends readonly PluginHooks[]
64
+ ? StoreOf<First> & MergeStores<Rest>
65
+ : StoreOf<First>
66
+ : {}
67
+ : {};
68
+
69
+ /**
70
+ * Merge stores from plugin functions
71
+ */
72
+ export type MergePluginStores<Plugins extends readonly Plugin[]> = Plugins extends readonly []
73
+ ? {}
74
+ : Plugins extends readonly [infer First, ...infer Rest]
75
+ ? First extends Plugin<infer S>
76
+ ? Rest extends readonly Plugin[]
77
+ ? S & MergePluginStores<Rest>
78
+ : S
79
+ : {}
80
+ : {};
81
+
82
+ /**
83
+ * Plugin factory function type - returns a function that creates hooks
84
+ */
85
+ export type PluginFactory<TOptions = any, TStore = {}> = (options?: TOptions) => Plugin<TStore>;
86
+
87
+ /**
88
+ * Command execution result
89
+ */
90
+ export interface CommandResult {
91
+ /** Command return value */
92
+ result?: any;
93
+
94
+ /** Error if command failed */
95
+ error?: Error;
96
+
97
+ /** Exit code */
98
+ exitCode?: number;
99
+ }
100
+
101
+ /**
102
+ * Plugin configuration types
103
+ */
104
+ export type PluginConfig =
105
+ | string // Path to plugin
106
+ | Plugin // Plugin function
107
+ | PluginFactory // Plugin factory function
108
+ | [PluginFactory, any]; // Plugin with options
109
+
110
+ /**
111
+ * Plugin context available during setup
112
+ */
113
+ export interface PluginContext {
114
+ /** Current configuration (being built) */
115
+ readonly config: Partial<RemptsConfig>;
116
+
117
+ /** Update configuration */
118
+ updateConfig(partial: Partial<RemptsConfig>): void;
119
+
120
+ /** Register a new command */
121
+ registerCommand(command: CommandDefinition): void;
122
+
123
+ /** Add global middleware */
124
+ use(middleware: Middleware): void;
125
+
126
+ /** Shared storage between plugins */
127
+ readonly store: PluginStore<any>;
128
+
129
+ /** Plugin logger */
130
+ readonly logger: Logger;
131
+
132
+ /** System paths */
133
+ readonly paths: PathInfo;
134
+ }
135
+
136
+ /**
137
+ * Command execution context
138
+ */
139
+ export interface CommandContext<TStore = {}> {
140
+ /** Command name being executed */
141
+ readonly command: string;
142
+
143
+ /** The Command object being executed */
144
+ readonly commandDef: Command<any, TStore>;
145
+
146
+ /** Positional arguments */
147
+ readonly args: string[];
148
+
149
+ /** Parsed flags/options */
150
+ readonly flags: Record<string, any>;
151
+
152
+ /** Environment information */
153
+ readonly env: EnvironmentInfo;
154
+
155
+ /** Type-safe context store */
156
+ readonly store?: PluginStore<TStore>;
157
+
158
+ /** Type-safe store value access */
159
+ getStoreValue<K extends keyof TStore>(key: K): TStore[K];
160
+ getStoreValue(key: string | number | symbol): any;
161
+
162
+ /** Type-safe store value update */
163
+ setStoreValue<K extends keyof TStore>(key: K, value: TStore[K]): void;
164
+ setStoreValue(key: string | number | symbol, value: any): void;
165
+
166
+ /** Check if a store property exists */
167
+ hasStoreValue<K extends keyof TStore>(key: K): boolean;
168
+ hasStoreValue(key: string | number | symbol): boolean;
169
+ }
170
+
171
+ /**
172
+ * System path information
173
+ */
174
+ export interface PathInfo {
175
+ /** Current working directory */
176
+ cwd: string;
177
+
178
+ /** User home directory */
179
+ home: string;
180
+
181
+ /** Config directory path */
182
+ config: string;
183
+ }
184
+
185
+ /**
186
+ * Environment information
187
+ */
188
+ export interface EnvironmentInfo {
189
+ /** Running in CI environment */
190
+ isCI: boolean;
191
+
192
+ /** Additional properties that plugins can add */
193
+ [key: string]: any;
194
+ }
195
+
196
+ /**
197
+ * Middleware function type
198
+ */
199
+ export type Middleware = (context: CommandContext, next: () => Promise<any>) => Promise<any>;
200
+
201
+ /**
202
+ * Plugin extension interfaces
203
+ *
204
+ * Note: Plugins should extend these interfaces directly in their own code
205
+ * rather than using module augmentation, as that creates circular dependencies.
206
+ */
@@ -0,0 +1,22 @@
1
+ /**
2
+ * TUI Registry - manages the global TUI renderer
3
+ * This module provides a simple registry for TUI renderers
4
+ */
5
+
6
+ import type { RenderArgs } from "../types";
7
+
8
+ let renderer: ((args: RenderArgs<any, any>) => Promise<unknown> | unknown) | null = null;
9
+
10
+ export function registerTuiRenderer<TFlags = Record<string, unknown>, TStore = {}>(
11
+ fn: (args: RenderArgs<TFlags, TStore>) => Promise<unknown> | unknown
12
+ ) {
13
+ renderer = fn as (args: RenderArgs<any, any>) => Promise<unknown> | unknown;
14
+ }
15
+
16
+ export function getTuiRenderer<TFlags = Record<string, unknown>, TStore = {}>() {
17
+ return renderer as ((args: RenderArgs<TFlags, TStore>) => Promise<unknown> | unknown) | null;
18
+ }
19
+
20
+ export function clearTuiRenderer() {
21
+ renderer = null;
22
+ }
@@ -0,0 +1,79 @@
1
+ import type { RenderResult } from "../types";
2
+
3
+ /**
4
+ * Options passed to the TUI renderer when rendering a component
5
+ */
6
+ export interface TuiRendererOptions {
7
+ /**
8
+ * Exit on Ctrl+C (default: true)
9
+ */
10
+ exitOnCtrlC?: boolean;
11
+
12
+ /**
13
+ * Target frames per second (default: 30)
14
+ */
15
+ targetFps?: number;
16
+
17
+ /**
18
+ * Enable mouse movement events (default: true)
19
+ */
20
+ enableMouseMovement?: boolean;
21
+
22
+ /**
23
+ * Additional renderer-specific options
24
+ */
25
+ [key: string]: unknown;
26
+ }
27
+
28
+ /**
29
+ * Context passed when rendering TUI components
30
+ */
31
+ export interface TuiRenderContext {
32
+ /**
33
+ * Renderer-specific options
34
+ */
35
+ rendererOptions?: TuiRendererOptions;
36
+ }
37
+
38
+ /**
39
+ * TUI Renderer interface
40
+ * Implementations should handle rendering React components to the terminal
41
+ */
42
+ export interface TuiRenderer {
43
+ /**
44
+ * Render a component result to the terminal
45
+ * @param component The component or render result to render
46
+ * @param context Rendering context and options
47
+ * @returns Promise that resolves when rendering completes
48
+ */
49
+ render(component: RenderResult, context: TuiRenderContext): Promise<unknown>;
50
+ }
51
+
52
+ /**
53
+ * Global TUI renderer instance
54
+ * Set by calling registerTuiRenderer()
55
+ */
56
+ let globalRenderer: TuiRenderer | null = null;
57
+
58
+ /**
59
+ * Register a TUI renderer globally
60
+ * @param renderer The renderer implementation
61
+ */
62
+ export function registerTuiRenderer(renderer: TuiRenderer): void {
63
+ globalRenderer = renderer;
64
+ }
65
+
66
+ /**
67
+ * Get the currently registered TUI renderer
68
+ * @returns The registered renderer, or null if none registered
69
+ */
70
+ export function getTuiRenderer(): TuiRenderer | null {
71
+ return globalRenderer;
72
+ }
73
+
74
+ /**
75
+ * Clear the registered TUI renderer (mainly for testing)
76
+ */
77
+ export function clearTuiRenderer(): void {
78
+ globalRenderer = null;
79
+ }
package/src/types.ts ADDED
@@ -0,0 +1,285 @@
1
+ import type { StandardSchemaV1 } from "@standard-schema/spec";
2
+ import type { GLOBAL_FLAGS } from "./global-flags";
3
+
4
+ // Re-export StandardSchemaV1 for use in other modules
5
+ export type { StandardSchemaV1 } from "@standard-schema/spec";
6
+
7
+ export type RenderResult = unknown;
8
+
9
+ export interface TuiRenderOptions {
10
+ exitOnCtrlC?: boolean;
11
+ targetFps?: number;
12
+ enableMouseMovement?: boolean;
13
+ [key: string]: unknown;
14
+ }
15
+
16
+ export interface RenderArgs<TFlags = Record<string, unknown>, TStore = {}>
17
+ extends HandlerArgs<TFlags, TStore> {
18
+ command: Command<any, TStore>;
19
+ rendererOptions?: TuiRenderOptions;
20
+ }
21
+
22
+ export type RenderFunction<TFlags = Record<string, unknown>, TStore = {}> = (
23
+ args: RenderArgs<TFlags, TStore>
24
+ ) => RenderResult;
25
+
26
+ // Core Rempts types
27
+ /**
28
+ * CLI instance with plugin type information
29
+ */
30
+ export interface CLI<TStore = {}> {
31
+ /**
32
+ * Initialize the CLI (load config, etc)
33
+ */
34
+ init(): Promise<void>;
35
+
36
+ /**
37
+ * Run the CLI with given arguments
38
+ */
39
+ run(argv?: string[]): Promise<void>;
40
+
41
+ /**
42
+ * Execute a command programmatically
43
+ */
44
+ execute(commandName: string, args?: string[]): Promise<void>;
45
+ execute<T extends keyof RegisteredCommands>(
46
+ commandName: T,
47
+ options: CommandOptions<T>
48
+ ): Promise<void>;
49
+ execute<T extends keyof RegisteredCommands>(
50
+ commandName: T,
51
+ args: string[],
52
+ options: CommandOptions<T>
53
+ ): Promise<void>;
54
+
55
+ /**
56
+ * Add a global before hook that runs before command execution
57
+ * This provides a simple API for setup/initialization tasks
58
+ */
59
+ before(hook: BeforeHook<TStore>): void;
60
+
61
+ /**
62
+ * Add a global after hook that runs after command execution
63
+ */
64
+ after(hook: AfterHook<TStore>): void;
65
+ }
66
+
67
+ // generic Command type that carries options type information
68
+ interface BaseCommand<
69
+ TOptions extends Options = Options,
70
+ TStore = {},
71
+ TName extends string = string,
72
+ > {
73
+ description: string;
74
+ options?: TOptions;
75
+ alias?: string | string[];
76
+ handler?: Handler<InferOptions<TOptions>, TStore, TName>;
77
+ render?: RenderFunction<InferOptions<TOptions>, TStore>;
78
+ }
79
+
80
+ export type Command<
81
+ TOptions extends Options = Options,
82
+ TStore = {},
83
+ TName extends string = string,
84
+ > =
85
+ | (BaseCommand<TOptions, TStore, TName> & {
86
+ handler: Handler<InferOptions<TOptions>, TStore, TName>;
87
+ })
88
+ | (BaseCommand<TOptions, TStore, TName> & {
89
+ render: RenderFunction<InferOptions<TOptions>, TStore>;
90
+ })
91
+ | (BaseCommand<TOptions, TStore, TName> & {
92
+ handler: Handler<InferOptions<TOptions>, TStore, TName>;
93
+ render: RenderFunction<InferOptions<TOptions>, TStore>;
94
+ })
95
+ | (BaseCommand<TOptions, TStore, TName> & {
96
+ // Synthetic parent command - no handler/render, subcommands discovered from file structure
97
+ handler?: never;
98
+ render?: never;
99
+ });
100
+
101
+ // Type helper to extract output types from StandardSchemaV1
102
+ type InferSchema<T> = T extends StandardSchemaV1<any, infer Out> ? Out : never;
103
+
104
+ export type InferOptions<T extends Options> = {
105
+ [K in keyof T]: T[K] extends CLIOption<infer S> ? InferSchema<S> : never;
106
+ };
107
+
108
+ // Type helper to merge global flags with command options
109
+ export type MergedOptions<TOptions extends Options> = typeof GLOBAL_FLAGS & TOptions;
110
+
111
+ // Type helper to infer types from merged options (global flags + command options)
112
+ export type InferMergedOptions<TOptions extends Options> = InferOptions<MergedOptions<TOptions>>;
113
+
114
+ // generic Handler type that accepts inferred flags type
115
+ export type Handler<
116
+ TFlags = Record<string, unknown>,
117
+ TStore = {},
118
+ TCommandName extends string = string,
119
+ > = (args: HandlerArgs<TFlags, TStore, TCommandName>) => void | Promise<void>;
120
+
121
+ // generic HandlerArgs that accepts flags type
122
+ export interface HandlerArgs<
123
+ TFlags = Record<string, unknown>,
124
+ TStore = {},
125
+ TCommandName extends string = string,
126
+ > {
127
+ // ✨ Automatic type inference from command options ✨
128
+ flags: TFlags;
129
+ positional: string[];
130
+ shell: typeof Bun.$;
131
+ env: typeof process.env;
132
+ cwd: string;
133
+ // Utilities
134
+ prompt: typeof import("@reliverse/rempts-utils").prompt;
135
+ spinner: typeof import("@reliverse/rempts-utils").spinner;
136
+ colors: typeof import("@reliverse/relico").relico;
137
+ // Plugin context (if plugins are loaded)
138
+ context?: import("./plugin/types.js").CommandContext<any>;
139
+ // Data set by global before hooks
140
+ hooks?: Record<string, any>;
141
+ // Terminal information
142
+ terminal: TerminalInfo;
143
+ // Runtime information
144
+ runtime: RuntimeInfo;
145
+ }
146
+
147
+ export interface TerminalInfo {
148
+ width: number;
149
+ height: number;
150
+ isInteractive: boolean;
151
+ isCI: boolean;
152
+ supportsColor: boolean;
153
+ supportsMouse: boolean;
154
+ }
155
+
156
+ export interface RuntimeInfo {
157
+ startTime: number;
158
+ args: string[];
159
+ command: string;
160
+ }
161
+
162
+ // CLI option with metadata - generic to preserve schema type
163
+ export interface CLIOption<S extends StandardSchemaV1 = StandardSchemaV1> {
164
+ schema: S;
165
+ short?: string;
166
+ description?: string;
167
+ default?: unknown; // Default value when flag is not provided (will be validated against schema)
168
+ }
169
+
170
+ // Options must use the CLIOption wrapper
171
+ export type Options = Record<string, CLIOption<any>>;
172
+
173
+ // Define command helper with proper type inference
174
+ // Note: 'name' is automatically inferred from file path: <cmds-dir>/<cmd-name>/cmd.{ts,js,mjs}
175
+ export function defineCommand<TOptions extends Options = Options, TStore = {}>(
176
+ command: Command<TOptions, TStore>
177
+ ): Command<TOptions, TStore> {
178
+ return command;
179
+ }
180
+
181
+ // Import configuration types from schema
182
+ import type { RemptsConfig } from "./config";
183
+
184
+ export type { RemptsConfig } from "./config";
185
+ export { remptsConfigSchema } from "./config";
186
+
187
+ // Plugin configuration type (imported from plugin/types)
188
+ export type PluginConfig = import("./plugin/types.js").PluginConfig;
189
+
190
+ export type RegisteredCommands = Record<string, Command<any, any, any>>;
191
+
192
+ /**
193
+ * Get command options type from registered commands
194
+ * Uses Standard Schema's InferOutput to extract types from schemas
195
+ */
196
+ export type CommandOptions<T extends keyof RegisteredCommands> =
197
+ RegisteredCommands[T] extends Command<infer TOptions, any, any> ? InferOptions<TOptions> : never;
198
+
199
+ export type CommandFlags<TCommand extends Command<any, any, any>> =
200
+ TCommand extends Command<infer TOptions, any, any> ? InferOptions<TOptions> : never;
201
+
202
+ /**
203
+ * Get all registered command names
204
+ */
205
+ export type RegisteredCommandNames = keyof RegisteredCommands;
206
+
207
+ // Resolved config after all plugins have run
208
+ // Codegen is handled internally and not part of the resolved config
209
+ export type ResolvedConfig = Required<
210
+ Omit<RemptsConfig, "build" | "dev" | "test" | "workspace" | "release">
211
+ > & {
212
+ build: NonNullable<RemptsConfig["build"]>;
213
+ dev: NonNullable<RemptsConfig["dev"]>;
214
+ test: NonNullable<RemptsConfig["test"]>;
215
+ workspace: NonNullable<RemptsConfig["workspace"]>;
216
+ release: NonNullable<RemptsConfig["release"]>;
217
+ };
218
+
219
+ /**
220
+ * Hook context passed to before/after hooks
221
+ */
222
+ export interface HookContext<TStore = {}> {
223
+ /** Global flags parsed from command line */
224
+ flags: Record<string, unknown>;
225
+ /** Store from plugins (if any) */
226
+ store: TStore;
227
+ /** Environment variables */
228
+ env: typeof process.env;
229
+ /** Current working directory */
230
+ cwd: string;
231
+ /** Set data that will be available to command handlers */
232
+ set(key: string, value: any): void;
233
+ /** Get data that was set by hooks */
234
+ get(key: string): any;
235
+ }
236
+
237
+ /**
238
+ * Before hook function type
239
+ */
240
+ export type BeforeHook<TStore = {}> = (context: HookContext<TStore>) => void | Promise<void>;
241
+
242
+ /**
243
+ * After hook function type
244
+ */
245
+ export type AfterHook<TStore = {}> = (
246
+ context: HookContext<TStore> & { exitCode: number; error?: Error }
247
+ ) => void | Promise<void>;
248
+
249
+ /**
250
+ * Rich validation error with context information
251
+ */
252
+ export class RemptsValidationError extends Error {
253
+ constructor(
254
+ message: string,
255
+ readonly context: {
256
+ option: string;
257
+ value: unknown;
258
+ command: string;
259
+ expectedType: string;
260
+ hint?: string;
261
+ }
262
+ ) {
263
+ super(message);
264
+ this.name = "RemptsValidationError";
265
+ }
266
+
267
+ override toString(): string {
268
+ return `${this.name}: Invalid option '${this.context.option}' for command '${this.context.command}'
269
+
270
+ Expected: ${this.context.expectedType}
271
+ Received: ${typeof this.context.value} (${JSON.stringify(this.context.value)})
272
+ ${this.context.hint ? `\nHint: ${this.context.hint}` : ""}`;
273
+ }
274
+ }
275
+
276
+ // Helper to create a CLI option with metadata
277
+ export function option<S extends StandardSchemaV1>(
278
+ schema: S,
279
+ metadata?: { short?: string; description?: string; default?: unknown }
280
+ ): CLIOption<S> {
281
+ return {
282
+ schema,
283
+ ...metadata,
284
+ };
285
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Simple logger implementation
3
+ */
4
+
5
+ export interface Logger {
6
+ info(message: string, ...args: any[]): void;
7
+ warn(message: string, ...args: any[]): void;
8
+ error(message: string, ...args: any[]): void;
9
+ debug(message: string, ...args: any[]): void;
10
+ }
11
+
12
+ export function createLogger(namespace: string): Logger {
13
+ const prefix = `[${namespace}]`;
14
+ const debugEnabled =
15
+ process.env.dler_DEBUG === "true" || process.env.dler_DEBUG?.includes(namespace);
16
+ const silent = process.env.dler_SILENT === "true" || process.env.NODE_ENV === "test";
17
+
18
+ return {
19
+ info(message: string, ...args: any[]) {
20
+ if (!silent) {
21
+ console.log(prefix, message, ...args);
22
+ }
23
+ },
24
+
25
+ warn(message: string, ...args: any[]) {
26
+ if (!silent) {
27
+ console.warn(prefix, message, ...args);
28
+ }
29
+ },
30
+
31
+ error(message: string, ...args: any[]) {
32
+ if (!silent) {
33
+ console.error(prefix, message, ...args);
34
+ }
35
+ },
36
+
37
+ debug(message: string, ...args: any[]) {
38
+ if (debugEnabled && !silent) {
39
+ console.log(`${prefix} [DEBUG]`, message, ...args);
40
+ }
41
+ },
42
+ };
43
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Deep merge utility for configuration objects
3
+ */
4
+
5
+ /**
6
+ * Check if a value is a plain object
7
+ */
8
+ function isPlainObject(value: any): value is Record<string, any> {
9
+ return (
10
+ value !== null &&
11
+ typeof value === "object" &&
12
+ value.constructor === Object &&
13
+ Object.prototype.toString.call(value) === "[object Object]"
14
+ );
15
+ }
16
+
17
+ /**
18
+ * Deep merge multiple objects
19
+ * Arrays are concatenated, objects are recursively merged
20
+ */
21
+ export function deepMerge<T = any>(...objects: Partial<T>[]): T {
22
+ const result: any = {};
23
+
24
+ for (const obj of objects) {
25
+ if (!obj) {
26
+ continue;
27
+ }
28
+
29
+ for (const [key, value] of Object.entries(obj)) {
30
+ const existing = result[key];
31
+
32
+ if (Array.isArray(value)) {
33
+ // Concatenate arrays
34
+ result[key] = Array.isArray(existing) ? [...existing, ...value] : [...value];
35
+ } else if (isPlainObject(value)) {
36
+ // Recursively merge objects
37
+ result[key] = isPlainObject(existing) ? deepMerge(existing, value) : { ...value };
38
+ } else {
39
+ // Primitive values - last one wins
40
+ result[key] = value;
41
+ }
42
+ }
43
+ }
44
+
45
+ return result as T;
46
+ }
47
+
48
+ /**
49
+ * Shallow merge multiple objects
50
+ * Last value wins for all properties
51
+ */
52
+ export function shallowMerge<T = any>(...objects: Partial<T>[]): T {
53
+ return Object.assign({}, ...objects) as T;
54
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Utility exports
3
+ */
4
+
5
+ export type { Logger } from "./logger";
6
+ export { createLogger } from "./logger";
7
+ export { deepMerge, shallowMerge } from "./merge";