@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,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zustand store utilities for Rempts plugin system
|
|
3
|
+
*/
|
|
4
|
+
import { type StoreApi } from "zustand";
|
|
5
|
+
/**
|
|
6
|
+
* Generic Zustand store interface for plugins
|
|
7
|
+
*/
|
|
8
|
+
export interface PluginStore<TState = any> extends StoreApi<TState> {
|
|
9
|
+
/**
|
|
10
|
+
* Get the current state
|
|
11
|
+
*/
|
|
12
|
+
getState(): TState;
|
|
13
|
+
/**
|
|
14
|
+
* Subscribe to state changes
|
|
15
|
+
*/
|
|
16
|
+
subscribe(listener: (state: TState, prevState: TState) => void): () => void;
|
|
17
|
+
/**
|
|
18
|
+
* Set new state
|
|
19
|
+
*/
|
|
20
|
+
setState(updater: TState | ((prevState: TState) => TState)): void;
|
|
21
|
+
/**
|
|
22
|
+
* Destroy the store
|
|
23
|
+
*/
|
|
24
|
+
destroy(): void;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Create a Zustand store for a plugin
|
|
28
|
+
*/
|
|
29
|
+
export declare function createPluginStore<TState>(initialState: TState): PluginStore<TState>;
|
|
30
|
+
/**
|
|
31
|
+
* Combine multiple plugin stores into a single store
|
|
32
|
+
*/
|
|
33
|
+
export declare function combinePluginStores<TCombined>(stores: Record<string, PluginStore<any>>): PluginStore<TCombined>;
|
|
34
|
+
/**
|
|
35
|
+
* Type helper for plugin store state
|
|
36
|
+
*/
|
|
37
|
+
export type PluginStoreState<TStore extends PluginStore<any>> = ReturnType<TStore["getState"]>;
|
|
38
|
+
/**
|
|
39
|
+
* Middleware for logging store changes (useful for debugging)
|
|
40
|
+
*/
|
|
41
|
+
export declare function createLoggingMiddleware<TState>(): (config: any) => (set: any, get: any, api: any) => any;
|
|
42
|
+
/**
|
|
43
|
+
* Create a store with logging enabled
|
|
44
|
+
*/
|
|
45
|
+
export declare function createPluginStoreWithLogging<TState>(initialState: TState, enableLogging?: boolean): PluginStore<TState>;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { createStore } from "zustand";
|
|
2
|
+
export function createPluginStore(initialState) {
|
|
3
|
+
const store = createStore()(() => initialState);
|
|
4
|
+
return {
|
|
5
|
+
...store,
|
|
6
|
+
destroy: () => {
|
|
7
|
+
}
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
export function combinePluginStores(stores) {
|
|
11
|
+
const initialState = Object.keys(stores).reduce((acc, key) => {
|
|
12
|
+
const store = stores[key];
|
|
13
|
+
if (store) {
|
|
14
|
+
acc[key] = store.getState();
|
|
15
|
+
}
|
|
16
|
+
return acc;
|
|
17
|
+
}, {});
|
|
18
|
+
const combinedStore = createStore()(() => initialState);
|
|
19
|
+
const unsubscribers = Object.keys(stores).map((key) => {
|
|
20
|
+
const store = stores[key];
|
|
21
|
+
if (store) {
|
|
22
|
+
return store.subscribe((state) => {
|
|
23
|
+
combinedStore.setState((prevState) => ({
|
|
24
|
+
...prevState,
|
|
25
|
+
[key]: state
|
|
26
|
+
}));
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
return () => {
|
|
30
|
+
};
|
|
31
|
+
});
|
|
32
|
+
return {
|
|
33
|
+
...combinedStore,
|
|
34
|
+
destroy: () => {
|
|
35
|
+
unsubscribers.forEach((unsubscribe) => unsubscribe());
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export function createLoggingMiddleware() {
|
|
40
|
+
return (config) => (set, get, api) => config(
|
|
41
|
+
(...args) => {
|
|
42
|
+
console.log("Store before:", get());
|
|
43
|
+
set(...args);
|
|
44
|
+
console.log("Store after:", get());
|
|
45
|
+
},
|
|
46
|
+
get,
|
|
47
|
+
api
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
export function createPluginStoreWithLogging(initialState, enableLogging = false) {
|
|
51
|
+
if (enableLogging) {
|
|
52
|
+
const store = createStore()(createLoggingMiddleware()(() => initialState));
|
|
53
|
+
return {
|
|
54
|
+
...store,
|
|
55
|
+
destroy: () => {
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
return createPluginStore(initialState);
|
|
60
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin testing utilities for Rempts
|
|
3
|
+
*/
|
|
4
|
+
import type { RemptsConfig } from "../types.js";
|
|
5
|
+
import { type PluginStore } from "./store.js.js";
|
|
6
|
+
import type { CommandContext, Plugin, PluginContext } from "./types.js";
|
|
7
|
+
/**
|
|
8
|
+
* Mock plugin context for testing
|
|
9
|
+
*/
|
|
10
|
+
export declare function createMockPluginContext(config?: Partial<RemptsConfig>, store?: PluginStore<any>): PluginContext;
|
|
11
|
+
/**
|
|
12
|
+
* Mock command context for testing
|
|
13
|
+
*/
|
|
14
|
+
export declare function createMockCommandContext<TStore = {}>(command?: string, args?: string[], flags?: Record<string, any>, initialStore?: TStore): CommandContext<TStore>;
|
|
15
|
+
/**
|
|
16
|
+
* Test plugin lifecycle hooks
|
|
17
|
+
*/
|
|
18
|
+
export declare function testPluginHooks<TStore = {}>(plugin: Plugin<TStore>, options?: {
|
|
19
|
+
config?: Partial<RemptsConfig>;
|
|
20
|
+
store?: TStore;
|
|
21
|
+
command?: string;
|
|
22
|
+
args?: string[];
|
|
23
|
+
flags?: Record<string, any>;
|
|
24
|
+
}): Promise<{
|
|
25
|
+
setup?: any;
|
|
26
|
+
configResolved?: any;
|
|
27
|
+
beforeCommand?: any;
|
|
28
|
+
afterCommand?: any;
|
|
29
|
+
}>;
|
|
30
|
+
/**
|
|
31
|
+
* Assert plugin behavior in tests
|
|
32
|
+
*/
|
|
33
|
+
export declare function assertPluginBehavior(results: Awaited<ReturnType<typeof testPluginHooks>>, expectations: {
|
|
34
|
+
setupShouldSucceed?: boolean;
|
|
35
|
+
configResolvedShouldSucceed?: boolean;
|
|
36
|
+
beforeCommandShouldSucceed?: boolean;
|
|
37
|
+
afterCommandShouldSucceed?: boolean;
|
|
38
|
+
}): void;
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { createLogger } from "../utils/logger.js";
|
|
2
|
+
import { createPluginStore } from "./store.js";
|
|
3
|
+
export function createMockPluginContext(config = {}, store = createPluginStore({})) {
|
|
4
|
+
return {
|
|
5
|
+
config,
|
|
6
|
+
updateConfig: () => {
|
|
7
|
+
},
|
|
8
|
+
registerCommand: () => {
|
|
9
|
+
},
|
|
10
|
+
use: () => {
|
|
11
|
+
},
|
|
12
|
+
store,
|
|
13
|
+
logger: createLogger("test"),
|
|
14
|
+
paths: {
|
|
15
|
+
cwd: process.cwd(),
|
|
16
|
+
home: process.env.HOME || "/tmp",
|
|
17
|
+
config: "/tmp/.config/rempts"
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export function createMockCommandContext(command = "test", args = [], flags = {}, initialStore = {}) {
|
|
22
|
+
let storeState = { ...initialStore };
|
|
23
|
+
const mockStore = {
|
|
24
|
+
getState: () => storeState,
|
|
25
|
+
setState: (updater) => {
|
|
26
|
+
if (typeof updater === "function") {
|
|
27
|
+
storeState = { ...storeState, ...updater(storeState) };
|
|
28
|
+
} else {
|
|
29
|
+
storeState = { ...storeState, ...updater };
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
subscribe: () => () => {
|
|
33
|
+
},
|
|
34
|
+
// Mock subscription
|
|
35
|
+
destroy: () => {
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
return {
|
|
39
|
+
command,
|
|
40
|
+
commandDef: {},
|
|
41
|
+
args,
|
|
42
|
+
flags,
|
|
43
|
+
env: {
|
|
44
|
+
isCI: false,
|
|
45
|
+
isAIAgent: false,
|
|
46
|
+
aiAgents: []
|
|
47
|
+
},
|
|
48
|
+
store: mockStore,
|
|
49
|
+
getStoreValue: (key) => storeState[key],
|
|
50
|
+
setStoreValue: (key, value) => {
|
|
51
|
+
mockStore.setState({ [key]: value });
|
|
52
|
+
},
|
|
53
|
+
hasStoreValue: (key) => key in storeState
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
export async function testPluginHooks(plugin, options = {}) {
|
|
57
|
+
const hooks = plugin();
|
|
58
|
+
const results = {};
|
|
59
|
+
if (hooks.setup) {
|
|
60
|
+
const context = createMockPluginContext(options.config);
|
|
61
|
+
try {
|
|
62
|
+
await hooks.setup(context);
|
|
63
|
+
results.setup = { success: true, context };
|
|
64
|
+
} catch (error) {
|
|
65
|
+
results.setup = { success: false, error };
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (hooks.configResolved) {
|
|
69
|
+
const config = {
|
|
70
|
+
name: "test-cli",
|
|
71
|
+
version: "1.0.0",
|
|
72
|
+
description: "Test CLI",
|
|
73
|
+
commands: {},
|
|
74
|
+
build: {
|
|
75
|
+
targets: ["native"],
|
|
76
|
+
compress: false,
|
|
77
|
+
minify: false,
|
|
78
|
+
sourcemap: true
|
|
79
|
+
},
|
|
80
|
+
dev: {
|
|
81
|
+
watch: true,
|
|
82
|
+
inspect: false
|
|
83
|
+
},
|
|
84
|
+
test: {
|
|
85
|
+
pattern: ["**/*.test.ts", "**/*.spec.ts"],
|
|
86
|
+
coverage: false,
|
|
87
|
+
watch: false
|
|
88
|
+
},
|
|
89
|
+
workspace: {
|
|
90
|
+
versionStrategy: "fixed"
|
|
91
|
+
},
|
|
92
|
+
release: {
|
|
93
|
+
npm: true,
|
|
94
|
+
github: false,
|
|
95
|
+
tagFormat: "v{{version}}",
|
|
96
|
+
conventionalCommits: true
|
|
97
|
+
},
|
|
98
|
+
plugins: []
|
|
99
|
+
};
|
|
100
|
+
try {
|
|
101
|
+
await hooks.configResolved(config);
|
|
102
|
+
results.configResolved = { success: true, config };
|
|
103
|
+
} catch (error) {
|
|
104
|
+
results.configResolved = { success: false, error };
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (hooks.beforeCommand) {
|
|
108
|
+
const context = createMockCommandContext(
|
|
109
|
+
options.command || "test",
|
|
110
|
+
options.args || [],
|
|
111
|
+
options.flags || {},
|
|
112
|
+
options.store || {}
|
|
113
|
+
);
|
|
114
|
+
try {
|
|
115
|
+
await hooks.beforeCommand(context);
|
|
116
|
+
results.beforeCommand = { success: true, context };
|
|
117
|
+
} catch (error) {
|
|
118
|
+
results.beforeCommand = { success: false, error };
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (hooks.afterCommand) {
|
|
122
|
+
const context = createMockCommandContext(
|
|
123
|
+
options.command || "test",
|
|
124
|
+
options.args || [],
|
|
125
|
+
options.flags || {},
|
|
126
|
+
options.store || {}
|
|
127
|
+
);
|
|
128
|
+
try {
|
|
129
|
+
await hooks.afterCommand(context);
|
|
130
|
+
results.afterCommand = { success: true, context };
|
|
131
|
+
} catch (error) {
|
|
132
|
+
results.afterCommand = { success: false, error };
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return results;
|
|
136
|
+
}
|
|
137
|
+
export function assertPluginBehavior(results, expectations) {
|
|
138
|
+
const assertions = [];
|
|
139
|
+
if (expectations.setupShouldSucceed !== void 0) {
|
|
140
|
+
const actual = results.setup?.success ?? false;
|
|
141
|
+
if (actual !== expectations.setupShouldSucceed) {
|
|
142
|
+
assertions.push(
|
|
143
|
+
`Setup hook ${actual ? "succeeded" : "failed"} but expected ${expectations.setupShouldSucceed ? "success" : "failure"}`
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (expectations.configResolvedShouldSucceed !== void 0) {
|
|
148
|
+
const actual = results.configResolved?.success ?? false;
|
|
149
|
+
if (actual !== expectations.configResolvedShouldSucceed) {
|
|
150
|
+
assertions.push(
|
|
151
|
+
`ConfigResolved hook ${actual ? "succeeded" : "failed"} but expected ${expectations.configResolvedShouldSucceed ? "success" : "failure"}`
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (expectations.beforeCommandShouldSucceed !== void 0) {
|
|
156
|
+
const actual = results.beforeCommand?.success ?? false;
|
|
157
|
+
if (actual !== expectations.beforeCommandShouldSucceed) {
|
|
158
|
+
assertions.push(
|
|
159
|
+
`BeforeCommand hook ${actual ? "succeeded" : "failed"} but expected ${expectations.beforeCommandShouldSucceed ? "success" : "failure"}`
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (expectations.afterCommandShouldSucceed !== void 0) {
|
|
164
|
+
const actual = results.afterCommand?.success ?? false;
|
|
165
|
+
if (actual !== expectations.afterCommandShouldSucceed) {
|
|
166
|
+
assertions.push(
|
|
167
|
+
`AfterCommand hook ${actual ? "succeeded" : "failed"} but expected ${expectations.afterCommandShouldSucceed ? "success" : "failure"}`
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (assertions.length > 0) {
|
|
172
|
+
throw new Error(`Plugin behavior assertions failed:
|
|
173
|
+
${assertions.join("\n")}`);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core plugin types and interfaces for Rempts
|
|
3
|
+
*/
|
|
4
|
+
import type { Command, RemptsConfig, ResolvedConfig } from "../types.js";
|
|
5
|
+
import type { Logger } from "../utils/logger.js";
|
|
6
|
+
import type { PluginStore } from "./store.js";
|
|
7
|
+
export type CommandDefinition = Command<any>;
|
|
8
|
+
/**
|
|
9
|
+
* Functional plugin hooks with store type
|
|
10
|
+
*/
|
|
11
|
+
export interface PluginHooks<TStore = {}> {
|
|
12
|
+
/** Plugin store - Zustand store instance */
|
|
13
|
+
store?: PluginStore<TStore>;
|
|
14
|
+
/**
|
|
15
|
+
* Setup hook - Called during CLI initialization
|
|
16
|
+
* Can modify configuration and register commands
|
|
17
|
+
*/
|
|
18
|
+
setup?: (context: PluginContext) => void | Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Config resolved hook - Called after all configuration is finalized
|
|
21
|
+
* Config is now immutable
|
|
22
|
+
*/
|
|
23
|
+
configResolved?: (config: ResolvedConfig) => void | Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Before command hook - Called before command execution
|
|
26
|
+
* Can inject context and validate
|
|
27
|
+
* Uses generic constraints to preserve store type information
|
|
28
|
+
*/
|
|
29
|
+
beforeCommand?: (context: CommandContext<any>) => void | Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* After command hook - Called after command execution
|
|
32
|
+
* Receives result or error from command
|
|
33
|
+
* Uses generic constraints to preserve store type information
|
|
34
|
+
*/
|
|
35
|
+
afterCommand?: (context: CommandContext<any> & CommandResult) => void | Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Core plugin function that returns hooks
|
|
39
|
+
*/
|
|
40
|
+
export type Plugin<TStore = {}> = () => PluginHooks<TStore>;
|
|
41
|
+
/**
|
|
42
|
+
* Extract store type from plugin hooks
|
|
43
|
+
*/
|
|
44
|
+
export type StoreOf<P> = P extends PluginHooks<infer S> ? S : {};
|
|
45
|
+
/**
|
|
46
|
+
* Merge multiple plugin stores into one type
|
|
47
|
+
*/
|
|
48
|
+
export type MergeStores<Plugins extends readonly PluginHooks[]> = Plugins extends readonly [] ? {} : Plugins extends readonly [infer First, ...infer Rest] ? First extends PluginHooks ? Rest extends readonly PluginHooks[] ? StoreOf<First> & MergeStores<Rest> : StoreOf<First> : {} : {};
|
|
49
|
+
/**
|
|
50
|
+
* Merge stores from plugin functions
|
|
51
|
+
*/
|
|
52
|
+
export type MergePluginStores<Plugins extends readonly Plugin[]> = Plugins extends readonly [] ? {} : Plugins extends readonly [infer First, ...infer Rest] ? First extends Plugin<infer S> ? Rest extends readonly Plugin[] ? S & MergePluginStores<Rest> : S : {} : {};
|
|
53
|
+
/**
|
|
54
|
+
* Plugin factory function type - returns a function that creates hooks
|
|
55
|
+
*/
|
|
56
|
+
export type PluginFactory<TOptions = any, TStore = {}> = (options?: TOptions) => Plugin<TStore>;
|
|
57
|
+
/**
|
|
58
|
+
* Command execution result
|
|
59
|
+
*/
|
|
60
|
+
export interface CommandResult {
|
|
61
|
+
/** Command return value */
|
|
62
|
+
result?: any;
|
|
63
|
+
/** Error if command failed */
|
|
64
|
+
error?: Error;
|
|
65
|
+
/** Exit code */
|
|
66
|
+
exitCode?: number;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Plugin configuration types
|
|
70
|
+
*/
|
|
71
|
+
export type PluginConfig = string | Plugin | PluginFactory | [PluginFactory, any];
|
|
72
|
+
/**
|
|
73
|
+
* Plugin context available during setup
|
|
74
|
+
*/
|
|
75
|
+
export interface PluginContext {
|
|
76
|
+
/** Current configuration (being built) */
|
|
77
|
+
readonly config: Partial<RemptsConfig>;
|
|
78
|
+
/** Update configuration */
|
|
79
|
+
updateConfig(partial: Partial<RemptsConfig>): void;
|
|
80
|
+
/** Register a new command */
|
|
81
|
+
registerCommand(command: CommandDefinition): void;
|
|
82
|
+
/** Add global middleware */
|
|
83
|
+
use(middleware: Middleware): void;
|
|
84
|
+
/** Shared storage between plugins */
|
|
85
|
+
readonly store: PluginStore<any>;
|
|
86
|
+
/** Plugin logger */
|
|
87
|
+
readonly logger: Logger;
|
|
88
|
+
/** System paths */
|
|
89
|
+
readonly paths: PathInfo;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Command execution context
|
|
93
|
+
*/
|
|
94
|
+
export interface CommandContext<TStore = {}> {
|
|
95
|
+
/** Command name being executed */
|
|
96
|
+
readonly command: string;
|
|
97
|
+
/** The Command object being executed */
|
|
98
|
+
readonly commandDef: Command<any, TStore>;
|
|
99
|
+
/** Positional arguments */
|
|
100
|
+
readonly args: string[];
|
|
101
|
+
/** Parsed flags/options */
|
|
102
|
+
readonly flags: Record<string, any>;
|
|
103
|
+
/** Environment information */
|
|
104
|
+
readonly env: EnvironmentInfo;
|
|
105
|
+
/** Type-safe context store */
|
|
106
|
+
readonly store?: PluginStore<TStore>;
|
|
107
|
+
/** Type-safe store value access */
|
|
108
|
+
getStoreValue<K extends keyof TStore>(key: K): TStore[K];
|
|
109
|
+
getStoreValue(key: string | number | symbol): any;
|
|
110
|
+
/** Type-safe store value update */
|
|
111
|
+
setStoreValue<K extends keyof TStore>(key: K, value: TStore[K]): void;
|
|
112
|
+
setStoreValue(key: string | number | symbol, value: any): void;
|
|
113
|
+
/** Check if a store property exists */
|
|
114
|
+
hasStoreValue<K extends keyof TStore>(key: K): boolean;
|
|
115
|
+
hasStoreValue(key: string | number | symbol): boolean;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* System path information
|
|
119
|
+
*/
|
|
120
|
+
export interface PathInfo {
|
|
121
|
+
/** Current working directory */
|
|
122
|
+
cwd: string;
|
|
123
|
+
/** User home directory */
|
|
124
|
+
home: string;
|
|
125
|
+
/** Config directory path */
|
|
126
|
+
config: string;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Environment information
|
|
130
|
+
*/
|
|
131
|
+
export interface EnvironmentInfo {
|
|
132
|
+
/** Running in CI environment */
|
|
133
|
+
isCI: boolean;
|
|
134
|
+
/** Additional properties that plugins can add */
|
|
135
|
+
[key: string]: any;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Middleware function type
|
|
139
|
+
*/
|
|
140
|
+
export type Middleware = (context: CommandContext, next: () => Promise<any>) => Promise<any>;
|
|
141
|
+
/**
|
|
142
|
+
* Plugin extension interfaces
|
|
143
|
+
*
|
|
144
|
+
* Note: Plugins should extend these interfaces directly in their own code
|
|
145
|
+
* rather than using module augmentation, as that creates circular dependencies.
|
|
146
|
+
*/
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TUI Registry - manages the global TUI renderer
|
|
3
|
+
* This module provides a simple registry for TUI renderers
|
|
4
|
+
*/
|
|
5
|
+
import type { RenderArgs } from "../types.js";
|
|
6
|
+
export declare function registerTuiRenderer<TFlags = Record<string, unknown>, TStore = {}>(fn: (args: RenderArgs<TFlags, TStore>) => Promise<unknown> | unknown): void;
|
|
7
|
+
export declare function getTuiRenderer<TFlags = Record<string, unknown>, TStore = {}>(): ((args: RenderArgs<TFlags, TStore>) => Promise<unknown> | unknown) | null;
|
|
8
|
+
export declare function clearTuiRenderer(): void;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { RenderResult } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Options passed to the TUI renderer when rendering a component
|
|
4
|
+
*/
|
|
5
|
+
export interface TuiRendererOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Exit on Ctrl+C (default: true)
|
|
8
|
+
*/
|
|
9
|
+
exitOnCtrlC?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Target frames per second (default: 30)
|
|
12
|
+
*/
|
|
13
|
+
targetFps?: number;
|
|
14
|
+
/**
|
|
15
|
+
* Enable mouse movement events (default: true)
|
|
16
|
+
*/
|
|
17
|
+
enableMouseMovement?: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Additional renderer-specific options
|
|
20
|
+
*/
|
|
21
|
+
[key: string]: unknown;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Context passed when rendering TUI components
|
|
25
|
+
*/
|
|
26
|
+
export interface TuiRenderContext {
|
|
27
|
+
/**
|
|
28
|
+
* Renderer-specific options
|
|
29
|
+
*/
|
|
30
|
+
rendererOptions?: TuiRendererOptions;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* TUI Renderer interface
|
|
34
|
+
* Implementations should handle rendering React components to the terminal
|
|
35
|
+
*/
|
|
36
|
+
export interface TuiRenderer {
|
|
37
|
+
/**
|
|
38
|
+
* Render a component result to the terminal
|
|
39
|
+
* @param component The component or render result to render
|
|
40
|
+
* @param context Rendering context and options
|
|
41
|
+
* @returns Promise that resolves when rendering completes
|
|
42
|
+
*/
|
|
43
|
+
render(component: RenderResult, context: TuiRenderContext): Promise<unknown>;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Register a TUI renderer globally
|
|
47
|
+
* @param renderer The renderer implementation
|
|
48
|
+
*/
|
|
49
|
+
export declare function registerTuiRenderer(renderer: TuiRenderer): void;
|
|
50
|
+
/**
|
|
51
|
+
* Get the currently registered TUI renderer
|
|
52
|
+
* @returns The registered renderer, or null if none registered
|
|
53
|
+
*/
|
|
54
|
+
export declare function getTuiRenderer(): TuiRenderer | null;
|
|
55
|
+
/**
|
|
56
|
+
* Clear the registered TUI renderer (mainly for testing)
|
|
57
|
+
*/
|
|
58
|
+
export declare function clearTuiRenderer(): void;
|