pi-cicd 1.0.3 → 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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-cicd",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "Extension for Pi coding agent",
5
5
  "type": "module",
6
6
  "main": "./index.ts",
@@ -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
+ }