@kb-labs/shared-command-kit 1.0.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.
- package/LICENSE +22 -0
- package/README.md +1030 -0
- package/dist/analytics/index.d.ts +111 -0
- package/dist/analytics/index.js +56 -0
- package/dist/analytics/index.js.map +1 -0
- package/dist/errors/index.d.ts +227 -0
- package/dist/errors/index.js +276 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/flags/index.d.ts +196 -0
- package/dist/flags/index.js +288 -0
- package/dist/flags/index.js.map +1 -0
- package/dist/helpers/index.d.ts +650 -0
- package/dist/helpers/index.js +274 -0
- package/dist/helpers/index.js.map +1 -0
- package/dist/index.d.ts +1696 -0
- package/dist/index.js +1543 -0
- package/dist/index.js.map +1 -0
- package/dist/studio/index.js +178 -0
- package/dist/studio/index.js.map +1 -0
- package/package.json +76 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,1696 @@
|
|
|
1
|
+
import { PluginContextV3, ManifestV3, PermissionSpec, JobDecl, CommandResult as CommandResult$1, HostContext, WSMessage, WSSender, WSInput } from '@kb-labs/plugin-contracts';
|
|
2
|
+
export { PluginContextV3 } from '@kb-labs/plugin-contracts';
|
|
3
|
+
import { FlagSchemaDefinition as FlagSchemaDefinition$1, InferFlags } from './flags/index.js';
|
|
4
|
+
export { ArrayFlagSchema, BaseFlagSchema, BooleanFlagSchema, FlagSchema, FlagSchemaWithInfer, FlagType, FlagValidationError, NumberFlagSchema, SafeValidationResult, StringFlagSchema, ValidationResult, defineFlags, validateFlags, validateFlagsSafe } from './flags/index.js';
|
|
5
|
+
export { AnalyticsContext, AnalyticsEvents, createAnalyticsWrapper, trackEvent, withAnalytics } from './analytics/index.js';
|
|
6
|
+
export { ErrorDefinition, ErrorDefinitions, FormatErrorOptions, FormattedError, PluginError, commonErrors, defineError, formatError } from './errors/index.js';
|
|
7
|
+
export { getLLMTier, isCacheAvailable, isEmbeddingsAvailable, isLLMAvailable, isPlatformConfigured, isVectorStoreAvailable, trackAnalyticsEvent, useAnalytics, useCache, useConfig, useEmbeddings, useLLM, useLogger, useLoggerWithContext, usePlatform, useStorage, useVectorStore } from './helpers/index.js';
|
|
8
|
+
import { z } from 'zod';
|
|
9
|
+
export { CommandOutput } from '@kb-labs/shared-cli-ui';
|
|
10
|
+
export { LLMTier, UseLLMOptions } from '@kb-labs/core-platform';
|
|
11
|
+
import '@kb-labs/core-runtime';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @module @kb-labs/shared-command-kit
|
|
15
|
+
* System Command Definition - For KB Labs official commands with full privileges
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Flag definition for Command interface
|
|
20
|
+
*/
|
|
21
|
+
interface FlagDefinition {
|
|
22
|
+
name: string;
|
|
23
|
+
type: 'string' | 'boolean' | 'number' | 'array';
|
|
24
|
+
alias?: string;
|
|
25
|
+
description?: string;
|
|
26
|
+
default?: unknown;
|
|
27
|
+
required?: boolean;
|
|
28
|
+
choices?: string[];
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Command definition for system commands
|
|
32
|
+
*/
|
|
33
|
+
interface Command {
|
|
34
|
+
name: string;
|
|
35
|
+
describe: string;
|
|
36
|
+
longDescription?: string;
|
|
37
|
+
category?: string;
|
|
38
|
+
aliases?: string[];
|
|
39
|
+
flags?: FlagDefinition[];
|
|
40
|
+
examples?: string[];
|
|
41
|
+
run: (ctx: PluginContextV3, argv: string[], flags: Record<string, unknown>) => Promise<number>;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Command group definition
|
|
45
|
+
*/
|
|
46
|
+
interface CommandGroup {
|
|
47
|
+
name: string;
|
|
48
|
+
describe: string;
|
|
49
|
+
commands: Command[];
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Extended command config for system commands
|
|
53
|
+
*
|
|
54
|
+
* All type parameters are optional - use them when you want type safety, skip them for simplicity.
|
|
55
|
+
*
|
|
56
|
+
* TFlags can be inferred from the flags schema, but can also be explicitly provided
|
|
57
|
+
* for better type inference in complex cases.
|
|
58
|
+
*
|
|
59
|
+
* TResult must extend CommandResult (requires ok: boolean field).
|
|
60
|
+
*/
|
|
61
|
+
interface SystemCommandConfig<TFlags extends FlagSchemaDefinition$1 = FlagSchemaDefinition$1, TResult extends CommandResult = CommandResult, TArgv extends readonly string[] = string[]> {
|
|
62
|
+
/** Command name (required for system commands) */
|
|
63
|
+
name: string;
|
|
64
|
+
/** Command description (required for system commands) */
|
|
65
|
+
description: string;
|
|
66
|
+
/** Long description for help */
|
|
67
|
+
longDescription?: string;
|
|
68
|
+
/** Category (defaults to 'system') */
|
|
69
|
+
category?: string;
|
|
70
|
+
/** Command aliases */
|
|
71
|
+
aliases?: string[];
|
|
72
|
+
/** Usage examples */
|
|
73
|
+
examples?: string[];
|
|
74
|
+
/** Flag schema definition - TypeScript will infer TFlags from this */
|
|
75
|
+
flags: TFlags;
|
|
76
|
+
/**
|
|
77
|
+
* Analytics configuration (legacy field, kept for backward compatibility)
|
|
78
|
+
* Use ctx.platform.analytics.track() or withAnalytics() helper instead
|
|
79
|
+
*/
|
|
80
|
+
analytics?: {
|
|
81
|
+
command?: string;
|
|
82
|
+
startEvent?: string;
|
|
83
|
+
finishEvent?: string;
|
|
84
|
+
actor?: string;
|
|
85
|
+
context?: Record<string, unknown>;
|
|
86
|
+
includeFlags?: boolean;
|
|
87
|
+
};
|
|
88
|
+
/** Command handler - receives PluginContextV3 and must return TResult */
|
|
89
|
+
handler: (ctx: PluginContextV3, argv: TArgv, flags: InferFlags<TFlags>) => Promise<number | TResult> | number | TResult;
|
|
90
|
+
/** Optional formatter - receives TResult with inferred flags */
|
|
91
|
+
formatter?: (result: TResult, ctx: PluginContextV3, flags: InferFlags<TFlags>, argv?: TArgv) => void;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Define a system command with full privileges
|
|
95
|
+
*
|
|
96
|
+
* System commands are KB Labs official commands that run with full system access,
|
|
97
|
+
* bypassing sandbox restrictions. They are architecturally separated from plugin
|
|
98
|
+
* commands - plugins can NEVER gain system privileges.
|
|
99
|
+
*
|
|
100
|
+
* TResult is REQUIRED - every command must explicitly declare its result contract.
|
|
101
|
+
* This ensures type safety and enables future contract validation.
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* ```typescript
|
|
105
|
+
* import { defineSystemCommand, type CommandResult, type FlagSchemaDefinition } from '@kb-labs/shared-command-kit';
|
|
106
|
+
*
|
|
107
|
+
* // Simple command with automatic flag type inference (RECOMMENDED)
|
|
108
|
+
* export const helloCommand = defineSystemCommand<CommandResult & { message: string }>({
|
|
109
|
+
* name: 'hello',
|
|
110
|
+
* description: 'Print a friendly greeting',
|
|
111
|
+
* category: 'system',
|
|
112
|
+
* flags: {
|
|
113
|
+
* name: { type: 'string', description: 'Name to greet' },
|
|
114
|
+
* json: { type: 'boolean', default: false },
|
|
115
|
+
* } satisfies FlagSchemaDefinition, // Preserves literal types for type inference
|
|
116
|
+
* async handler(ctx, argv, flags) {
|
|
117
|
+
* // ctx is EnhancedCliContext (extends PluginContextV3)
|
|
118
|
+
* // ctx.cwd - working directory (V2 promoted field)
|
|
119
|
+
* // ctx.ui - UI output API with new convenience methods
|
|
120
|
+
* // flags.name is inferred as string | undefined
|
|
121
|
+
* const message = `Hello, ${flags.name || 'World'}!`;
|
|
122
|
+
*
|
|
123
|
+
* // UI output (CLI only, no-op in REST/Workflow)
|
|
124
|
+
* if (!flags.json) {
|
|
125
|
+
* if (ctx.ui?.success) {
|
|
126
|
+
* ctx.ui.success('Greeting', [
|
|
127
|
+
* { items: [message] },
|
|
128
|
+
* ]);
|
|
129
|
+
* }
|
|
130
|
+
* } else {
|
|
131
|
+
* ctx.ui?.json({ message });
|
|
132
|
+
* }
|
|
133
|
+
*
|
|
134
|
+
* return { ok: true, message };
|
|
135
|
+
* },
|
|
136
|
+
* });
|
|
137
|
+
*
|
|
138
|
+
* // Command with explicit result type and automatic flag inference
|
|
139
|
+
* type WorkflowListResult = CommandResult & {
|
|
140
|
+
* workflows: Array<{ id: string }>;
|
|
141
|
+
* total: number;
|
|
142
|
+
* };
|
|
143
|
+
*
|
|
144
|
+
* export const wfList = defineSystemCommand<WorkflowListResult>({
|
|
145
|
+
* name: 'list',
|
|
146
|
+
* description: 'List workflows',
|
|
147
|
+
* flags: {
|
|
148
|
+
* source: { type: 'string', default: 'all' },
|
|
149
|
+
* tag: { type: 'string' },
|
|
150
|
+
* json: { type: 'boolean', default: false },
|
|
151
|
+
* } satisfies FlagSchemaDefinition, // TypeScript infers flag types automatically
|
|
152
|
+
* async handler(ctx, argv, flags) {
|
|
153
|
+
* // flags.source is inferred as string
|
|
154
|
+
* // flags.tag is inferred as string | undefined
|
|
155
|
+
* // flags.json is inferred as boolean
|
|
156
|
+
* const workflows = await listWorkflows(flags.source, flags.tag);
|
|
157
|
+
*
|
|
158
|
+
* // UI output (new convenience methods)
|
|
159
|
+
* if (!flags.json) {
|
|
160
|
+
* if (ctx.ui?.success) {
|
|
161
|
+
* ctx.ui.success('Workflows', [
|
|
162
|
+
* { header: 'Summary', items: [`Total: ${workflows.length}`, `Source: ${flags.source}`] },
|
|
163
|
+
* { items: workflows.map(w => `• ${w.id}`) },
|
|
164
|
+
* ]);
|
|
165
|
+
* }
|
|
166
|
+
* } else {
|
|
167
|
+
* ctx.ui?.json({ workflows, total: workflows.length });
|
|
168
|
+
* }
|
|
169
|
+
*
|
|
170
|
+
* return { ok: true, workflows, total: workflows.length };
|
|
171
|
+
* },
|
|
172
|
+
* });
|
|
173
|
+
*
|
|
174
|
+
* // Command with explicit flag types (for complex cases)
|
|
175
|
+
* export const wfRun = defineSystemCommand<
|
|
176
|
+
* { 'workflow-id': { type: 'string'; required: true } },
|
|
177
|
+
* CommandResult & { run: WorkflowRun }
|
|
178
|
+
* >({
|
|
179
|
+
* name: 'run',
|
|
180
|
+
* description: 'Execute a workflow',
|
|
181
|
+
* flags: {
|
|
182
|
+
* 'workflow-id': { type: 'string', required: true },
|
|
183
|
+
* },
|
|
184
|
+
* async handler(ctx, argv, flags) {
|
|
185
|
+
* // flags['workflow-id'] is inferred as string (required)
|
|
186
|
+
*
|
|
187
|
+
* // Progress tracking (CLI only, no-op in REST/Workflow)
|
|
188
|
+
* ctx.ui?.startProgress('running', 'Starting workflow...');
|
|
189
|
+
* const run = await executeWorkflow(flags['workflow-id']);
|
|
190
|
+
* ctx.ui?.completeProgress('running', 'Workflow started!');
|
|
191
|
+
*
|
|
192
|
+
* return { ok: true, run };
|
|
193
|
+
* },
|
|
194
|
+
* });
|
|
195
|
+
*
|
|
196
|
+
* // Note: System commands support all UI convenience methods:
|
|
197
|
+
* // - ctx.ui.success() / showError() / warning() / info() - Result display with sideBox
|
|
198
|
+
* // - ctx.ui.startProgress() / completeProgress() / failProgress() - Progress tracking
|
|
199
|
+
* // - ctx.ui.table() / keyValue() / list() - Low-level formatting
|
|
200
|
+
* // All UI methods are CLI-only and no-op in REST/Workflow contexts
|
|
201
|
+
* ```
|
|
202
|
+
*/
|
|
203
|
+
declare function defineSystemCommand<TFlags extends FlagSchemaDefinition$1, TResult extends CommandResult = CommandResult, TArgv extends readonly string[] = string[]>(config: SystemCommandConfig<TFlags, TResult, TArgv>): Command;
|
|
204
|
+
/**
|
|
205
|
+
* Create a system command group
|
|
206
|
+
*
|
|
207
|
+
* Groups organize related system commands for better help organization
|
|
208
|
+
* and registration.
|
|
209
|
+
*
|
|
210
|
+
* @example
|
|
211
|
+
* ```typescript
|
|
212
|
+
* export const systemInfoGroup = defineSystemCommandGroup(
|
|
213
|
+
* 'system:info',
|
|
214
|
+
* 'System information commands',
|
|
215
|
+
* [helloCommand, versionCommand, healthCommand]
|
|
216
|
+
* );
|
|
217
|
+
* ```
|
|
218
|
+
*/
|
|
219
|
+
declare function defineSystemCommandGroup(name: string, describe: string, commands: Command[]): CommandGroup;
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Manifest definition helpers
|
|
223
|
+
* @module @kb-labs/shared-command-kit/manifest
|
|
224
|
+
*/
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Define a ManifestV3 with type safety
|
|
228
|
+
*
|
|
229
|
+
* This is a type-safe wrapper for creating ManifestV3 objects.
|
|
230
|
+
* It provides compile-time validation via TypeScript and optional
|
|
231
|
+
* runtime validation via Zod (if enabled).
|
|
232
|
+
*
|
|
233
|
+
* For built plugins (dist/), this function is compiled away and only
|
|
234
|
+
* the plain object remains, avoiding runtime dependencies.
|
|
235
|
+
*
|
|
236
|
+
* @example
|
|
237
|
+
* ```typescript
|
|
238
|
+
* // Basic usage
|
|
239
|
+
* export const manifest = defineManifest({
|
|
240
|
+
* schema: 'kb.plugin/2',
|
|
241
|
+
* id: '@kb-labs/my-plugin',
|
|
242
|
+
* version: '1.0.0',
|
|
243
|
+
* cli: {
|
|
244
|
+
* commands: [...]
|
|
245
|
+
* }
|
|
246
|
+
* });
|
|
247
|
+
*
|
|
248
|
+
* // With contracts typing (Level 2)
|
|
249
|
+
* import type { PluginContracts } from '@kb-labs/my-plugin-contracts';
|
|
250
|
+
*
|
|
251
|
+
* export const manifest = defineManifest<typeof pluginContractsManifest>({
|
|
252
|
+
* schema: 'kb.plugin/2',
|
|
253
|
+
* id: '@kb-labs/my-plugin',
|
|
254
|
+
* artifacts: [
|
|
255
|
+
* { id: 'my.artifact.id' } // ✅ Type-checked against contracts
|
|
256
|
+
* ],
|
|
257
|
+
* cli: {
|
|
258
|
+
* commands: [{
|
|
259
|
+
* id: 'my:command', // ✅ Type-checked against contracts
|
|
260
|
+
* // ...
|
|
261
|
+
* }]
|
|
262
|
+
* }
|
|
263
|
+
* });
|
|
264
|
+
* ```
|
|
265
|
+
*
|
|
266
|
+
* @param manifest - Manifest configuration
|
|
267
|
+
* @returns ManifestV3 object
|
|
268
|
+
*/
|
|
269
|
+
declare function defineManifest<TContracts = unknown>(manifest: ManifestV3): ManifestV3;
|
|
270
|
+
/**
|
|
271
|
+
* Flag schema definition (compatible with defineFlags)
|
|
272
|
+
*/
|
|
273
|
+
type FlagSchemaDefinition = Record<string, {
|
|
274
|
+
type: 'string' | 'boolean' | 'number' | 'array';
|
|
275
|
+
alias?: string;
|
|
276
|
+
default?: unknown;
|
|
277
|
+
description?: string;
|
|
278
|
+
choices?: string[];
|
|
279
|
+
required?: boolean;
|
|
280
|
+
}>;
|
|
281
|
+
/**
|
|
282
|
+
* Convert flag schema definition to CliFlagDecl[] for manifest
|
|
283
|
+
*
|
|
284
|
+
* This helper converts the flag schema format used in defineCommand
|
|
285
|
+
* to the array format expected in ManifestV3.
|
|
286
|
+
*
|
|
287
|
+
* @example
|
|
288
|
+
* ```typescript
|
|
289
|
+
* const helloFlags = {
|
|
290
|
+
* name: { type: 'string', description: 'Name to greet', alias: 'n' },
|
|
291
|
+
* json: { type: 'boolean', description: 'Emit JSON', default: false }
|
|
292
|
+
* };
|
|
293
|
+
*
|
|
294
|
+
* const manifestFlags = defineCommandFlags(helloFlags);
|
|
295
|
+
* // Use in manifest: flags: manifestFlags
|
|
296
|
+
*
|
|
297
|
+
* // In manifest.v2.ts:
|
|
298
|
+
* export const manifest = defineManifest({
|
|
299
|
+
* cli: {
|
|
300
|
+
* commands: [{
|
|
301
|
+
* id: 'hello',
|
|
302
|
+
* flags: defineCommandFlags(helloFlags),
|
|
303
|
+
* // ...
|
|
304
|
+
* }]
|
|
305
|
+
* }
|
|
306
|
+
* });
|
|
307
|
+
* ```
|
|
308
|
+
*/
|
|
309
|
+
declare function defineCommandFlags<TFlags extends FlagSchemaDefinition>(flags: TFlags): Array<{
|
|
310
|
+
name: string;
|
|
311
|
+
type: 'string' | 'boolean' | 'number' | 'array';
|
|
312
|
+
alias?: string;
|
|
313
|
+
default?: unknown;
|
|
314
|
+
description?: string;
|
|
315
|
+
choices?: string[];
|
|
316
|
+
required?: boolean;
|
|
317
|
+
}>;
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Schema Builders for KB Labs Plugins
|
|
321
|
+
*
|
|
322
|
+
* Optional helpers for common Zod validation patterns.
|
|
323
|
+
* You can always use plain Zod - these are just conveniences for repetitive patterns.
|
|
324
|
+
*
|
|
325
|
+
* @example
|
|
326
|
+
* ```typescript
|
|
327
|
+
* import { schema } from '@kb-labs/shared-command-kit';
|
|
328
|
+
*
|
|
329
|
+
* const RequestSchema = schema.object({
|
|
330
|
+
* cwd: schema.cwd(),
|
|
331
|
+
* scope: schema.scopeId(),
|
|
332
|
+
* text: schema.text({ min: 1, max: 10000 }),
|
|
333
|
+
* mode: schema.enum(['instant', 'auto', 'thinking'], { default: 'auto' }),
|
|
334
|
+
* limit: schema.positiveInt({ max: 100, default: 10 }),
|
|
335
|
+
* });
|
|
336
|
+
* ```
|
|
337
|
+
*/
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Current working directory path (optional string)
|
|
341
|
+
* Commonly used in CLI and REST handlers
|
|
342
|
+
*
|
|
343
|
+
* @example
|
|
344
|
+
* ```typescript
|
|
345
|
+
* const schema = z.object({
|
|
346
|
+
* cwd: schema.cwd(),
|
|
347
|
+
* });
|
|
348
|
+
* // Equivalent to: cwd: z.string().optional()
|
|
349
|
+
* ```
|
|
350
|
+
*/
|
|
351
|
+
declare function cwd(): z.ZodOptional<z.ZodString>;
|
|
352
|
+
/**
|
|
353
|
+
* Scope identifier (required non-empty string)
|
|
354
|
+
* Used for Mind RAG scopes, workflow scopes, etc.
|
|
355
|
+
*
|
|
356
|
+
* @example
|
|
357
|
+
* ```typescript
|
|
358
|
+
* const schema = z.object({
|
|
359
|
+
* scope: schema.scopeId(),
|
|
360
|
+
* });
|
|
361
|
+
* // Equivalent to: scope: z.string().min(1)
|
|
362
|
+
* ```
|
|
363
|
+
*/
|
|
364
|
+
declare function scopeId(): z.ZodString;
|
|
365
|
+
/**
|
|
366
|
+
* Text string with optional length constraints
|
|
367
|
+
*
|
|
368
|
+
* @example
|
|
369
|
+
* ```typescript
|
|
370
|
+
* schema.text({ min: 1, max: 10000 })
|
|
371
|
+
* // Equivalent to: z.string().min(1).max(10000)
|
|
372
|
+
* ```
|
|
373
|
+
*/
|
|
374
|
+
declare function text(options?: {
|
|
375
|
+
min?: number;
|
|
376
|
+
max?: number;
|
|
377
|
+
default?: string;
|
|
378
|
+
}): z.ZodString | z.ZodDefault<z.ZodString>;
|
|
379
|
+
/**
|
|
380
|
+
* Positive integer with optional constraints
|
|
381
|
+
*
|
|
382
|
+
* @example
|
|
383
|
+
* ```typescript
|
|
384
|
+
* schema.positiveInt({ max: 100, default: 10 })
|
|
385
|
+
* // Equivalent to: z.number().int().positive().max(100).default(10)
|
|
386
|
+
* ```
|
|
387
|
+
*/
|
|
388
|
+
declare function positiveInt(options?: {
|
|
389
|
+
min?: number;
|
|
390
|
+
max?: number;
|
|
391
|
+
default?: number;
|
|
392
|
+
}): z.ZodNumber | z.ZodDefault<z.ZodNumber>;
|
|
393
|
+
/**
|
|
394
|
+
* Non-negative integer (0 or positive)
|
|
395
|
+
*
|
|
396
|
+
* @example
|
|
397
|
+
* ```typescript
|
|
398
|
+
* schema.nonNegativeInt({ max: 100 })
|
|
399
|
+
* // Equivalent to: z.number().int().min(0).max(100)
|
|
400
|
+
* ```
|
|
401
|
+
*/
|
|
402
|
+
declare function nonNegativeInt(options?: {
|
|
403
|
+
max?: number;
|
|
404
|
+
default?: number;
|
|
405
|
+
}): z.ZodNumber | z.ZodDefault<z.ZodNumber>;
|
|
406
|
+
/**
|
|
407
|
+
* Enum with optional default value
|
|
408
|
+
*
|
|
409
|
+
* @example
|
|
410
|
+
* ```typescript
|
|
411
|
+
* schema.enum(['instant', 'auto', 'thinking'], { default: 'auto' })
|
|
412
|
+
* // Equivalent to: z.enum(['instant', 'auto', 'thinking']).default('auto')
|
|
413
|
+
* ```
|
|
414
|
+
*/
|
|
415
|
+
declare function enumSchema<T extends [string, ...string[]]>(values: T, options?: {
|
|
416
|
+
default?: T[number];
|
|
417
|
+
}): z.ZodDefault<z.ZodEnum<T>> | z.ZodEnum<T>;
|
|
418
|
+
/**
|
|
419
|
+
* Plugin ID (@kb-labs/package-name format)
|
|
420
|
+
*
|
|
421
|
+
* @example
|
|
422
|
+
* ```typescript
|
|
423
|
+
* schema.pluginId()
|
|
424
|
+
* // Matches: @kb-labs/mind, @kb-labs/workflow, etc.
|
|
425
|
+
* ```
|
|
426
|
+
*/
|
|
427
|
+
declare function pluginId(): z.ZodString;
|
|
428
|
+
/**
|
|
429
|
+
* Command ID (plugin:command format)
|
|
430
|
+
*
|
|
431
|
+
* @example
|
|
432
|
+
* ```typescript
|
|
433
|
+
* schema.commandId()
|
|
434
|
+
* // Matches: mind:query, workflow:run, etc.
|
|
435
|
+
* ```
|
|
436
|
+
*/
|
|
437
|
+
declare function commandId(): z.ZodString;
|
|
438
|
+
/**
|
|
439
|
+
* Artifact ID (plugin.artifact.id format)
|
|
440
|
+
*
|
|
441
|
+
* @example
|
|
442
|
+
* ```typescript
|
|
443
|
+
* schema.artifactId()
|
|
444
|
+
* // Matches: mind.index.vector, workflow.run.result, etc.
|
|
445
|
+
* ```
|
|
446
|
+
*/
|
|
447
|
+
declare function artifactId(): z.ZodString;
|
|
448
|
+
/**
|
|
449
|
+
* File path (string)
|
|
450
|
+
* Optional with default to undefined
|
|
451
|
+
*
|
|
452
|
+
* @example
|
|
453
|
+
* ```typescript
|
|
454
|
+
* schema.filePath()
|
|
455
|
+
* // Equivalent to: z.string()
|
|
456
|
+
* ```
|
|
457
|
+
*/
|
|
458
|
+
declare function filePath(options?: {
|
|
459
|
+
optional?: boolean;
|
|
460
|
+
}): z.ZodString | z.ZodOptional<z.ZodString>;
|
|
461
|
+
/**
|
|
462
|
+
* URL string
|
|
463
|
+
*
|
|
464
|
+
* @example
|
|
465
|
+
* ```typescript
|
|
466
|
+
* schema.url()
|
|
467
|
+
* // Equivalent to: z.string().url()
|
|
468
|
+
* ```
|
|
469
|
+
*/
|
|
470
|
+
declare function url(options?: {
|
|
471
|
+
optional?: boolean;
|
|
472
|
+
}): z.ZodString | z.ZodOptional<z.ZodString>;
|
|
473
|
+
/**
|
|
474
|
+
* Email string
|
|
475
|
+
*
|
|
476
|
+
* @example
|
|
477
|
+
* ```typescript
|
|
478
|
+
* schema.email()
|
|
479
|
+
* // Equivalent to: z.string().email()
|
|
480
|
+
* ```
|
|
481
|
+
*/
|
|
482
|
+
declare function email(options?: {
|
|
483
|
+
optional?: boolean;
|
|
484
|
+
}): z.ZodString | z.ZodOptional<z.ZodString>;
|
|
485
|
+
/**
|
|
486
|
+
* UUID string
|
|
487
|
+
*
|
|
488
|
+
* @example
|
|
489
|
+
* ```typescript
|
|
490
|
+
* schema.uuid()
|
|
491
|
+
* // Equivalent to: z.string().uuid()
|
|
492
|
+
* ```
|
|
493
|
+
*/
|
|
494
|
+
declare function uuid(options?: {
|
|
495
|
+
optional?: boolean;
|
|
496
|
+
}): z.ZodString | z.ZodOptional<z.ZodString>;
|
|
497
|
+
/**
|
|
498
|
+
* ISO datetime string
|
|
499
|
+
*
|
|
500
|
+
* @example
|
|
501
|
+
* ```typescript
|
|
502
|
+
* schema.datetime()
|
|
503
|
+
* // Equivalent to: z.string().datetime()
|
|
504
|
+
* ```
|
|
505
|
+
*/
|
|
506
|
+
declare function datetime(options?: {
|
|
507
|
+
optional?: boolean;
|
|
508
|
+
}): z.ZodString | z.ZodOptional<z.ZodString>;
|
|
509
|
+
/**
|
|
510
|
+
* JSON object (any valid JSON object)
|
|
511
|
+
*
|
|
512
|
+
* @example
|
|
513
|
+
* ```typescript
|
|
514
|
+
* schema.json()
|
|
515
|
+
* // Equivalent to: z.record(z.unknown())
|
|
516
|
+
* ```
|
|
517
|
+
*/
|
|
518
|
+
declare function json(): z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
519
|
+
/**
|
|
520
|
+
* Boolean with optional default
|
|
521
|
+
*
|
|
522
|
+
* @example
|
|
523
|
+
* ```typescript
|
|
524
|
+
* schema.boolean({ default: false })
|
|
525
|
+
* // Equivalent to: z.boolean().default(false)
|
|
526
|
+
* ```
|
|
527
|
+
*/
|
|
528
|
+
declare function boolean(options?: {
|
|
529
|
+
default?: boolean;
|
|
530
|
+
}): z.ZodBoolean | z.ZodDefault<z.ZodBoolean>;
|
|
531
|
+
/**
|
|
532
|
+
* Array of items with optional length constraints
|
|
533
|
+
*
|
|
534
|
+
* @example
|
|
535
|
+
* ```typescript
|
|
536
|
+
* schema.array(z.string(), { min: 1, max: 10 })
|
|
537
|
+
* // Equivalent to: z.array(z.string()).min(1).max(10)
|
|
538
|
+
* ```
|
|
539
|
+
*/
|
|
540
|
+
declare function array<T extends z.ZodTypeAny>(itemSchema: T, options?: {
|
|
541
|
+
min?: number;
|
|
542
|
+
max?: number;
|
|
543
|
+
}): z.ZodArray<T, "many">;
|
|
544
|
+
/**
|
|
545
|
+
* Object schema builder (alias for z.object)
|
|
546
|
+
*
|
|
547
|
+
* @example
|
|
548
|
+
* ```typescript
|
|
549
|
+
* schema.object({ name: z.string() })
|
|
550
|
+
* // Equivalent to: z.object({ name: z.string() })
|
|
551
|
+
* ```
|
|
552
|
+
*/
|
|
553
|
+
declare function object<T extends z.ZodRawShape>(shape: T): z.ZodObject<T, "strip", z.ZodTypeAny, z.objectUtil.addQuestionMarks<z.baseObjectOutputType<T>, any> extends infer T_1 ? { [k in keyof T_1]: T_1[k]; } : never, z.baseObjectInputType<T> extends infer T_2 ? { [k_1 in keyof T_2]: T_2[k_1]; } : never>;
|
|
554
|
+
/**
|
|
555
|
+
* Export schema builders namespace
|
|
556
|
+
*
|
|
557
|
+
* @example
|
|
558
|
+
* ```typescript
|
|
559
|
+
* import { schema } from '@kb-labs/shared-command-kit';
|
|
560
|
+
*
|
|
561
|
+
* const MySchema = schema.object({
|
|
562
|
+
* cwd: schema.cwd(),
|
|
563
|
+
* scope: schema.scopeId(),
|
|
564
|
+
* text: schema.text({ min: 1, max: 10000 }),
|
|
565
|
+
* });
|
|
566
|
+
* ```
|
|
567
|
+
*/
|
|
568
|
+
declare const schema: {
|
|
569
|
+
cwd: typeof cwd;
|
|
570
|
+
scopeId: typeof scopeId;
|
|
571
|
+
pluginId: typeof pluginId;
|
|
572
|
+
commandId: typeof commandId;
|
|
573
|
+
artifactId: typeof artifactId;
|
|
574
|
+
filePath: typeof filePath;
|
|
575
|
+
text: typeof text;
|
|
576
|
+
url: typeof url;
|
|
577
|
+
email: typeof email;
|
|
578
|
+
uuid: typeof uuid;
|
|
579
|
+
datetime: typeof datetime;
|
|
580
|
+
positiveInt: typeof positiveInt;
|
|
581
|
+
nonNegativeInt: typeof nonNegativeInt;
|
|
582
|
+
enum: typeof enumSchema;
|
|
583
|
+
boolean: typeof boolean;
|
|
584
|
+
json: typeof json;
|
|
585
|
+
array: typeof array;
|
|
586
|
+
object: typeof object;
|
|
587
|
+
};
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* REST Handler Definition (V3)
|
|
591
|
+
*
|
|
592
|
+
* Define REST handlers compatible with plugin-runtime's runInProcess().
|
|
593
|
+
* Returns { execute } object with (ctx, input) signature.
|
|
594
|
+
*
|
|
595
|
+
* @example
|
|
596
|
+
* ```typescript
|
|
597
|
+
* import { defineHandler } from '@kb-labs/shared-command-kit';
|
|
598
|
+
*
|
|
599
|
+
* export default defineHandler({
|
|
600
|
+
* async execute(ctx, input: { scope?: string }) {
|
|
601
|
+
* const plan = await loadPlan(ctx.cwd);
|
|
602
|
+
* return plan;
|
|
603
|
+
* }
|
|
604
|
+
* });
|
|
605
|
+
* ```
|
|
606
|
+
*/
|
|
607
|
+
|
|
608
|
+
/**
|
|
609
|
+
* REST input structure from route-mounter.
|
|
610
|
+
* Query params, body, and route params are separated to avoid conflicts.
|
|
611
|
+
*/
|
|
612
|
+
interface RestInput<TQuery = unknown, TBody = unknown, TParams = unknown> {
|
|
613
|
+
query?: TQuery;
|
|
614
|
+
body?: TBody;
|
|
615
|
+
params?: TParams;
|
|
616
|
+
}
|
|
617
|
+
/**
|
|
618
|
+
* Handler interface expected by runInProcess().
|
|
619
|
+
*/
|
|
620
|
+
interface Handler<TConfig = unknown, TInput = unknown, TOutput = unknown> {
|
|
621
|
+
/**
|
|
622
|
+
* Execute the handler
|
|
623
|
+
*/
|
|
624
|
+
execute(ctx: PluginContextV3<TConfig>, input: TInput): Promise<TOutput>;
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* Handler definition options.
|
|
628
|
+
* Extensible for future features (inputSchema, middleware, etc.)
|
|
629
|
+
*/
|
|
630
|
+
interface HandlerDefinition<TConfig = unknown, TInput = unknown, TOutput = unknown> {
|
|
631
|
+
/**
|
|
632
|
+
* Execute the handler.
|
|
633
|
+
* Returns data directly - no need for exitCode/CommandResult wrapper.
|
|
634
|
+
*
|
|
635
|
+
* @param ctx - Plugin context with runtime APIs (fs, fetch, env, ui, etc.)
|
|
636
|
+
* @param input - Request input (body for POST, query for GET, etc.)
|
|
637
|
+
* @returns Response data (will be serialized as JSON)
|
|
638
|
+
* @throws Error on failure (will be converted to HTTP 500)
|
|
639
|
+
*/
|
|
640
|
+
execute(ctx: PluginContextV3<TConfig>, input: TInput): Promise<TOutput>;
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* Define a REST handler
|
|
644
|
+
*
|
|
645
|
+
* Creates a handler object compatible with runInProcess() from plugin-runtime.
|
|
646
|
+
* The handler receives full PluginContextV3 with runtime APIs.
|
|
647
|
+
*
|
|
648
|
+
* @example
|
|
649
|
+
* ```typescript
|
|
650
|
+
* // Simple handler
|
|
651
|
+
* export default defineHandler({
|
|
652
|
+
* async execute(ctx, input: { scope?: string }) {
|
|
653
|
+
* const plan = await loadPlan(ctx.cwd);
|
|
654
|
+
* return plan;
|
|
655
|
+
* }
|
|
656
|
+
* });
|
|
657
|
+
*
|
|
658
|
+
* // With typed query parameters using RestInput
|
|
659
|
+
* import { defineHandler, type RestInput } from '@kb-labs/sdk';
|
|
660
|
+
*
|
|
661
|
+
* export default defineHandler({
|
|
662
|
+
* async execute(ctx, input: RestInput<{ workspace?: string }>) {
|
|
663
|
+
* const workspace = input.query?.workspace || 'root';
|
|
664
|
+
* return { workspace };
|
|
665
|
+
* }
|
|
666
|
+
* });
|
|
667
|
+
*
|
|
668
|
+
* // With typed query and body
|
|
669
|
+
* interface QueryParams {
|
|
670
|
+
* workspace?: string;
|
|
671
|
+
* }
|
|
672
|
+
*
|
|
673
|
+
* interface BodyParams {
|
|
674
|
+
* name: string;
|
|
675
|
+
* description?: string;
|
|
676
|
+
* }
|
|
677
|
+
*
|
|
678
|
+
* export default defineHandler({
|
|
679
|
+
* async execute(ctx, input: RestInput<QueryParams, BodyParams>) {
|
|
680
|
+
* const workspace = input.query?.workspace || 'root';
|
|
681
|
+
* const name = input.body?.name;
|
|
682
|
+
* return { workspace, name };
|
|
683
|
+
* }
|
|
684
|
+
* });
|
|
685
|
+
*
|
|
686
|
+
* // With typed generics
|
|
687
|
+
* interface GetPlanInput {
|
|
688
|
+
* scope?: string;
|
|
689
|
+
* includeHistory?: boolean;
|
|
690
|
+
* }
|
|
691
|
+
*
|
|
692
|
+
* interface ReleasePlan {
|
|
693
|
+
* version: string;
|
|
694
|
+
* packages: string[];
|
|
695
|
+
* }
|
|
696
|
+
*
|
|
697
|
+
* export default defineHandler<unknown, GetPlanInput, ReleasePlan>({
|
|
698
|
+
* async execute(ctx, input) {
|
|
699
|
+
* // ctx: PluginContextV3 with runtime.fs, ui, etc.
|
|
700
|
+
* // input: GetPlanInput (typed)
|
|
701
|
+
* // return: ReleasePlan (typed)
|
|
702
|
+
* return await loadPlan(ctx.cwd, input.scope);
|
|
703
|
+
* }
|
|
704
|
+
* });
|
|
705
|
+
*
|
|
706
|
+
* // Using runtime APIs
|
|
707
|
+
* export default defineHandler({
|
|
708
|
+
* async execute(ctx, input: { path: string }) {
|
|
709
|
+
* // File system access
|
|
710
|
+
* const content = await ctx.runtime.fs.readFile(input.path, 'utf-8');
|
|
711
|
+
*
|
|
712
|
+
* // Environment variables
|
|
713
|
+
* const apiKey = ctx.runtime.env('API_KEY');
|
|
714
|
+
*
|
|
715
|
+
* // Logging
|
|
716
|
+
* ctx.runtime.log('info', 'Processing file', { path: input.path });
|
|
717
|
+
*
|
|
718
|
+
* return { content, hasApiKey: !!apiKey };
|
|
719
|
+
* }
|
|
720
|
+
* });
|
|
721
|
+
* ```
|
|
722
|
+
*/
|
|
723
|
+
declare function defineHandler<TConfig = unknown, TInput = unknown, TOutput = unknown>(definition: HandlerDefinition<TConfig, TInput, TOutput>): Handler<TConfig, TInput, TOutput>;
|
|
724
|
+
|
|
725
|
+
/**
|
|
726
|
+
* Lifecycle Hook Helpers
|
|
727
|
+
*
|
|
728
|
+
* Optional helpers for plugin lifecycle hooks (setup, destroy, upgrade).
|
|
729
|
+
* You can always use plain functions - this is just convenience.
|
|
730
|
+
*
|
|
731
|
+
* @example
|
|
732
|
+
* ```typescript
|
|
733
|
+
* import { defineSetupHandler } from '@kb-labs/shared-command-kit';
|
|
734
|
+
*
|
|
735
|
+
* export const setup = defineSetupHandler({
|
|
736
|
+
* name: 'mind:setup',
|
|
737
|
+
* workspace: {
|
|
738
|
+
* directories: ['.kb/mind/index', '.kb/mind/cache'],
|
|
739
|
+
* },
|
|
740
|
+
* config: {
|
|
741
|
+
* 'kb.config.json': {
|
|
742
|
+
* mind: { enabled: true, scopes: ['default'] },
|
|
743
|
+
* },
|
|
744
|
+
* },
|
|
745
|
+
* async handler(ctx) {
|
|
746
|
+
* ctx.log('Mind workspace initialized');
|
|
747
|
+
* return { ok: true };
|
|
748
|
+
* },
|
|
749
|
+
* });
|
|
750
|
+
* ```
|
|
751
|
+
*/
|
|
752
|
+
/**
|
|
753
|
+
* Lifecycle handler context
|
|
754
|
+
*/
|
|
755
|
+
interface LifecycleContext {
|
|
756
|
+
/** Output directory (plugin workspace root) */
|
|
757
|
+
outdir: string;
|
|
758
|
+
/** Plugin ID */
|
|
759
|
+
pluginId: string;
|
|
760
|
+
/** Request ID for tracing */
|
|
761
|
+
requestId?: string;
|
|
762
|
+
/** Logger */
|
|
763
|
+
log?: (level: 'debug' | 'info' | 'warn' | 'error', msg: string, meta?: Record<string, unknown>) => void;
|
|
764
|
+
/** Environment getter */
|
|
765
|
+
env?: (key: string) => string | undefined;
|
|
766
|
+
}
|
|
767
|
+
/**
|
|
768
|
+
* Workspace setup configuration
|
|
769
|
+
*/
|
|
770
|
+
interface WorkspaceConfig {
|
|
771
|
+
/** Directories to create (relative to outdir or absolute) */
|
|
772
|
+
directories?: string[];
|
|
773
|
+
/** Files to create with content */
|
|
774
|
+
files?: Record<string, string>;
|
|
775
|
+
}
|
|
776
|
+
/**
|
|
777
|
+
* Config file updates
|
|
778
|
+
*/
|
|
779
|
+
type ConfigUpdates = Record<string, Record<string, unknown>>;
|
|
780
|
+
/**
|
|
781
|
+
* Setup handler definition
|
|
782
|
+
*/
|
|
783
|
+
interface SetupHandlerDefinition {
|
|
784
|
+
/** Handler name (for logging) */
|
|
785
|
+
name: string;
|
|
786
|
+
/** Workspace configuration (directories/files to create) */
|
|
787
|
+
workspace?: WorkspaceConfig;
|
|
788
|
+
/** Config file updates (will be merged with existing config) */
|
|
789
|
+
config?: ConfigUpdates;
|
|
790
|
+
/** Custom setup logic (optional) */
|
|
791
|
+
handler?: (ctx: LifecycleContext) => Promise<{
|
|
792
|
+
ok: boolean;
|
|
793
|
+
message?: string;
|
|
794
|
+
}>;
|
|
795
|
+
}
|
|
796
|
+
/**
|
|
797
|
+
* Destroy handler definition
|
|
798
|
+
*/
|
|
799
|
+
interface DestroyHandlerDefinition {
|
|
800
|
+
/** Handler name (for logging) */
|
|
801
|
+
name: string;
|
|
802
|
+
/** Workspace cleanup (directories/files to remove) */
|
|
803
|
+
workspace?: {
|
|
804
|
+
/** Directories to remove */
|
|
805
|
+
directories?: string[];
|
|
806
|
+
/** Files to remove */
|
|
807
|
+
files?: string[];
|
|
808
|
+
};
|
|
809
|
+
/** Config cleanup (keys to remove from config files) */
|
|
810
|
+
config?: Record<string, string[]>;
|
|
811
|
+
/** Custom destroy logic (optional) */
|
|
812
|
+
handler?: (ctx: LifecycleContext) => Promise<{
|
|
813
|
+
ok: boolean;
|
|
814
|
+
message?: string;
|
|
815
|
+
}>;
|
|
816
|
+
}
|
|
817
|
+
/**
|
|
818
|
+
* Setup handler result
|
|
819
|
+
*/
|
|
820
|
+
interface SetupResult {
|
|
821
|
+
ok: boolean;
|
|
822
|
+
message?: string;
|
|
823
|
+
}
|
|
824
|
+
/**
|
|
825
|
+
* Define a setup handler with declarative workspace and config setup
|
|
826
|
+
*
|
|
827
|
+
* @example
|
|
828
|
+
* ```typescript
|
|
829
|
+
* export const setup = defineSetupHandler({
|
|
830
|
+
* name: 'mind:setup',
|
|
831
|
+
* workspace: {
|
|
832
|
+
* directories: [
|
|
833
|
+
* '.kb/mind/index',
|
|
834
|
+
* '.kb/mind/cache',
|
|
835
|
+
* '.kb/mind/pack',
|
|
836
|
+
* ],
|
|
837
|
+
* files: {
|
|
838
|
+
* '.kb/mind/.gitignore': 'cache/\npack/\n',
|
|
839
|
+
* },
|
|
840
|
+
* },
|
|
841
|
+
* config: {
|
|
842
|
+
* 'kb.config.json': {
|
|
843
|
+
* mind: {
|
|
844
|
+
* enabled: true,
|
|
845
|
+
* scopes: ['default'],
|
|
846
|
+
* },
|
|
847
|
+
* },
|
|
848
|
+
* },
|
|
849
|
+
* async handler(ctx) {
|
|
850
|
+
* ctx.log?.('info', 'Custom setup logic', {});
|
|
851
|
+
* return { ok: true };
|
|
852
|
+
* },
|
|
853
|
+
* });
|
|
854
|
+
* ```
|
|
855
|
+
*/
|
|
856
|
+
declare function defineSetupHandler(definition: SetupHandlerDefinition): (ctx: LifecycleContext) => Promise<SetupResult>;
|
|
857
|
+
/**
|
|
858
|
+
* Define a destroy handler with declarative cleanup
|
|
859
|
+
*
|
|
860
|
+
* @example
|
|
861
|
+
* ```typescript
|
|
862
|
+
* export const destroy = defineDestroyHandler({
|
|
863
|
+
* name: 'mind:destroy',
|
|
864
|
+
* workspace: {
|
|
865
|
+
* directories: ['.kb/mind'],
|
|
866
|
+
* },
|
|
867
|
+
* config: {
|
|
868
|
+
* 'kb.config.json': ['mind'], // Remove 'mind' key
|
|
869
|
+
* },
|
|
870
|
+
* });
|
|
871
|
+
* ```
|
|
872
|
+
*/
|
|
873
|
+
declare function defineDestroyHandler(definition: DestroyHandlerDefinition): (ctx: LifecycleContext) => Promise<SetupResult>;
|
|
874
|
+
|
|
875
|
+
/**
|
|
876
|
+
* Job definition helpers
|
|
877
|
+
* @module @kb-labs/shared-command-kit/jobs
|
|
878
|
+
*/
|
|
879
|
+
|
|
880
|
+
/**
|
|
881
|
+
* Job input passed to handler at runtime
|
|
882
|
+
*/
|
|
883
|
+
interface JobInput {
|
|
884
|
+
/** Job identifier */
|
|
885
|
+
jobId: string;
|
|
886
|
+
/** When the job was scheduled to execute */
|
|
887
|
+
executedAt: Date;
|
|
888
|
+
/** How many times this job has run */
|
|
889
|
+
runCount: number;
|
|
890
|
+
}
|
|
891
|
+
/**
|
|
892
|
+
* Job handler function signature
|
|
893
|
+
*
|
|
894
|
+
* @template TInput - Custom input type (extends JobInput)
|
|
895
|
+
* @template TOutput - Handler return type
|
|
896
|
+
*/
|
|
897
|
+
type JobHandler<TInput extends JobInput = JobInput, TOutput = {
|
|
898
|
+
ok: boolean;
|
|
899
|
+
[key: string]: unknown;
|
|
900
|
+
}> = (input: TInput, ctx: PluginContextV3) => Promise<TOutput>;
|
|
901
|
+
/**
|
|
902
|
+
* Job definition configuration
|
|
903
|
+
*
|
|
904
|
+
* Combines JobDecl manifest fields with the actual handler function
|
|
905
|
+
* for type-safe job creation.
|
|
906
|
+
*/
|
|
907
|
+
interface JobDefinition<TInput extends JobInput = JobInput, TOutput = {
|
|
908
|
+
ok: boolean;
|
|
909
|
+
[key: string]: unknown;
|
|
910
|
+
}> {
|
|
911
|
+
/** Unique job identifier within plugin (e.g., 'auto-index') */
|
|
912
|
+
id: string;
|
|
913
|
+
/**
|
|
914
|
+
* Cron schedule expression
|
|
915
|
+
* Supports shortcuts (@hourly, @daily, @weekly, @monthly, @yearly) and standard cron format
|
|
916
|
+
*/
|
|
917
|
+
schedule: string;
|
|
918
|
+
/** Human-readable description */
|
|
919
|
+
describe?: string;
|
|
920
|
+
/** Whether job is enabled (default: true) */
|
|
921
|
+
enabled?: boolean;
|
|
922
|
+
/** Job priority (1-10, default: 5, higher = more important) */
|
|
923
|
+
priority?: number;
|
|
924
|
+
/** Execution timeout in milliseconds (default: 60000 = 1min) */
|
|
925
|
+
timeout?: number;
|
|
926
|
+
/** Number of retry attempts on failure (default: 2) */
|
|
927
|
+
retries?: number;
|
|
928
|
+
/** Tags for filtering and organization */
|
|
929
|
+
tags?: string[];
|
|
930
|
+
/** Permissions for job execution (filesystem, network, quotas) */
|
|
931
|
+
permissions?: PermissionSpec;
|
|
932
|
+
/** Job handler function */
|
|
933
|
+
handler: JobHandler<TInput, TOutput>;
|
|
934
|
+
}
|
|
935
|
+
/**
|
|
936
|
+
* Defined job object with manifest conversion
|
|
937
|
+
*/
|
|
938
|
+
interface DefinedJob<TInput extends JobInput = JobInput, TOutput = {
|
|
939
|
+
ok: boolean;
|
|
940
|
+
[key: string]: unknown;
|
|
941
|
+
}> {
|
|
942
|
+
/** Job configuration */
|
|
943
|
+
readonly config: Omit<JobDefinition<TInput, TOutput>, 'handler'> & {
|
|
944
|
+
handler: string;
|
|
945
|
+
};
|
|
946
|
+
/** Job handler function */
|
|
947
|
+
readonly handler: JobHandler<TInput, TOutput>;
|
|
948
|
+
/** Convert to manifest JobDecl */
|
|
949
|
+
toManifest(handlerPath: string): JobDecl;
|
|
950
|
+
}
|
|
951
|
+
/**
|
|
952
|
+
* Define a type-safe job with handler
|
|
953
|
+
*
|
|
954
|
+
* This helper provides compile-time type safety for job definitions
|
|
955
|
+
* and allows sharing the same handler function between manifest and runtime.
|
|
956
|
+
*
|
|
957
|
+
* The handler function can be exported from a separate file and the manifest
|
|
958
|
+
* references it via the handler path.
|
|
959
|
+
*
|
|
960
|
+
* See plugin-template/src/jobs/hello.ts for a complete example.
|
|
961
|
+
*
|
|
962
|
+
* @param definition - Job configuration with handler
|
|
963
|
+
* @returns DefinedJob object with handler and manifest conversion
|
|
964
|
+
*/
|
|
965
|
+
declare function defineJob<TInput extends JobInput = JobInput, TOutput = {
|
|
966
|
+
ok: boolean;
|
|
967
|
+
[key: string]: unknown;
|
|
968
|
+
}>(definition: JobDefinition<TInput, TOutput>): DefinedJob<TInput, TOutput>;
|
|
969
|
+
|
|
970
|
+
/**
|
|
971
|
+
* Define a CLI command handler
|
|
972
|
+
*/
|
|
973
|
+
|
|
974
|
+
/**
|
|
975
|
+
* CLI input wrapper - V3 plugin system wraps flags in this structure
|
|
976
|
+
*/
|
|
977
|
+
interface CLIInput<TFlags = unknown> {
|
|
978
|
+
flags: TFlags;
|
|
979
|
+
argv: string[];
|
|
980
|
+
}
|
|
981
|
+
interface CommandHandlerV3<TConfig = unknown, TInput = unknown, TResult = unknown> {
|
|
982
|
+
/**
|
|
983
|
+
* Execute the command
|
|
984
|
+
*/
|
|
985
|
+
execute(context: PluginContextV3<TConfig>, input: TInput): Promise<CommandResult$1<TResult>> | CommandResult$1<TResult>;
|
|
986
|
+
/**
|
|
987
|
+
* Optional cleanup - called after execute completes
|
|
988
|
+
*/
|
|
989
|
+
cleanup?(): Promise<void> | void;
|
|
990
|
+
}
|
|
991
|
+
interface CommandDefinition<TConfig = unknown, TInput = unknown, TResult = unknown> {
|
|
992
|
+
/**
|
|
993
|
+
* Command ID (e.g., "my-plugin:greet")
|
|
994
|
+
*/
|
|
995
|
+
id: string;
|
|
996
|
+
/**
|
|
997
|
+
* Command description
|
|
998
|
+
*/
|
|
999
|
+
description?: string;
|
|
1000
|
+
/**
|
|
1001
|
+
* Handler implementation
|
|
1002
|
+
*/
|
|
1003
|
+
handler: CommandHandlerV3<TConfig, TInput, TResult>;
|
|
1004
|
+
/**
|
|
1005
|
+
* Optional input schema validation (future: use Zod/JSON Schema)
|
|
1006
|
+
*/
|
|
1007
|
+
schema?: unknown;
|
|
1008
|
+
}
|
|
1009
|
+
/**
|
|
1010
|
+
* Define a CLI command
|
|
1011
|
+
*
|
|
1012
|
+
* For CLI commands, use CLIInput<TFlags> as TInput type to get proper typing
|
|
1013
|
+
* for the V3 plugin system's { flags, argv } structure.
|
|
1014
|
+
*
|
|
1015
|
+
* @example
|
|
1016
|
+
* ```typescript
|
|
1017
|
+
* interface GreetFlags {
|
|
1018
|
+
* name?: string;
|
|
1019
|
+
* }
|
|
1020
|
+
*
|
|
1021
|
+
* interface GreetResult {
|
|
1022
|
+
* message: string;
|
|
1023
|
+
* target: string;
|
|
1024
|
+
* }
|
|
1025
|
+
*
|
|
1026
|
+
* export default defineCommand<unknown, CLIInput<GreetFlags>, GreetResult>({
|
|
1027
|
+
* id: 'greet',
|
|
1028
|
+
* description: 'Greet a user',
|
|
1029
|
+
* handler: {
|
|
1030
|
+
* async execute(context, input) {
|
|
1031
|
+
* const target = input.flags.name || 'World';
|
|
1032
|
+
* context.ui.success(`Hello, ${target}!`);
|
|
1033
|
+
*
|
|
1034
|
+
* return {
|
|
1035
|
+
* exitCode: 0,
|
|
1036
|
+
* result: { message: `Hello, ${target}!`, target },
|
|
1037
|
+
* meta: { version: 'v3' }
|
|
1038
|
+
* };
|
|
1039
|
+
* }
|
|
1040
|
+
* }
|
|
1041
|
+
* });
|
|
1042
|
+
* ```
|
|
1043
|
+
*/
|
|
1044
|
+
declare function defineCommand<TConfig = unknown, TInput = unknown, TResult = unknown>(definition: CommandDefinition<TConfig, TInput, TResult>): CommandHandlerV3<TConfig, TInput, TResult>;
|
|
1045
|
+
/**
|
|
1046
|
+
* Type guard to check if host context is CLI
|
|
1047
|
+
*/
|
|
1048
|
+
declare function isCLIHost(hostContext: HostContext): hostContext is Extract<HostContext, {
|
|
1049
|
+
host: 'cli';
|
|
1050
|
+
}>;
|
|
1051
|
+
|
|
1052
|
+
/**
|
|
1053
|
+
* Define a REST API route handler
|
|
1054
|
+
*/
|
|
1055
|
+
|
|
1056
|
+
interface RouteHandler<TConfig = unknown, TInput = unknown> {
|
|
1057
|
+
/**
|
|
1058
|
+
* Execute the route handler
|
|
1059
|
+
*/
|
|
1060
|
+
execute(context: PluginContextV3<TConfig>, input: TInput): Promise<CommandResult$1 | void> | CommandResult$1 | void;
|
|
1061
|
+
/**
|
|
1062
|
+
* Optional cleanup - called after execute completes
|
|
1063
|
+
*/
|
|
1064
|
+
cleanup?(): Promise<void> | void;
|
|
1065
|
+
}
|
|
1066
|
+
interface RouteDefinition<TConfig = unknown, TInput = unknown> {
|
|
1067
|
+
/**
|
|
1068
|
+
* Route path (e.g., "/api/greet")
|
|
1069
|
+
*/
|
|
1070
|
+
path: string;
|
|
1071
|
+
/**
|
|
1072
|
+
* HTTP method (e.g., "GET", "POST")
|
|
1073
|
+
*/
|
|
1074
|
+
method: string;
|
|
1075
|
+
/**
|
|
1076
|
+
* Route description
|
|
1077
|
+
*/
|
|
1078
|
+
description?: string;
|
|
1079
|
+
/**
|
|
1080
|
+
* Handler implementation
|
|
1081
|
+
*/
|
|
1082
|
+
handler: RouteHandler<TConfig, TInput>;
|
|
1083
|
+
/**
|
|
1084
|
+
* Optional input schema validation (future: use Zod/JSON Schema)
|
|
1085
|
+
*/
|
|
1086
|
+
schema?: unknown;
|
|
1087
|
+
}
|
|
1088
|
+
/**
|
|
1089
|
+
* Define a REST API route
|
|
1090
|
+
*
|
|
1091
|
+
* @example
|
|
1092
|
+
* ```typescript
|
|
1093
|
+
* export default defineRoute({
|
|
1094
|
+
* path: '/greet',
|
|
1095
|
+
* method: 'POST',
|
|
1096
|
+
* description: 'Greet a user',
|
|
1097
|
+
* handler: {
|
|
1098
|
+
* async execute(context, input: { name: string }) {
|
|
1099
|
+
* return {
|
|
1100
|
+
* data: { message: `Hello, ${input.name}!` },
|
|
1101
|
+
* exitCode: 0,
|
|
1102
|
+
* };
|
|
1103
|
+
* }
|
|
1104
|
+
* }
|
|
1105
|
+
* });
|
|
1106
|
+
* ```
|
|
1107
|
+
*/
|
|
1108
|
+
declare function defineRoute<TConfig = unknown, TInput = unknown>(definition: RouteDefinition<TConfig, TInput>): RouteHandler<TConfig, TInput>;
|
|
1109
|
+
/**
|
|
1110
|
+
* Type guard to check if host context is REST
|
|
1111
|
+
*/
|
|
1112
|
+
declare function isRESTHost(hostContext: HostContext): hostContext is Extract<HostContext, {
|
|
1113
|
+
host: 'rest';
|
|
1114
|
+
}>;
|
|
1115
|
+
|
|
1116
|
+
/**
|
|
1117
|
+
* Define a webhook handler
|
|
1118
|
+
*/
|
|
1119
|
+
|
|
1120
|
+
interface WebhookHandler<TConfig = unknown, TInput = unknown> {
|
|
1121
|
+
/**
|
|
1122
|
+
* Execute the webhook handler
|
|
1123
|
+
*/
|
|
1124
|
+
execute(context: PluginContextV3<TConfig>, input: TInput): Promise<CommandResult$1 | void> | CommandResult$1 | void;
|
|
1125
|
+
/**
|
|
1126
|
+
* Optional cleanup - called after execute completes
|
|
1127
|
+
*/
|
|
1128
|
+
cleanup?(): Promise<void> | void;
|
|
1129
|
+
}
|
|
1130
|
+
interface WebhookDefinition<TConfig = unknown, TInput = unknown> {
|
|
1131
|
+
/**
|
|
1132
|
+
* Event name (e.g., "github:push", "stripe:payment.success")
|
|
1133
|
+
*/
|
|
1134
|
+
event: string;
|
|
1135
|
+
/**
|
|
1136
|
+
* Webhook description
|
|
1137
|
+
*/
|
|
1138
|
+
description?: string;
|
|
1139
|
+
/**
|
|
1140
|
+
* Handler implementation
|
|
1141
|
+
*/
|
|
1142
|
+
handler: WebhookHandler<TConfig, TInput>;
|
|
1143
|
+
/**
|
|
1144
|
+
* Optional input schema validation (future: use Zod/JSON Schema)
|
|
1145
|
+
*/
|
|
1146
|
+
schema?: unknown;
|
|
1147
|
+
}
|
|
1148
|
+
/**
|
|
1149
|
+
* Define a webhook handler
|
|
1150
|
+
*
|
|
1151
|
+
* @example
|
|
1152
|
+
* ```typescript
|
|
1153
|
+
* export default defineWebhook({
|
|
1154
|
+
* event: 'github:push',
|
|
1155
|
+
* description: 'Handle GitHub push events',
|
|
1156
|
+
* handler: {
|
|
1157
|
+
* async execute(context, input: { ref: string; commits: any[] }) {
|
|
1158
|
+
* const { event, source, payload } = context.hostContext as WebhookHost;
|
|
1159
|
+
*
|
|
1160
|
+
* context.ui.info(`Received ${event} from ${source}`);
|
|
1161
|
+
*
|
|
1162
|
+
* // Process webhook...
|
|
1163
|
+
*
|
|
1164
|
+
* return {
|
|
1165
|
+
* data: { processed: true },
|
|
1166
|
+
* exitCode: 0,
|
|
1167
|
+
* };
|
|
1168
|
+
* }
|
|
1169
|
+
* }
|
|
1170
|
+
* });
|
|
1171
|
+
* ```
|
|
1172
|
+
*/
|
|
1173
|
+
declare function defineWebhook<TConfig = unknown, TInput = unknown>(definition: WebhookDefinition<TConfig, TInput>): WebhookHandler<TConfig, TInput>;
|
|
1174
|
+
/**
|
|
1175
|
+
* Type guard to check if host context is webhook
|
|
1176
|
+
*/
|
|
1177
|
+
declare function isWebhookHost(hostContext: HostContext): hostContext is Extract<HostContext, {
|
|
1178
|
+
host: 'webhook';
|
|
1179
|
+
}>;
|
|
1180
|
+
|
|
1181
|
+
/**
|
|
1182
|
+
* Define a WebSocket channel handler with enhanced DX
|
|
1183
|
+
*
|
|
1184
|
+
* Provides type-safe WebSocket handlers following the same pattern as defineCommand, defineRoute, etc.
|
|
1185
|
+
*/
|
|
1186
|
+
|
|
1187
|
+
/**
|
|
1188
|
+
* Typed sender with message builders
|
|
1189
|
+
*
|
|
1190
|
+
* Wraps WSSender to provide generic type support for outgoing messages.
|
|
1191
|
+
*/
|
|
1192
|
+
interface TypedSender<TOutgoing = WSMessage> extends Omit<WSSender, 'send' | 'broadcast' | 'sendTo'> {
|
|
1193
|
+
/** Send typed message to this client */
|
|
1194
|
+
send(message: TOutgoing): Promise<void>;
|
|
1195
|
+
/** Broadcast typed message to all clients in channel */
|
|
1196
|
+
broadcast(message: TOutgoing, excludeSelf?: boolean): Promise<void>;
|
|
1197
|
+
/** Send typed message to specific connections */
|
|
1198
|
+
sendTo(connectionIds: string[], message: TOutgoing): Promise<void>;
|
|
1199
|
+
/** Original WSSender methods for raw messages */
|
|
1200
|
+
raw: WSSender;
|
|
1201
|
+
}
|
|
1202
|
+
/**
|
|
1203
|
+
* WebSocket handler with typed messages
|
|
1204
|
+
*/
|
|
1205
|
+
interface WebSocketHandler<TConfig = unknown, TIncoming = unknown, TOutgoing = WSMessage> {
|
|
1206
|
+
/**
|
|
1207
|
+
* Called when client connects
|
|
1208
|
+
*/
|
|
1209
|
+
onConnect?(context: PluginContextV3<TConfig>, sender: TypedSender<TOutgoing>): Promise<void> | void;
|
|
1210
|
+
/**
|
|
1211
|
+
* Called when message received from client
|
|
1212
|
+
*/
|
|
1213
|
+
onMessage?(context: PluginContextV3<TConfig>, message: TIncoming, sender: TypedSender<TOutgoing>): Promise<void> | void;
|
|
1214
|
+
/**
|
|
1215
|
+
* Called when client disconnects
|
|
1216
|
+
*/
|
|
1217
|
+
onDisconnect?(context: PluginContextV3<TConfig>, code: number, reason: string): Promise<void> | void;
|
|
1218
|
+
/**
|
|
1219
|
+
* Called on error
|
|
1220
|
+
*/
|
|
1221
|
+
onError?(context: PluginContextV3<TConfig>, error: Error, sender: TypedSender<TOutgoing>): Promise<void> | void;
|
|
1222
|
+
/**
|
|
1223
|
+
* Optional cleanup - called after any lifecycle event
|
|
1224
|
+
*/
|
|
1225
|
+
cleanup?(): Promise<void> | void;
|
|
1226
|
+
}
|
|
1227
|
+
interface WebSocketDefinition<TConfig = unknown, TIncoming = unknown, TOutgoing = WSMessage> {
|
|
1228
|
+
/**
|
|
1229
|
+
* Channel path (e.g., "/live", "/chat")
|
|
1230
|
+
*/
|
|
1231
|
+
path: string;
|
|
1232
|
+
/**
|
|
1233
|
+
* Channel description
|
|
1234
|
+
*/
|
|
1235
|
+
description?: string;
|
|
1236
|
+
/**
|
|
1237
|
+
* Handler implementation
|
|
1238
|
+
*/
|
|
1239
|
+
handler: WebSocketHandler<TConfig, TIncoming, TOutgoing>;
|
|
1240
|
+
/**
|
|
1241
|
+
* Optional message schema validation (future: use Zod/JSON Schema)
|
|
1242
|
+
*/
|
|
1243
|
+
schema?: unknown;
|
|
1244
|
+
}
|
|
1245
|
+
/**
|
|
1246
|
+
* Define a WebSocket channel handler
|
|
1247
|
+
*
|
|
1248
|
+
* @example Basic usage
|
|
1249
|
+
* ```typescript
|
|
1250
|
+
* export default defineWebSocket({
|
|
1251
|
+
* path: '/chat',
|
|
1252
|
+
* handler: {
|
|
1253
|
+
* async onConnect(ctx, sender) {
|
|
1254
|
+
* await sender.send({ type: 'ready', payload: {}, timestamp: Date.now() });
|
|
1255
|
+
* },
|
|
1256
|
+
* async onMessage(ctx, message, sender) {
|
|
1257
|
+
* console.log('Received:', message);
|
|
1258
|
+
* },
|
|
1259
|
+
* }
|
|
1260
|
+
* });
|
|
1261
|
+
* ```
|
|
1262
|
+
*
|
|
1263
|
+
* @example With typed messages
|
|
1264
|
+
* ```typescript
|
|
1265
|
+
* interface IncomingMsg {
|
|
1266
|
+
* type: 'start' | 'stop';
|
|
1267
|
+
* payload: { scope?: string };
|
|
1268
|
+
* }
|
|
1269
|
+
*
|
|
1270
|
+
* interface OutgoingMsg {
|
|
1271
|
+
* type: 'progress' | 'complete';
|
|
1272
|
+
* payload: { progress: number; message: string };
|
|
1273
|
+
* }
|
|
1274
|
+
*
|
|
1275
|
+
* export default defineWebSocket<unknown, IncomingMsg, OutgoingMsg>({
|
|
1276
|
+
* path: '/live',
|
|
1277
|
+
* handler: {
|
|
1278
|
+
* async onMessage(ctx, message, sender) {
|
|
1279
|
+
* if (message.type === 'start') {
|
|
1280
|
+
* await sender.send({
|
|
1281
|
+
* type: 'progress',
|
|
1282
|
+
* payload: { progress: 50, message: 'Processing...' },
|
|
1283
|
+
* });
|
|
1284
|
+
* }
|
|
1285
|
+
* }
|
|
1286
|
+
* }
|
|
1287
|
+
* });
|
|
1288
|
+
* ```
|
|
1289
|
+
*
|
|
1290
|
+
* @example With message router (advanced pattern matching)
|
|
1291
|
+
* ```typescript
|
|
1292
|
+
* import { defineMessage, MessageRouter } from '@kb-labs/sdk';
|
|
1293
|
+
*
|
|
1294
|
+
* // Define message types
|
|
1295
|
+
* const StartMsg = defineMessage<{ scope?: string }>('start');
|
|
1296
|
+
* const StopMsg = defineMessage<{}>('stop');
|
|
1297
|
+
*
|
|
1298
|
+
* // Create outgoing message builders
|
|
1299
|
+
* const ProgressMsg = defineMessage<{ phase: string; progress: number }>('progress');
|
|
1300
|
+
* const CompleteMsg = defineMessage<{ commits: any[] }>('complete');
|
|
1301
|
+
*
|
|
1302
|
+
* export default defineWebSocket({
|
|
1303
|
+
* path: '/live',
|
|
1304
|
+
* handler: {
|
|
1305
|
+
* async onMessage(ctx, message, sender) {
|
|
1306
|
+
* const router = new MessageRouter()
|
|
1307
|
+
* .on(StartMsg, async (ctx, payload, sender) => {
|
|
1308
|
+
* await sender.send(ProgressMsg.create({
|
|
1309
|
+
* phase: 'analyzing',
|
|
1310
|
+
* progress: 0,
|
|
1311
|
+
* }));
|
|
1312
|
+
* })
|
|
1313
|
+
* .on(StopMsg, async (ctx, payload, sender) => {
|
|
1314
|
+
* sender.close(1000, 'Stopped by user');
|
|
1315
|
+
* });
|
|
1316
|
+
*
|
|
1317
|
+
* await router.handle(ctx, message, sender.raw);
|
|
1318
|
+
* }
|
|
1319
|
+
* }
|
|
1320
|
+
* });
|
|
1321
|
+
* ```
|
|
1322
|
+
*/
|
|
1323
|
+
declare function defineWebSocket<TConfig = unknown, TIncoming = unknown, TOutgoing = WSMessage>(definition: WebSocketDefinition<TConfig, TIncoming, TOutgoing>): {
|
|
1324
|
+
execute(context: PluginContextV3<TConfig>, input: WSInput): Promise<CommandResult$1 | void>;
|
|
1325
|
+
};
|
|
1326
|
+
/**
|
|
1327
|
+
* Type guard to check if host context is WebSocket
|
|
1328
|
+
*/
|
|
1329
|
+
declare function isWSHost(hostContext: HostContext): hostContext is Extract<HostContext, {
|
|
1330
|
+
host: 'ws';
|
|
1331
|
+
}>;
|
|
1332
|
+
|
|
1333
|
+
/**
|
|
1334
|
+
* Define a workflow action handler
|
|
1335
|
+
*/
|
|
1336
|
+
|
|
1337
|
+
interface ActionHandler<TConfig = unknown, TInput = unknown> {
|
|
1338
|
+
/**
|
|
1339
|
+
* Execute the workflow action
|
|
1340
|
+
*/
|
|
1341
|
+
execute(context: PluginContextV3<TConfig>, input: TInput): Promise<CommandResult$1 | void> | CommandResult$1 | void;
|
|
1342
|
+
/**
|
|
1343
|
+
* Optional cleanup - called after execute completes
|
|
1344
|
+
*/
|
|
1345
|
+
cleanup?(): Promise<void> | void;
|
|
1346
|
+
}
|
|
1347
|
+
interface ActionDefinition<TConfig = unknown, TInput = unknown> {
|
|
1348
|
+
/**
|
|
1349
|
+
* Action ID (e.g., "send-email")
|
|
1350
|
+
*/
|
|
1351
|
+
id: string;
|
|
1352
|
+
/**
|
|
1353
|
+
* Action description
|
|
1354
|
+
*/
|
|
1355
|
+
description?: string;
|
|
1356
|
+
/**
|
|
1357
|
+
* Handler implementation
|
|
1358
|
+
*/
|
|
1359
|
+
handler: ActionHandler<TConfig, TInput>;
|
|
1360
|
+
/**
|
|
1361
|
+
* Optional input schema validation (future: use Zod/JSON Schema)
|
|
1362
|
+
*/
|
|
1363
|
+
schema?: unknown;
|
|
1364
|
+
}
|
|
1365
|
+
/**
|
|
1366
|
+
* Define a workflow action
|
|
1367
|
+
*
|
|
1368
|
+
* @example
|
|
1369
|
+
* ```typescript
|
|
1370
|
+
* export default defineAction({
|
|
1371
|
+
* id: 'send-email',
|
|
1372
|
+
* description: 'Send an email notification',
|
|
1373
|
+
* handler: {
|
|
1374
|
+
* async execute(context, input: { to: string; subject: string; body: string }) {
|
|
1375
|
+
* // Access workflow context
|
|
1376
|
+
* const { workflowId, runId, stepId } = context.hostContext as WorkflowHost;
|
|
1377
|
+
*
|
|
1378
|
+
* context.ui.info(`Sending email in workflow ${workflowId}`);
|
|
1379
|
+
*
|
|
1380
|
+
* // Send email...
|
|
1381
|
+
*
|
|
1382
|
+
* return {
|
|
1383
|
+
* data: { sent: true, messageId: '123' },
|
|
1384
|
+
* exitCode: 0,
|
|
1385
|
+
* };
|
|
1386
|
+
* }
|
|
1387
|
+
* }
|
|
1388
|
+
* });
|
|
1389
|
+
* ```
|
|
1390
|
+
*/
|
|
1391
|
+
declare function defineAction<TConfig = unknown, TInput = unknown>(definition: ActionDefinition<TConfig, TInput>): ActionHandler<TConfig, TInput>;
|
|
1392
|
+
/**
|
|
1393
|
+
* Type guard to check if host context is workflow
|
|
1394
|
+
*/
|
|
1395
|
+
declare function isWorkflowHost(hostContext: HostContext): hostContext is Extract<HostContext, {
|
|
1396
|
+
host: 'workflow';
|
|
1397
|
+
}>;
|
|
1398
|
+
|
|
1399
|
+
/**
|
|
1400
|
+
* Enhanced WebSocket types for better DX
|
|
1401
|
+
*
|
|
1402
|
+
* Provides type-safe message builders and pattern matching utilities.
|
|
1403
|
+
*/
|
|
1404
|
+
|
|
1405
|
+
/**
|
|
1406
|
+
* Type-safe message builder
|
|
1407
|
+
*
|
|
1408
|
+
* @example
|
|
1409
|
+
* ```typescript
|
|
1410
|
+
* const Progress = defineMessage<{ phase: string; progress: number }>('progress');
|
|
1411
|
+
* const msg = Progress.create({ phase: 'analyzing', progress: 50 });
|
|
1412
|
+
* // msg: { type: 'progress', payload: { phase: 'analyzing', progress: 50 }, timestamp: number }
|
|
1413
|
+
* ```
|
|
1414
|
+
*/
|
|
1415
|
+
declare class MessageBuilder<TPayload = unknown> {
|
|
1416
|
+
private type;
|
|
1417
|
+
constructor(type: string);
|
|
1418
|
+
/**
|
|
1419
|
+
* Create message with payload
|
|
1420
|
+
*/
|
|
1421
|
+
create(payload: TPayload, messageId?: string): WSMessage;
|
|
1422
|
+
/**
|
|
1423
|
+
* Match against incoming message type (type guard)
|
|
1424
|
+
*/
|
|
1425
|
+
is(message: WSMessage): message is WSMessage & {
|
|
1426
|
+
payload: TPayload;
|
|
1427
|
+
};
|
|
1428
|
+
}
|
|
1429
|
+
/**
|
|
1430
|
+
* Helper to define typed messages
|
|
1431
|
+
*
|
|
1432
|
+
* @example
|
|
1433
|
+
* ```typescript
|
|
1434
|
+
* const StartMsg = defineMessage<{ scope?: string }>('start');
|
|
1435
|
+
* const ProgressMsg = defineMessage<{ phase: string; progress: number }>('progress');
|
|
1436
|
+
* ```
|
|
1437
|
+
*/
|
|
1438
|
+
declare function defineMessage<TPayload = unknown>(type: string): MessageBuilder<TPayload>;
|
|
1439
|
+
/**
|
|
1440
|
+
* Message router for pattern matching
|
|
1441
|
+
*
|
|
1442
|
+
* Provides elegant routing of incoming WebSocket messages to typed handlers.
|
|
1443
|
+
*
|
|
1444
|
+
* @example
|
|
1445
|
+
* ```typescript
|
|
1446
|
+
* const router = new MessageRouter()
|
|
1447
|
+
* .on(StartMsg, async (ctx, payload, sender) => {
|
|
1448
|
+
* // payload is typed as { scope?: string }
|
|
1449
|
+
* console.log('Starting with scope:', payload.scope);
|
|
1450
|
+
* })
|
|
1451
|
+
* .on(StopMsg, async (ctx, payload, sender) => {
|
|
1452
|
+
* // Different message type, different payload type
|
|
1453
|
+
* sender.close(1000, 'Stopped by user');
|
|
1454
|
+
* });
|
|
1455
|
+
*
|
|
1456
|
+
* await router.handle(ctx, message, sender);
|
|
1457
|
+
* ```
|
|
1458
|
+
*/
|
|
1459
|
+
declare class MessageRouter<TConfig = unknown> {
|
|
1460
|
+
private handlers;
|
|
1461
|
+
/**
|
|
1462
|
+
* Register message handler
|
|
1463
|
+
*/
|
|
1464
|
+
on<TPayload>(message: MessageBuilder<TPayload>, handler: (ctx: PluginContextV3<TConfig>, payload: TPayload, sender: WSSender) => Promise<void> | void): this;
|
|
1465
|
+
/**
|
|
1466
|
+
* Handle incoming message
|
|
1467
|
+
*
|
|
1468
|
+
* @returns true if message was handled, false otherwise
|
|
1469
|
+
*/
|
|
1470
|
+
handle(ctx: PluginContextV3<TConfig>, message: WSMessage, sender: WSSender): Promise<boolean>;
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1473
|
+
/**
|
|
1474
|
+
* @module @kb-labs/shared-command-kit
|
|
1475
|
+
* Command Kit - High-level API and utilities for building CLI commands
|
|
1476
|
+
*/
|
|
1477
|
+
|
|
1478
|
+
/**
|
|
1479
|
+
* Command execution status
|
|
1480
|
+
*/
|
|
1481
|
+
type CommandStatus = 'success' | 'failed' | 'error' | 'cancelled' | 'skipped' | 'warning' | 'info';
|
|
1482
|
+
/**
|
|
1483
|
+
* Helper types for command results (optional - use when convenient)
|
|
1484
|
+
*
|
|
1485
|
+
* These types make it easier to define command results without repeating `CommandResult &`.
|
|
1486
|
+
* They are completely optional - you can still use `CommandResult & { ... }` directly.
|
|
1487
|
+
*
|
|
1488
|
+
* @example
|
|
1489
|
+
* ```typescript
|
|
1490
|
+
* // Using helper types (optional)
|
|
1491
|
+
* type MyResult = SuccessResult<{ items: Item[]; total: number }>;
|
|
1492
|
+
*
|
|
1493
|
+
* // Direct usage (also works)
|
|
1494
|
+
* type MyResult = CommandResult & { ok: true; items: Item[]; total: number };
|
|
1495
|
+
* ```
|
|
1496
|
+
*/
|
|
1497
|
+
type SuccessResult<T extends Record<string, unknown> = Record<string, never>> = CommandResult & {
|
|
1498
|
+
ok: true;
|
|
1499
|
+
} & T;
|
|
1500
|
+
type ErrorResult<T extends Record<string, unknown> = Record<string, never>> = CommandResult & {
|
|
1501
|
+
ok: false;
|
|
1502
|
+
error: string;
|
|
1503
|
+
} & T;
|
|
1504
|
+
type ResultWith<T extends Record<string, unknown>> = CommandResult & T;
|
|
1505
|
+
/**
|
|
1506
|
+
* Base command result contract - all command results must extend this
|
|
1507
|
+
*
|
|
1508
|
+
* This defines the minimal contract that every command must fulfill.
|
|
1509
|
+
* Every command MUST explicitly declare its result type via generic TResult parameter.
|
|
1510
|
+
*
|
|
1511
|
+
* Required fields:
|
|
1512
|
+
* - `ok: boolean` - execution success status
|
|
1513
|
+
*
|
|
1514
|
+
* Recommended fields:
|
|
1515
|
+
* - `error?: string` - error message when ok === false
|
|
1516
|
+
* - `status?: CommandStatus` - execution status (auto-inferred if not provided)
|
|
1517
|
+
*
|
|
1518
|
+
* Additional fields should be added via generic TResult type parameter.
|
|
1519
|
+
*
|
|
1520
|
+
* @example
|
|
1521
|
+
* ```typescript
|
|
1522
|
+
* // Minimal result (not recommended - use explicit type)
|
|
1523
|
+
* type MyResult = CommandResult; // { ok: boolean; error?: string; status?: CommandStatus }
|
|
1524
|
+
*
|
|
1525
|
+
* // Extended result with custom fields (RECOMMENDED)
|
|
1526
|
+
* type WorkflowRunResult = CommandResult & {
|
|
1527
|
+
* run: WorkflowRun;
|
|
1528
|
+
* timingMs: number;
|
|
1529
|
+
* };
|
|
1530
|
+
*
|
|
1531
|
+
* type ListResult = CommandResult & {
|
|
1532
|
+
* items: Item[];
|
|
1533
|
+
* total: number;
|
|
1534
|
+
* };
|
|
1535
|
+
* ```
|
|
1536
|
+
*/
|
|
1537
|
+
type CommandResult = {
|
|
1538
|
+
/** Whether the command executed successfully - REQUIRED */
|
|
1539
|
+
ok: boolean;
|
|
1540
|
+
/** Error message if ok === false - RECOMMENDED for error cases */
|
|
1541
|
+
error?: string;
|
|
1542
|
+
/** Execution status - automatically inferred from ok if not provided */
|
|
1543
|
+
status?: CommandStatus;
|
|
1544
|
+
};
|
|
1545
|
+
/**
|
|
1546
|
+
* Command handler function signature
|
|
1547
|
+
*
|
|
1548
|
+
* TConfig is the product configuration type (auto-loaded from kb.config.json)
|
|
1549
|
+
* TEnv is the environment variables type (validated at runtime)
|
|
1550
|
+
* TResult must extend CommandResult ({ ok: boolean }) and represents the contract
|
|
1551
|
+
* for what the command returns. This ensures type safety and enables future contract
|
|
1552
|
+
* validation.
|
|
1553
|
+
*
|
|
1554
|
+
* TArgv is optional - by default it's `string[]`, but you can provide a tuple type
|
|
1555
|
+
* for strict argument typing if needed.
|
|
1556
|
+
*
|
|
1557
|
+
* @example
|
|
1558
|
+
* ```typescript
|
|
1559
|
+
* // Default: argv is string[]
|
|
1560
|
+
* handler: (ctx, argv, flags) => { ... }
|
|
1561
|
+
*
|
|
1562
|
+
* // With typed config
|
|
1563
|
+
* handler: (ctx, argv, flags) => {
|
|
1564
|
+
* ctx.config?.llmProvider // TypeScript knows the config type
|
|
1565
|
+
* }
|
|
1566
|
+
*
|
|
1567
|
+
* // With typed env
|
|
1568
|
+
* handler: (ctx, argv, flags) => {
|
|
1569
|
+
* ctx.env.OPENAI_API_KEY // TypeScript knows it's a string
|
|
1570
|
+
* }
|
|
1571
|
+
*
|
|
1572
|
+
* // Strict typing: argv is tuple ['workflow-id', ...string[]]
|
|
1573
|
+
* handler: (ctx, argv: ['workflow-id', ...string[]], flags) => {
|
|
1574
|
+
* const workflowId = argv[0]; // TypeScript knows it's 'workflow-id'
|
|
1575
|
+
* }
|
|
1576
|
+
* ```
|
|
1577
|
+
*/
|
|
1578
|
+
type CommandHandler<_TConfig = any, TFlags extends Record<string, unknown> = Record<string, unknown>, TResult extends CommandResult = CommandResult, TArgv extends readonly string[] = string[], _TEnv = Record<string, string | undefined>> = (ctx: PluginContextV3, argv: TArgv, flags: TFlags) => Promise<number | TResult> | number | TResult;
|
|
1579
|
+
/**
|
|
1580
|
+
* Command formatter function
|
|
1581
|
+
*
|
|
1582
|
+
* All type parameters are optional with defaults - same as CommandHandler.
|
|
1583
|
+
* Use explicit types when you want type safety, skip them for simplicity.
|
|
1584
|
+
*
|
|
1585
|
+
* @example
|
|
1586
|
+
* ```typescript
|
|
1587
|
+
* // Default: argv is string[]
|
|
1588
|
+
* formatter: (result, ctx, flags) => { ... }
|
|
1589
|
+
*
|
|
1590
|
+
* // With typed config
|
|
1591
|
+
* formatter: (result, ctx, flags) => {
|
|
1592
|
+
* ctx.config?.llmProvider // TypeScript knows the config type
|
|
1593
|
+
* }
|
|
1594
|
+
*
|
|
1595
|
+
* // With typed env
|
|
1596
|
+
* formatter: (result, ctx, flags) => {
|
|
1597
|
+
* ctx.env.OPENAI_API_KEY // TypeScript knows it's a string
|
|
1598
|
+
* }
|
|
1599
|
+
*
|
|
1600
|
+
* // Strict typing: argv is tuple ['workflow-id', ...string[]]
|
|
1601
|
+
* formatter: (result, ctx, flags, argv: ['workflow-id', ...string[]]) => {
|
|
1602
|
+
* const workflowId = argv[0]; // TypeScript knows it's 'workflow-id'
|
|
1603
|
+
* }
|
|
1604
|
+
* ```
|
|
1605
|
+
*/
|
|
1606
|
+
type CommandFormatter<_TConfig = any, TFlags extends Record<string, unknown> = Record<string, unknown>, TResult extends CommandResult = CommandResult, TArgv extends readonly string[] = string[], _TEnv = Record<string, string | undefined>> = (result: TResult, ctx: PluginContextV3, flags: TFlags, argv?: TArgv) => void;
|
|
1607
|
+
/**
|
|
1608
|
+
* Command configuration
|
|
1609
|
+
*
|
|
1610
|
+
* All type parameters are optional with sensible defaults:
|
|
1611
|
+
* - TConfig defaults to any (product config type)
|
|
1612
|
+
* - TFlags defaults to FlagSchemaDefinition (flags are Record<string, unknown>)
|
|
1613
|
+
* - TResult defaults to CommandResult (basic { ok: boolean })
|
|
1614
|
+
* - TArgv defaults to string[] (arguments are string[])
|
|
1615
|
+
* - TEnv defaults to Record<string, string | undefined> (process.env)
|
|
1616
|
+
*
|
|
1617
|
+
* Use explicit types when you want better type safety, but everything works without them.
|
|
1618
|
+
*
|
|
1619
|
+
* @example
|
|
1620
|
+
* ```typescript
|
|
1621
|
+
* // Default: argv is string[]
|
|
1622
|
+
* const cmd = defineCommand({
|
|
1623
|
+
* handler: (ctx, argv, flags) => { ... }
|
|
1624
|
+
* });
|
|
1625
|
+
*
|
|
1626
|
+
* // Simple usage with flags and result only (RECOMMENDED)
|
|
1627
|
+
* const cmd = defineCommand<MyFlags, MyResult>({
|
|
1628
|
+
* handler: (ctx, argv, flags) => {
|
|
1629
|
+
* // flags are typed as InferFlags<MyFlags>
|
|
1630
|
+
* return { ok: true, ...result };
|
|
1631
|
+
* }
|
|
1632
|
+
* });
|
|
1633
|
+
*
|
|
1634
|
+
* // With typed config (third parameter)
|
|
1635
|
+
* type MindConfig = { llmProvider: string; maxTokens: number };
|
|
1636
|
+
* const cmd = defineCommand<Flags, Result, MindConfig>({
|
|
1637
|
+
* handler: (ctx, argv, flags) => {
|
|
1638
|
+
* ctx.config?.llmProvider // TypeScript knows it's a string
|
|
1639
|
+
* }
|
|
1640
|
+
* });
|
|
1641
|
+
*
|
|
1642
|
+
* // With typed env (fifth parameter)
|
|
1643
|
+
* type Env = { OPENAI_API_KEY: string; DEBUG?: string };
|
|
1644
|
+
* const cmd = defineCommand<Flags, Result, Config, Argv, Env>({
|
|
1645
|
+
* handler: (ctx, argv, flags) => {
|
|
1646
|
+
* ctx.env.OPENAI_API_KEY // string (validated!)
|
|
1647
|
+
* }
|
|
1648
|
+
* });
|
|
1649
|
+
*
|
|
1650
|
+
* // Strict typing: argv is tuple ['workflow-id', ...string[]]
|
|
1651
|
+
* const cmd = defineCommand<Flags, Result, Config, ['workflow-id', ...string[]]>({
|
|
1652
|
+
* handler: (ctx, argv, flags) => {
|
|
1653
|
+
* const workflowId = argv[0]; // TypeScript knows it's 'workflow-id'
|
|
1654
|
+
* }
|
|
1655
|
+
* });
|
|
1656
|
+
* ```
|
|
1657
|
+
*/
|
|
1658
|
+
interface CommandConfig<TFlags extends FlagSchemaDefinition$1 = FlagSchemaDefinition$1, TResult extends CommandResult = CommandResult, TConfig = any, TArgv extends readonly string[] = string[], TEnv = Record<string, string | undefined>> {
|
|
1659
|
+
/** Command name (for logging) */
|
|
1660
|
+
name?: string;
|
|
1661
|
+
/** Flag schema definition */
|
|
1662
|
+
flags: TFlags;
|
|
1663
|
+
/**
|
|
1664
|
+
* Analytics configuration (legacy field, kept for backward compatibility)
|
|
1665
|
+
* Use ctx.platform.analytics.track() or withAnalytics() helper instead
|
|
1666
|
+
*/
|
|
1667
|
+
analytics?: {
|
|
1668
|
+
command?: string;
|
|
1669
|
+
startEvent?: string;
|
|
1670
|
+
finishEvent?: string;
|
|
1671
|
+
actor?: string;
|
|
1672
|
+
context?: Record<string, unknown>;
|
|
1673
|
+
includeFlags?: boolean;
|
|
1674
|
+
};
|
|
1675
|
+
/**
|
|
1676
|
+
* Optional environment variable schema for validation.
|
|
1677
|
+
* If provided, required env vars will be validated at runtime.
|
|
1678
|
+
*
|
|
1679
|
+
* @example
|
|
1680
|
+
* ```typescript
|
|
1681
|
+
* env: {
|
|
1682
|
+
* OPENAI_API_KEY: { required: true },
|
|
1683
|
+
* DEBUG: { required: false },
|
|
1684
|
+
* }
|
|
1685
|
+
* ```
|
|
1686
|
+
*/
|
|
1687
|
+
env?: Record<string, {
|
|
1688
|
+
required?: boolean;
|
|
1689
|
+
}>;
|
|
1690
|
+
/** Command handler - must return TResult */
|
|
1691
|
+
handler: CommandHandler<TConfig, InferFlags<TFlags>, TResult, TArgv, TEnv>;
|
|
1692
|
+
/** Optional formatter for output - receives TResult */
|
|
1693
|
+
formatter?: CommandFormatter<TConfig, InferFlags<TFlags>, TResult, TArgv, TEnv>;
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1696
|
+
export { type ActionDefinition, type ActionHandler, type CLIInput, type Command, type CommandConfig, type CommandDefinition, type CommandFormatter, type CommandGroup, type CommandHandler, type CommandHandlerV3, type CommandResult, type CommandStatus, type ConfigUpdates, type DefinedJob, type DestroyHandlerDefinition, type ErrorResult, FlagSchemaDefinition$1 as FlagSchemaDefinition, type Handler, type HandlerDefinition, InferFlags, type JobDefinition, type JobHandler, type JobInput, type LifecycleContext, MessageBuilder, MessageRouter, type RestInput, type ResultWith, type RouteDefinition, type RouteHandler, type SetupHandlerDefinition, type SetupResult, type SuccessResult, type SystemCommandConfig, type TypedSender, type WebSocketDefinition, type WebSocketHandler, type WebhookDefinition, type WebhookHandler, type WorkspaceConfig, array, artifactId, boolean, commandId, cwd, datetime, defineAction, defineCommand, defineCommandFlags, defineDestroyHandler, defineHandler, defineJob, defineManifest, defineMessage, defineRoute, defineSetupHandler, defineSystemCommand, defineSystemCommandGroup, defineWebSocket, defineWebhook, email, enumSchema, filePath, isCLIHost, isRESTHost, isWSHost, isWebhookHost, isWorkflowHost, json, nonNegativeInt, object, pluginId, positiveInt, schema, scopeId, text, url, uuid };
|