@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.
- package/README.md +398 -102
- package/dist/cli.d.ts +32 -0
- package/dist/cli.js +731 -0
- package/dist/config-loader.d.ts +42 -0
- package/dist/config-loader.js +20 -0
- package/dist/config.d.ts +99 -0
- package/dist/config.js +188 -0
- package/dist/file-loader.d.ts +43 -0
- package/dist/file-loader.js +199 -0
- package/dist/global-flags.d.ts +36 -0
- package/dist/global-flags.js +36 -0
- package/dist/mod.d.ts +13 -0
- package/dist/mod.js +19 -0
- package/dist/parser.d.ts +6 -0
- package/dist/parser.js +137 -0
- package/dist/plugin/context.d.ts +13 -0
- package/dist/plugin/context.js +53 -0
- package/dist/plugin/create.d.ts +92 -0
- package/dist/plugin/create.js +61 -0
- package/dist/plugin/loader.d.ts +12 -0
- package/dist/plugin/loader.js +65 -0
- package/dist/plugin/manager.d.ts +53 -0
- package/dist/plugin/manager.js +135 -0
- package/dist/plugin/mod.d.ts +10 -0
- package/dist/plugin/mod.js +27 -0
- package/dist/plugin/store.d.ts +45 -0
- package/dist/plugin/store.js +60 -0
- package/dist/plugin/testing.d.ts +38 -0
- package/dist/plugin/testing.js +175 -0
- package/dist/plugin/types.d.ts +146 -0
- package/dist/tui/registry.d.ts +8 -0
- package/dist/tui/registry.js +10 -0
- package/dist/tui/types.d.ts +58 -0
- package/dist/tui/types.js +10 -0
- package/dist/types.d.ts +178 -0
- package/dist/types.js +25 -0
- package/dist/utils/logger.d.ts +10 -0
- package/dist/utils/logger.js +27 -0
- package/dist/utils/merge.d.ts +13 -0
- package/dist/utils/merge.js +25 -0
- package/dist/utils/mod.d.ts +6 -0
- package/dist/utils/mod.js +2 -0
- package/dist/utils/type-helpers.d.ts +41 -0
- package/dist/utils/type-helpers.js +0 -0
- package/dist/validation.d.ts +30 -0
- package/dist/validation.js +121 -0
- package/package.json +47 -44
- package/src/cli.ts +1049 -0
- package/src/config-loader.ts +71 -0
- package/src/config.ts +270 -0
- package/src/file-loader.ts +346 -0
- package/src/global-flags.ts +50 -0
- package/src/mod.ts +74 -0
- package/src/parser.ts +212 -0
- package/src/plugin/context.ts +88 -0
- package/src/plugin/create.ts +174 -0
- package/src/plugin/loader.ts +111 -0
- package/src/plugin/manager.ts +244 -0
- package/src/plugin/mod.ts +51 -0
- package/src/plugin/store.ts +124 -0
- package/src/plugin/testing.ts +236 -0
- package/src/plugin/types.ts +206 -0
- package/src/tui/registry.ts +22 -0
- package/src/tui/types.ts +79 -0
- package/src/types.ts +285 -0
- package/src/utils/logger.ts +43 -0
- package/src/utils/merge.ts +54 -0
- package/src/utils/mod.ts +7 -0
- package/src/utils/type-helpers.ts +151 -0
- package/src/validation.ts +177 -0
- package/LICENSE +0 -21
- package/bin/core-impl/anykey/anykey-mod.d.ts +0 -12
- package/bin/core-impl/anykey/anykey-mod.js +0 -125
- package/bin/core-impl/date/date.d.ts +0 -2
- package/bin/core-impl/date/date.js +0 -236
- package/bin/core-impl/editor/editor-mod.d.ts +0 -25
- package/bin/core-impl/editor/editor-mod.js +0 -896
- package/bin/core-impl/figures/figures-mod.d.ts +0 -233
- package/bin/core-impl/figures/figures-mod.js +0 -286
- package/bin/core-impl/figures/figures.test.d.ts +0 -1
- package/bin/core-impl/figures/figures.test.js +0 -474
- package/bin/core-impl/input/confirm-prompt.d.ts +0 -5
- package/bin/core-impl/input/confirm-prompt.js +0 -173
- package/bin/core-impl/input/input-prompt.d.ts +0 -16
- package/bin/core-impl/input/input-prompt.js +0 -370
- package/bin/core-impl/launcher/_parser.d.ts +0 -2
- package/bin/core-impl/launcher/_parser.js +0 -122
- package/bin/core-impl/launcher/_utils.d.ts +0 -8
- package/bin/core-impl/launcher/_utils.js +0 -29
- package/bin/core-impl/launcher/args.d.ts +0 -3
- package/bin/core-impl/launcher/args.js +0 -89
- package/bin/core-impl/launcher/command.d.ts +0 -8
- package/bin/core-impl/launcher/command.js +0 -68
- package/bin/core-impl/launcher/launcher-mod.d.ts +0 -8
- package/bin/core-impl/launcher/launcher-mod.js +0 -34
- package/bin/core-impl/launcher/usage.d.ts +0 -3
- package/bin/core-impl/launcher/usage.js +0 -104
- package/bin/core-impl/msg-fmt/colors.d.ts +0 -30
- package/bin/core-impl/msg-fmt/colors.js +0 -42
- package/bin/core-impl/msg-fmt/logger.d.ts +0 -17
- package/bin/core-impl/msg-fmt/logger.js +0 -106
- package/bin/core-impl/msg-fmt/mapping.d.ts +0 -3
- package/bin/core-impl/msg-fmt/mapping.js +0 -49
- package/bin/core-impl/msg-fmt/messages.d.ts +0 -35
- package/bin/core-impl/msg-fmt/messages.js +0 -314
- package/bin/core-impl/msg-fmt/terminal.d.ts +0 -15
- package/bin/core-impl/msg-fmt/terminal.js +0 -59
- package/bin/core-impl/msg-fmt/variants.d.ts +0 -11
- package/bin/core-impl/msg-fmt/variants.js +0 -52
- package/bin/core-impl/next-steps/next-steps.d.ts +0 -14
- package/bin/core-impl/next-steps/next-steps.js +0 -24
- package/bin/core-impl/number/number-mod.d.ts +0 -28
- package/bin/core-impl/number/number-mod.js +0 -197
- package/bin/core-impl/results/results.d.ts +0 -7
- package/bin/core-impl/results/results.js +0 -27
- package/bin/core-impl/select/multiselect-prompt.d.ts +0 -2
- package/bin/core-impl/select/multiselect-prompt.js +0 -341
- package/bin/core-impl/select/nummultiselect-prompt.d.ts +0 -6
- package/bin/core-impl/select/nummultiselect-prompt.js +0 -105
- package/bin/core-impl/select/numselect-prompt.d.ts +0 -7
- package/bin/core-impl/select/numselect-prompt.js +0 -115
- package/bin/core-impl/select/select-prompt.d.ts +0 -33
- package/bin/core-impl/select/select-prompt.js +0 -302
- package/bin/core-impl/select/toggle-prompt.d.ts +0 -5
- package/bin/core-impl/select/toggle-prompt.js +0 -208
- package/bin/core-impl/st-end/end.d.ts +0 -2
- package/bin/core-impl/st-end/end.js +0 -42
- package/bin/core-impl/st-end/start.d.ts +0 -17
- package/bin/core-impl/st-end/start.js +0 -66
- package/bin/core-impl/task/progress.d.ts +0 -2
- package/bin/core-impl/task/progress.js +0 -57
- package/bin/core-impl/task/spinner.d.ts +0 -15
- package/bin/core-impl/task/spinner.js +0 -110
- package/bin/core-impl/utils/colorize.d.ts +0 -2
- package/bin/core-impl/utils/colorize.js +0 -134
- package/bin/core-impl/utils/errors.d.ts +0 -1
- package/bin/core-impl/utils/errors.js +0 -15
- package/bin/core-impl/utils/prevent.d.ts +0 -10
- package/bin/core-impl/utils/prevent.js +0 -69
- package/bin/core-impl/utils/prompt-end.d.ts +0 -8
- package/bin/core-impl/utils/prompt-end.js +0 -33
- package/bin/core-impl/utils/stream-text.d.ts +0 -18
- package/bin/core-impl/utils/stream-text.js +0 -136
- package/bin/core-impl/utils/system.d.ts +0 -6
- package/bin/core-impl/utils/system.js +0 -7
- package/bin/core-impl/utils/validate.d.ts +0 -22
- package/bin/core-impl/utils/validate.js +0 -17
- package/bin/core-impl/visual/animate/animate.d.ts +0 -14
- package/bin/core-impl/visual/animate/animate.js +0 -64
- package/bin/core-impl/visual/ascii-art/ascii-art.d.ts +0 -6
- package/bin/core-impl/visual/ascii-art/ascii-art.js +0 -12
- package/bin/core-types.d.ts +0 -434
- package/bin/main.d.ts +0 -41
- package/bin/main.js +0 -96
- /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
|
+
}
|
package/src/tui/types.ts
ADDED
|
@@ -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
|
+
}
|