@pikku/core 0.9.10 → 0.9.12-next.0

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 (100) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/function/function-runner.d.ts +13 -8
  3. package/dist/function/function-runner.js +49 -37
  4. package/dist/index.d.ts +3 -1
  5. package/dist/index.js +3 -1
  6. package/dist/middleware-runner.d.ts +61 -40
  7. package/dist/middleware-runner.js +118 -66
  8. package/dist/permissions.js +1 -0
  9. package/dist/pikku-state.d.ts +26 -1
  10. package/dist/pikku-state.js +10 -1
  11. package/dist/services/content-service.d.ts +2 -3
  12. package/dist/services/index.d.ts +0 -1
  13. package/dist/services/index.js +0 -1
  14. package/dist/services/local-content.d.ts +2 -4
  15. package/dist/services/local-content.js +2 -2
  16. package/dist/types/core.types.d.ts +51 -2
  17. package/dist/types/core.types.js +21 -0
  18. package/dist/wirings/channel/channel-handler.d.ts +2 -2
  19. package/dist/wirings/channel/channel-handler.js +12 -9
  20. package/dist/wirings/channel/channel-runner.d.ts +0 -2
  21. package/dist/wirings/channel/channel-runner.js +2 -3
  22. package/dist/wirings/channel/channel.types.d.ts +5 -3
  23. package/dist/wirings/channel/local/local-channel-runner.js +12 -12
  24. package/dist/wirings/channel/serverless/serverless-channel-runner.js +7 -8
  25. package/dist/wirings/cli/channel/cli-channel-runner.d.ts +12 -0
  26. package/dist/wirings/cli/channel/cli-channel-runner.js +80 -0
  27. package/dist/wirings/cli/channel/index.d.ts +1 -0
  28. package/dist/wirings/cli/channel/index.js +1 -0
  29. package/dist/wirings/cli/cli-runner.d.ts +32 -0
  30. package/dist/wirings/cli/cli-runner.js +328 -0
  31. package/dist/wirings/cli/cli.types.d.ts +177 -0
  32. package/dist/wirings/cli/cli.types.js +1 -0
  33. package/dist/wirings/cli/command-parser.d.ts +19 -0
  34. package/dist/wirings/cli/command-parser.js +373 -0
  35. package/dist/wirings/cli/index.d.ts +5 -0
  36. package/dist/wirings/cli/index.js +5 -0
  37. package/dist/wirings/http/http-runner.d.ts +29 -10
  38. package/dist/wirings/http/http-runner.js +103 -131
  39. package/dist/wirings/http/http.types.d.ts +10 -10
  40. package/dist/wirings/http/index.d.ts +1 -1
  41. package/dist/wirings/http/index.js +1 -1
  42. package/dist/wirings/http/pikku-fetch-http-response.js +3 -1
  43. package/dist/wirings/http/routers/http-router.d.ts +0 -2
  44. package/dist/wirings/http/routers/path-to-regex.d.ts +1 -1
  45. package/dist/wirings/http/routers/path-to-regex.js +5 -34
  46. package/dist/wirings/mcp/mcp-runner.d.ts +4 -5
  47. package/dist/wirings/mcp/mcp-runner.js +30 -34
  48. package/dist/wirings/mcp/mcp.types.d.ts +11 -8
  49. package/dist/wirings/queue/queue-runner.d.ts +2 -2
  50. package/dist/wirings/queue/queue-runner.js +25 -27
  51. package/dist/wirings/queue/queue.types.d.ts +6 -5
  52. package/dist/wirings/rpc/index.d.ts +1 -1
  53. package/dist/wirings/rpc/index.js +1 -1
  54. package/dist/wirings/rpc/rpc-runner.d.ts +6 -18
  55. package/dist/wirings/rpc/rpc-runner.js +13 -8
  56. package/dist/wirings/scheduler/scheduler-runner.d.ts +2 -2
  57. package/dist/wirings/scheduler/scheduler-runner.js +37 -35
  58. package/dist/wirings/scheduler/scheduler.types.d.ts +4 -3
  59. package/package.json +4 -3
  60. package/src/function/function-runner.test.ts +73 -23
  61. package/src/function/function-runner.ts +74 -55
  62. package/src/index.ts +8 -1
  63. package/src/middleware-runner.test.ts +24 -16
  64. package/src/middleware-runner.ts +136 -83
  65. package/src/permissions.ts +1 -0
  66. package/src/pikku-state.ts +47 -2
  67. package/src/services/content-service.ts +5 -4
  68. package/src/services/index.ts +0 -1
  69. package/src/services/local-content.ts +11 -6
  70. package/src/types/core.types.ts +74 -3
  71. package/src/wirings/channel/channel-handler.ts +9 -13
  72. package/src/wirings/channel/channel-runner.ts +2 -6
  73. package/src/wirings/channel/channel.types.ts +5 -1
  74. package/src/wirings/channel/local/local-channel-runner.ts +25 -15
  75. package/src/wirings/channel/serverless/serverless-channel-runner.ts +15 -17
  76. package/src/wirings/cli/channel/cli-channel-runner.ts +118 -0
  77. package/src/wirings/cli/channel/index.ts +1 -0
  78. package/src/wirings/cli/cli-runner.test.ts +382 -0
  79. package/src/wirings/cli/cli-runner.ts +503 -0
  80. package/src/wirings/cli/cli.types.ts +320 -0
  81. package/src/wirings/cli/command-parser.test.ts +440 -0
  82. package/src/wirings/cli/command-parser.ts +470 -0
  83. package/src/wirings/cli/index.ts +12 -0
  84. package/src/wirings/http/http-runner.test.ts +8 -7
  85. package/src/wirings/http/http-runner.ts +126 -159
  86. package/src/wirings/http/http.types.ts +56 -11
  87. package/src/wirings/http/index.ts +1 -1
  88. package/src/wirings/http/pikku-fetch-http-response.ts +3 -1
  89. package/src/wirings/http/routers/http-router.ts +0 -2
  90. package/src/wirings/http/routers/path-to-regex.test.ts +4 -5
  91. package/src/wirings/http/routers/path-to-regex.ts +6 -43
  92. package/src/wirings/mcp/mcp-runner.ts +56 -55
  93. package/src/wirings/mcp/mcp.types.ts +23 -8
  94. package/src/wirings/queue/queue-runner.ts +44 -47
  95. package/src/wirings/queue/queue.types.ts +10 -6
  96. package/src/wirings/rpc/index.ts +1 -1
  97. package/src/wirings/rpc/rpc-runner.ts +27 -9
  98. package/src/wirings/scheduler/scheduler-runner.ts +57 -56
  99. package/src/wirings/scheduler/scheduler.types.ts +9 -2
  100. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,328 @@
