pi-cicd 1.0.4 → 1.0.5
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/package.json +1 -1
- package/src/commands/command-registry.ts +186 -0
package/package.json
CHANGED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Command Registry Pattern
|
|
3
|
+
*
|
|
4
|
+
* Registry for command handlers with validation and aliases.
|
|
5
|
+
*
|
|
6
|
+
* Inspired by gstack and pi-hermes-memory patterns.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export interface CommandDefinition<T = unknown> {
|
|
10
|
+
/** Command name (e.g., "deploy", "ci-status") */
|
|
11
|
+
name: string;
|
|
12
|
+
/** Short description */
|
|
13
|
+
description?: string;
|
|
14
|
+
/** Longer description */
|
|
15
|
+
help?: string;
|
|
16
|
+
/** Aliases for the command */
|
|
17
|
+
aliases?: string[];
|
|
18
|
+
/** Parameter schema */
|
|
19
|
+
params?: T;
|
|
20
|
+
/** Examples for help */
|
|
21
|
+
examples?: Array<{ cmd: string; desc: string }>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface CommandHandler<T = unknown> {
|
|
25
|
+
/** Execute the command */
|
|
26
|
+
execute(params: T, context: CommandContext): Promise<CommandResult>;
|
|
27
|
+
/** Validate parameters before execution */
|
|
28
|
+
validate?(params: T): ValidationResult;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface CommandContext {
|
|
32
|
+
/** Current working directory */
|
|
33
|
+
cwd: string;
|
|
34
|
+
/** User environment */
|
|
35
|
+
env: Record<string, string>;
|
|
36
|
+
/** Logger */
|
|
37
|
+
log: Logger;
|
|
38
|
+
/** Config store */
|
|
39
|
+
config: ConfigStore;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface CommandResult {
|
|
43
|
+
/** Exit code (0 = success) */
|
|
44
|
+
code: number;
|
|
45
|
+
/** Output to stdout */
|
|
46
|
+
output?: string;
|
|
47
|
+
/** Output to stderr */
|
|
48
|
+
error?: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface ValidationResult {
|
|
52
|
+
valid: boolean;
|
|
53
|
+
errors?: string[];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface Logger {
|
|
57
|
+
info(msg: string): void;
|
|
58
|
+
warn(msg: string): void;
|
|
59
|
+
error(msg: string): void;
|
|
60
|
+
debug(msg: string): void;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface ConfigStore {
|
|
64
|
+
get<T>(key: string, defaultValue?: T): T | undefined;
|
|
65
|
+
set<T>(key: string, value: T): void;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Command registry for managing available commands.
|
|
70
|
+
*/
|
|
71
|
+
export class CommandRegistry {
|
|
72
|
+
private commands = new Map<string, CommandHandler>();
|
|
73
|
+
private definitions = new Map<string, CommandDefinition>();
|
|
74
|
+
private aliases = new Map<string, string>();
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Register a command.
|
|
78
|
+
*/
|
|
79
|
+
register<T = unknown>(
|
|
80
|
+
definition: CommandDefinition<T>,
|
|
81
|
+
handler: CommandHandler<T>
|
|
82
|
+
): void {
|
|
83
|
+
this.commands.set(definition.name, handler as CommandHandler);
|
|
84
|
+
this.definitions.set(definition.name, definition);
|
|
85
|
+
|
|
86
|
+
// Register aliases
|
|
87
|
+
for (const alias of definition.aliases ?? []) {
|
|
88
|
+
this.aliases.set(alias, definition.name);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Execute a command by name.
|
|
94
|
+
*/
|
|
95
|
+
async execute(
|
|
96
|
+
name: string,
|
|
97
|
+
params: unknown,
|
|
98
|
+
context: CommandContext
|
|
99
|
+
): Promise<CommandResult> {
|
|
100
|
+
// Resolve alias
|
|
101
|
+
const resolved = this.aliases.get(name) ?? name;
|
|
102
|
+
|
|
103
|
+
// Find command
|
|
104
|
+
const handler = this.commands.get(resolved);
|
|
105
|
+
if (!handler) {
|
|
106
|
+
return {
|
|
107
|
+
code: 1,
|
|
108
|
+
error: `Unknown command: ${name}`,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Validate
|
|
113
|
+
if (handler.validate) {
|
|
114
|
+
const validation = handler.validate(params);
|
|
115
|
+
if (!validation.valid) {
|
|
116
|
+
return {
|
|
117
|
+
code: 1,
|
|
118
|
+
error: `Validation failed: ${validation.errors?.join(", ")}`,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Execute
|
|
124
|
+
try {
|
|
125
|
+
return await handler.execute(params, context);
|
|
126
|
+
} catch (error) {
|
|
127
|
+
return {
|
|
128
|
+
code: 1,
|
|
129
|
+
error: error instanceof Error ? error.message : String(error),
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Get command definition.
|
|
136
|
+
*/
|
|
137
|
+
getDefinition(name: string): CommandDefinition | undefined {
|
|
138
|
+
const resolved = this.aliases.get(name) ?? name;
|
|
139
|
+
return this.definitions.get(resolved);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* List all command names.
|
|
144
|
+
*/
|
|
145
|
+
listCommands(): string[] {
|
|
146
|
+
return Array.from(this.definitions.keys()).sort();
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Get help text for a command.
|
|
151
|
+
*/
|
|
152
|
+
getHelp(name: string): string | undefined {
|
|
153
|
+
const def = this.getDefinition(name);
|
|
154
|
+
if (!def) return undefined;
|
|
155
|
+
|
|
156
|
+
let help = `# ${def.name}`;
|
|
157
|
+
if (def.aliases?.length) {
|
|
158
|
+
help += ` (alias: ${def.aliases.join(", ")})`;
|
|
159
|
+
}
|
|
160
|
+
help += "\n\n";
|
|
161
|
+
|
|
162
|
+
if (def.description) {
|
|
163
|
+
help += `${def.description}\n\n`;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (def.help) {
|
|
167
|
+
help += `${def.help}\n\n`;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (def.examples?.length) {
|
|
171
|
+
help += "## Examples\n\n";
|
|
172
|
+
for (const ex of def.examples) {
|
|
173
|
+
help += `\`${ex.cmd}\`\n${ex.desc}\n\n`;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return help;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Create a command registry.
|
|
183
|
+
*/
|
|
184
|
+
export function createCommandRegistry(): CommandRegistry {
|
|
185
|
+
return new CommandRegistry();
|
|
186
|
+
}
|