1
+ import { NotFoundError } from '../../errors/errors.js';
2
+ import { addFunction, runPikkuFunc } from '../../function/function-runner.js';
3
+ import { pikkuState } from '../../pikku-state.js';
4
+ import { PikkuWiringTypes, } from '../../types/core.types.js';
5
+ import { closeSessionServices } from '../../utils.js';
6
+ import { rpcService } from '../rpc/rpc-runner.js';
7
+ import { PikkuUserSessionService } from '../../services/user-session-service.js';
8
+ import { LocalVariablesService } from '../../services/local-variables.js';
9
+ import { generateCommandHelp, parseCLIArguments } from './command-parser.js';
10
+ /**
11
+ * Default JSON renderer for CLI output
12
+ */
13
+ const defaultJSONRenderer = (_services, data) => {
14
+ console.log(JSON.stringify(data, null, 2));
15
+ };
16
+ /**
17
+ * Registers a CLI command tree and all its functions
18
+ */
19
+ export const wireCLI = (cli) => {
20
+ // Get the existing metadata that was generated during inspection
21
+ const cliMeta = pikkuState('cli', 'meta') || {};
22
+ if (!cliMeta[cli.program]) {
23
+ throw new Error(`CLI metadata not found for program '${cli.program}'. Did you run 'pikku all'?`);
24
+ }
25
+ // Get existing programs state and add this program
26
+ const programs = pikkuState('cli', 'programs') || {};
27
+ programs[cli.program] = {
28
+ defaultRenderer: (cli.render ||
29
+ defaultJSONRenderer),
30
+ middleware: cli.middleware || [],
31
+ renderers: {},
32
+ tags: cli.tags,
33
+ };
34
+ pikkuState('cli', 'programs', programs);
35
+ // Register all command functions recursively
36
+ registerCLICommands(cli.commands, [], cli.options || {}, cli.program);
37
+ };
38
+ /**
39
+ * Unwraps a function from pikku wrappers (pikkuFunc, pikkuSessionlessFunc, etc.)
40
+ * These wrappers return { func, middleware, ... } but we need the actual function
41
+ */
42
+ function unwrapFunc(command) {
43
+ if (typeof command === 'function') {
44
+ return { func: command };
45
+ }
46
+ // If command has a func property that's an object with func, unwrap it
47
+ if (command.func &&
48
+ typeof command.func === 'object' &&
49
+ 'func' in command.func) {
50
+ return {
51
+ func: command.func.func,
52
+ middleware: command.func.middleware,
53
+ auth: command.func.auth,
54
+ permissions: command.func.permissions,
55
+ tags: command.func.tags,
56
+ };
57
+ }
58
+ // Otherwise return as-is
59
+ return command;
60
+ }
61
+ /**
62
+ * Registers CLI commands and their functions recursively
63
+ */
64
+ function registerCLICommands(commands, path = [], inheritedOptions = {}, program) {
65
+ // Get the CLI metadata to find actual function names
66
+ const cliMeta = pikkuState('cli', 'meta')[program];
67
+ for (const [name, command] of Object.entries(commands)) {
68
+ const fullPath = [...path, name];
69
+ const commandId = fullPath.join('.');
70
+ // Navigate metadata to find the actual function name
71
+ let currentMeta = cliMeta?.commands[fullPath[0]];
72
+ for (let i = 1; i < fullPath.length; i++) {
73
+ currentMeta = currentMeta?.subcommands?.[fullPath[i]];
74
+ }
75
+ const funcName = currentMeta?.pikkuFuncName;
76
+ // Skip if no function name (could be a command group)
77
+ if (!funcName) {
78
+ // Recursively register subcommands if they exist
79
+ if (typeof command === 'object' && command.subcommands) {
80
+ const commandOptions = command.options || {};
81
+ const mergedOptions = { ...inheritedOptions, ...commandOptions };
82
+ registerCLICommands(command.subcommands, fullPath, mergedOptions, program);
83
+ }
84
+ continue;
85
+ }
86
+ // Merge options (inherited + local)
87
+ const commandOptions = typeof command === 'object' ? command.options || {} : {};
88
+ const mergedOptions = { ...inheritedOptions, ...commandOptions };
89
+ // Store the options and middleware in program state for use during execution
90
+ const programs = pikkuState('cli', 'programs');
91
+ if (programs[program]) {
92
+ if (!programs[program].commandOptions) {
93
+ programs[program].commandOptions = {};
94
+ }
95
+ programs[program].commandOptions[commandId] = mergedOptions;
96
+ // Store command middleware from the wire config
97
+ if (typeof command === 'object' && command.middleware) {
98
+ if (!programs[program].commandMiddleware) {
99
+ programs[program].commandMiddleware = {};
100
+ }
101
+ programs[program].commandMiddleware[commandId] = command.middleware;
102
+ }
103
+ }
104
+ addFunction(funcName, unwrapFunc(command));
105
+ // Register renderer if provided
106
+ if (typeof command === 'object' && command.render) {
107
+ if (programs[program]) {
108
+ programs[program].renderers[commandId] = command.render;
109
+ }
110
+ }
111
+ // Recursively register subcommands
112
+ if (typeof command === 'object' && command.subcommands) {
113
+ registerCLICommands(command.subcommands, fullPath, mergedOptions, program);
114
+ }
115
+ }
116
+ }
117
+ /**
118
+ * Plucks only the data that the function expects based on its schema
119
+ */
120
+ function pluckCLIData(mergedData, funcName, availableOptions) {
121
+ const funcMeta = pikkuState('function', 'meta')[funcName];
122
+ const schemaName = funcMeta?.inputSchemaName;
123
+ const schema = schemaName
124
+ ? pikkuState('misc', 'schemas').get(schemaName)
125
+ : null;
126
+ if (schema && schema.properties) {
127
+ // If we have a schema, only include fields that are in the schema
128
+ const result = {};
129
+ for (const key of Object.keys(schema.properties)) {
130
+ if (key in mergedData) {
131
+ result[key] = mergedData[key];
132
+ }
133
+ else if (availableOptions[key]?.default !== undefined) {
134
+ // Apply default if not provided
135
+ result[key] = availableOptions[key].default;
136
+ }
137
+ }
138
+ return result;
139
+ }
140
+ else {
141
+ // No schema, include all data
142
+ return { ...mergedData };
143
+ }
144
+ }
145
+ /**
146
+ * Executes a CLI command for a specific program
147
+ */
148
+ export async function runCLICommand({ program, commandPath, data, singletonServices, createSessionServices, }) {
149
+ // Get the command metadata to find the function name
150
+ const cliMeta = pikkuState('cli', 'meta');
151
+ const programMeta = cliMeta[program];
152
+ if (!programMeta) {
153
+ throw new NotFoundError(`Program not found: ${program}`);
154
+ }
155
+ // Navigate command tree to find the function name
156
+ let currentCommand = programMeta.commands[commandPath[0]];
157
+ if (!currentCommand) {
158
+ throw new NotFoundError(`Command not found: ${commandPath.join(' ')}`);
159
+ }
160
+ for (let i = 1; i < commandPath.length; i++) {
161
+ if (!currentCommand.subcommands ||
162
+ !currentCommand.subcommands[commandPath[i]]) {
163
+ throw new NotFoundError(`Command not found: ${commandPath.join(' ')}`);
164
+ }
165
+ currentCommand = currentCommand.subcommands[commandPath[i]];
166
+ }
167
+ const funcName = currentCommand.pikkuFuncName;
168
+ // Get program-specific data
169
+ const programs = pikkuState('cli', 'programs') || {};
170
+ const programData = programs[program];
171
+ // Combine program middleware + command middleware from the hierarchy
172
+ const allWireMiddleware = [
173
+ ...(programData?.middleware || []),
174
+ ];
175
+ // Walk through the command path and collect middleware from the runtime config
176
+ const commandParts = [];
177
+ for (const part of commandPath) {
178
+ commandParts.push(part);
179
+ const commandId = commandParts.join('.');
180
+ const middleware = programData?.commandMiddleware?.[commandId];
181
+ if (middleware) {
182
+ allWireMiddleware.push(...middleware);
183
+ }
184
+ }
185
+ // Get command ID and options
186
+ const commandId = commandPath.join('.');
187
+ const availableOptions = programData?.commandOptions?.[commandId] || {};
188
+ // Pluck only the fields the function expects
189
+ const pluckedData = () => pluckCLIData(data, funcName, availableOptions);
190
+ // Get the renderer
191
+ const renderer = programData?.renderers[commandId] || programData?.defaultRenderer;
192
+ // Create a CLI channel for progressive output
193
+ const channel = {
194
+ channelId: `cli:${program}:${commandId}`,
195
+ openingData: pluckedData,
196
+ send: async (data) => {
197
+ if (renderer) {
198
+ await Promise.resolve(renderer(singletonServices, data, undefined));
199
+ }
200
+ },
201
+ close: () => {
202
+ if (channel) {
203
+ channel.state = 'closed';
204
+ }
205
+ },
206
+ state: 'open',
207
+ };
208
+ const userSession = new PikkuUserSessionService();
209
+ let sessionServices;
210
+ const interaction = {
211
+ cli: {
212
+ program,
213
+ command: commandPath,
214
+ data: pluckedData,
215
+ channel,
216
+ },
217
+ };
218
+ const getAllServices = async (session) => {
219
+ // Create session-specific services for handling the command
220
+ sessionServices = await createSessionServices?.(singletonServices, interaction, session);
221
+ return rpcService.injectRPCService({
222
+ ...singletonServices,
223
+ ...sessionServices,
224
+ userSession,
225
+ channel,
226
+ }, interaction, false);
227
+ };
228
+ // Build inherited middleware from tags
229
+ const inheritedMiddleware = [];
230
+ if (programData?.tags) {
231
+ for (const tag of programData.tags) {
232
+ inheritedMiddleware.push({ type: 'tag', tag });
233
+ }
234
+ }
235
+ try {
236
+ const result = await runPikkuFunc(PikkuWiringTypes.cli, commandId, funcName, {
237
+ singletonServices,
238
+ getAllServices,
239
+ data: pluckedData,
240
+ auth: false,
241
+ userSession,
242
+ inheritedMiddleware,
243
+ wireMiddleware: allWireMiddleware,
244
+ interaction,
245
+ });
246
+ // Apply renderer one final time with the final output (if renderer exists)
247
+ if (renderer) {
248
+ await Promise.resolve(renderer(singletonServices, result, userSession.get()));
249
+ }
250
+ return result;
251
+ }
252
+ finally {
253
+ // Close the channel
254
+ channel.close();
255
+ // Clean up session services
256
+ if (sessionServices) {
257
+ await closeSessionServices(singletonServices.logger, sessionServices);
258
+ }
259
+ }
260
+ }
261
+ /**
262
+ * Factory function for CLI-specific renderers
263
+ */
264
+ export const pikkuCLIRender = (renderer) => {
265
+ return renderer;
266
+ };
267
+ /**
268
+ * Execute a CLI program with the given arguments
269
+ * This is the main entry point for CLI programs
270
+ */
271
+ export async function executeCLI({ programName, args = process.argv.slice(2), createConfig, createSingletonServices, createSessionServices, }) {
272
+ try {
273
+ // Get CLI metadata from state
274
+ const allCLIMeta = pikkuState('cli', 'meta') || {};
275
+ const programMeta = allCLIMeta[programName];
276
+ if (!programMeta) {
277
+ console.error(`Error: CLI program "${programName}" not found`);
278
+ process.exit(1);
279
+ }
280
+ // Parse arguments for this specific program
281
+ const parsed = parseCLIArguments(args, programName, allCLIMeta);
282
+ // Handle help (check after parsing to support subcommand help)
283
+ if (args.includes('--help') || args.includes('-h') || args.length === 0) {
284
+ const helpText = generateCommandHelp(programName, allCLIMeta, parsed.commandPath);
285
+ console.log(helpText);
286
+ return;
287
+ }
288
+ if (parsed.errors.length > 0) {
289
+ // Check if any error is about an unknown command
290
+ const hasUnknownCommand = parsed.errors.some((error) => error.startsWith('Unknown command:') ||
291
+ error.startsWith('Command not found:'));
292
+ if (hasUnknownCommand) {
293
+ // Show help instead of error for unknown commands
294
+ const helpText = generateCommandHelp(programName, allCLIMeta, parsed.commandPath);
295
+ console.log(helpText);
296
+ process.exit(1);
297
+ }
298
+ else {
299
+ // Show errors for other types of errors
300
+ console.error('Errors:');
301
+ parsed.errors.forEach((error) => console.error(` ${error}`));
302
+ process.exit(1);
303
+ }
304
+ }
305
+ // Merge positionals and options into single data object
306
+ const data = { ...parsed.positionals, ...parsed.options };
307
+ // Create config (pass data in case it needs to use any parsed options)
308
+ const config = await createConfig(new LocalVariablesService(), data);
309
+ // Create services with config
310
+ const singletonServices = await createSingletonServices(config);
311
+ // Execute the command
312
+ await runCLICommand({
313
+ program: programName,
314
+ commandPath: parsed.commandPath,
315
+ data,
316
+ singletonServices,
317
+ createSessionServices,
318
+ });
319
+ }
320
+ catch (error) {
321
+ console.error('Error:', error);
322
+ // Show stack trace in verbose mode
323
+ if (args.includes('--verbose') || args.includes('-v')) {
324
+ console.error('Stack trace:', error.stack);
325
+ }
326
+ process.exit(1);
327
+ }
328
+ }
@@ -0,0 +1,177 @@
1
+ import { CorePikkuMiddleware, CoreSingletonServices, CoreUserSession, PikkuDocs, CoreServices, MiddlewareMetadata } from '../../types/core.types.js';
2
+ import { CorePikkuFunctionConfig, CorePikkuPermission, CorePikkuFunction, CorePikkuFunctionSessionless } from '../../function/functions.types.js';
3
+ import { PikkuChannel } from '../channel/channel.types.js';
4
+ /**
5
+ * CLI option definition
6
+ */
7
+ export interface CLIOption<T = any> {
8
+ description: string;
9
+ short?: string;
10
+ default?: T;
11
+ choices?: T[];
12
+ array?: boolean;
13
+ required?: boolean;
14
+ }
15
+ /**
16
+ * CLI options collection
17
+ */
18
+ export type CLIOptions<T> = {
19
+ [K in keyof T]: CLIOption<T[K]>;
20
+ };
21
+ /**
22
+ * Positional argument definition
23
+ */
24
+ export interface CLIPositional {
25
+ name: string;
26
+ required: boolean;
27
+ variadic?: boolean;
28
+ }
29
+ /**
30
+ * CLI interaction context
31
+ */
32
+ export type PikkuCLI = {
33
+ program: string;
34
+ command: string[];
35
+ data: Record<string, any>;
36
+ channel: PikkuChannel<unknown, unknown>;
37
+ };
38
+ /**
39
+ * Runtime CLI program state
40
+ */
41
+ export interface CLIProgramState {
42
+ defaultRenderer?: CorePikkuCLIRender<any>;
43
+ middleware: CorePikkuMiddleware[];
44
+ renderers: Record<string, CorePikkuCLIRender<any>>;
45
+ commandOptions?: Record<string, Record<string, CLIOption>>;
46
+ commandMiddleware?: Record<string, CorePikkuMiddleware[]>;
47
+ tags?: string[];
48
+ }
49
+ /**
50
+ * CLI command metadata for runtime
51
+ */
52
+ export interface CLICommandMeta {
53
+ parameters?: string;
54
+ pikkuFuncName: string;
55
+ positionals: CLIPositional[];
56
+ options: Record<string, CLIOption>;
57
+ renderName?: string;
58
+ description?: string;
59
+ docs?: PikkuDocs;
60
+ tags?: string[];
61
+ subcommands?: Record<string, CLICommandMeta>;
62
+ middleware?: MiddlewareMetadata[];
63
+ }
64
+ /**
65
+ * CLI metadata collection (per program)
66
+ */
67
+ export type CLIProgramMeta = {
68
+ program: string;
69
+ commands: Record<string, CLICommandMeta>;
70
+ options: Record<string, CLIOption>;
71
+ defaultRenderName?: string;
72
+ };
73
+ /**
74
+ * All CLI programs metadata
75
+ */
76
+ export type CLIMeta = Record<string, CLIProgramMeta>;
77
+ /**
78
+ * CLI-specific renderer that outputs to console
79
+ */
80
+ export type CorePikkuCLIRender<Data, Services extends CoreSingletonServices = CoreServices, Session extends CoreUserSession = CoreUserSession> = CorePikkuRender<Data, void, Services, Session>;
81
+ /**
82
+ * Extract input parameters from a Pikku function config type
83
+ */
84
+ export type ExtractFunctionInput<Func> = Func extends CorePikkuFunctionConfig<infer FuncType> ? FuncType extends CorePikkuFunction<infer Input, any, any, any, any> | CorePikkuFunctionSessionless<infer Input, any, any, any, any> ? Input : never : never;
85
+ /**
86
+ * Strip < > [ ] characters from a string
87
+ */
88
+ type StripBrackets<S extends string> = S extends `<${infer Inner}>` ? Inner : S extends `[${infer Inner}]` ? Inner : S;
89
+ /**
90
+ * Split string by spaces
91
+ */
92
+ type SplitBySpace<S extends string> = S extends `${infer First} ${infer Rest}` ? [First, ...SplitBySpace<Rest>] : S extends '' ? [] : [S];
93
+ /**
94
+ * Extract parameter names from CLI parameter string
95
+ * Example: "<env> [region]" => ["env", "region"]
96
+ */
97
+ type ExtractParameterNames<S extends string> = {
98
+ [K in keyof SplitBySpace<S>]: SplitBySpace<S>[K] extends string ? StripBrackets<SplitBySpace<S>[K]> : never;
99
+ };
100
+ /**
101
+ * Validate that all parameter names are valid keys of the function input
102
+ */
103
+ export type ValidateParameters<Params extends string, Input> = ExtractParameterNames<Params> extends (infer P)[] ? P extends keyof Input ? Params : never : never;
104
+ /**
105
+ * Extract output type from a Pikku function config type
106
+ */
107
+ export type ExtractFunctionOutput<Func> = Func extends CorePikkuFunctionConfig<infer FuncType> ? FuncType extends CorePikkuFunction<any, infer Output, any, any, any> | CorePikkuFunctionSessionless<any, infer Output, any, any, any> ? Output : never : never;
108
+ /**
109
+ * CLI command configuration that infers options from function input type.
110
+ * This is a helper type for creating type-safe CLI commands.
111
+ */
112
+ export interface CoreCLICommandConfig<Func, PikkuMiddleware extends CorePikkuMiddleware<any> = CorePikkuMiddleware<any>, PikkuCLIRender extends CorePikkuCLIRender<any, any, any> = CorePikkuCLIRender<any, any>> {
113
+ parameters?: ValidateParameters<string, ExtractFunctionInput<Func>>;
114
+ func?: Func;
115
+ description?: string;
116
+ render?: PikkuCLIRender;
117
+ options?: Partial<Record<keyof ExtractFunctionInput<Func>, {
118
+ description?: string;
119
+ short?: string;
120
+ default?: ExtractFunctionInput<Func>[keyof ExtractFunctionInput<Func>];
121
+ }>> & Record<string, {
122
+ description?: string;
123
+ short?: string;
124
+ default?: any;
125
+ }>;
126
+ middleware?: PikkuMiddleware[];
127
+ subcommands?: Record<string, CoreCLICommandConfig<any, PikkuMiddleware, PikkuCLIRender>>;
128
+ auth?: boolean;
129
+ permissions?: any[];
130
+ }
131
+ /**
132
+ * CLI command definition
133
+ */
134
+ export interface CoreCLICommand<In, Out, PikkuFunction extends CorePikkuFunctionConfig<CorePikkuFunction<In, Out, any, any, any> | CorePikkuFunctionSessionless<In, Out, any, any, any>>, PikkuPermission extends CorePikkuPermission<any, any, any>, PikkuMiddleware extends CorePikkuMiddleware, Options = any, Subcommands extends Record<string, CoreCLICommandConfig<any, any, any>> = Record<string, CoreCLICommandConfig<any, any, any>>> {
135
+ parameters?: string;
136
+ func: PikkuFunction;
137
+ render?: CorePikkuCLIRender<Out>;
138
+ description?: string;
139
+ options?: CLIOptions<Options>;
140
+ middleware?: PikkuMiddleware[];
141
+ permissions?: Record<string, PikkuPermission | PikkuPermission[]>;
142
+ auth?: boolean;
143
+ docs?: PikkuDocs;
144
+ subcommands?: Subcommands;
145
+ }
146
+ /**
147
+ * Shorthand command definition (just a function)
148
+ */
149
+ export type CLICommandShorthand<In, Out, PikkuFunction extends CorePikkuFunctionConfig<CorePikkuFunction<In, Out, any, any, any> | CorePikkuFunctionSessionless<In, Out, any, any, any>>> = PikkuFunction;
150
+ /**
151
+ * Command definition (either full or shorthand)
152
+ */
153
+ export type CLICommandDefinition<In, Out, PikkuFunction extends CorePikkuFunctionConfig<CorePikkuFunction<In, Out, any, any, any> | CorePikkuFunctionSessionless<In, Out, any, any, any>>, PikkuPermission extends CorePikkuPermission<any, any, any>, PikkuMiddleware extends CorePikkuMiddleware, Options = any, Subcommands extends Record<string, CoreCLICommandConfig<any, any, any>> = Record<string, CoreCLICommandConfig<any, any, any>>> = CoreCLICommand<In, Out, PikkuFunction, PikkuPermission, PikkuMiddleware, Options, Subcommands> | CLICommandShorthand<In, Out, PikkuFunction>;
154
+ /**
155
+ * CLI wiring configuration
156
+ */
157
+ export interface CoreCLI<Commands extends Record<string, CoreCLICommandConfig<any, any, any>>, Options, PikkuMiddleware, PikkuCLIRender> {
158
+ program: string;
159
+ description?: string;
160
+ commands: Commands;
161
+ options?: CLIOptions<Options>;
162
+ middleware?: PikkuMiddleware[];
163
+ render?: PikkuCLIRender;
164
+ docs?: PikkuDocs;
165
+ tags?: string[];
166
+ }
167
+ /**
168
+ * Generic renderer type that can transform data into any output format.
169
+ * Can be used across different wirings for flexible output handling.
170
+ *
171
+ * @template Data - The input data type to be rendered
172
+ * @template Output - The output type after rendering
173
+ * @template Services - The services available to the renderer
174
+ * @template Session - The user session type
175
+ */
176
+ export type CorePikkuRender<Data, Output, Services extends CoreSingletonServices = CoreServices, Session extends CoreUserSession = CoreUserSession> = (services: Services, data: Data, session?: Session) => Output | Promise<Output>;
177
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,19 @@
1
+ import { CLIMeta } from './cli.types.js';
2
+ /**
3
+ * Result of parsing CLI arguments
4
+ */
5
+ export interface ParsedCommand {
6
+ program: string;
7
+ commandPath: string[];
8
+ positionals: Record<string, any>;
9
+ options: Record<string, any>;
10
+ errors: string[];
11
+ }
12
+ /**
13
+ * Parses raw CLI arguments into structured data for a specific program
14
+ */
15
+ export declare function parseCLIArguments(args: string[], programName: string, allMeta: CLIMeta): ParsedCommand;
16
+ /**
17
+ * Generates help text for a command in a specific program
18
+ */
19
+ export declare function generateCommandHelp(programName: string, allMeta: CLIMeta, commandPath?: string[]): string;