@kb-labs/workflow-runtime 1.1.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.
@@ -0,0 +1,524 @@
1
+ import { StepSpec } from '@kb-labs/workflow-contracts';
2
+ import { ArtifactClient } from '@kb-labs/workflow-artifacts';
3
+ export { ArtifactClient, ArtifactInput, ArtifactOutput, ArtifactReference, FileSystemArtifactClient, createFileSystemArtifactClient } from '@kb-labs/workflow-artifacts';
4
+ import { StepState } from '@kb-labs/workflow-constants';
5
+ import { PluginContextV3, ExecutionTarget } from '@kb-labs/plugin-contracts';
6
+ import { ExecutionBackend } from '@kb-labs/plugin-execution';
7
+ import { IEntityRegistry, RegistrySnapshot } from '@kb-labs/core-registry';
8
+ import { IAnalytics } from '@kb-labs/core-platform';
9
+ import { z } from 'zod';
10
+
11
+ interface RuntimeLogger {
12
+ debug(message: string, meta?: Record<string, unknown>): void;
13
+ info(message: string, meta?: Record<string, unknown>): void;
14
+ warn(message: string, meta?: Record<string, unknown>): void;
15
+ error(message: string, meta?: Record<string, unknown>): void;
16
+ }
17
+ interface RuntimeEvents {
18
+ emit(name: string, payload: Record<string, unknown>): Promise<void> | void;
19
+ }
20
+ interface RuntimeTrace {
21
+ traceId: string;
22
+ spanId?: string;
23
+ parentSpanId?: string;
24
+ }
25
+ interface StepContext {
26
+ runId: string;
27
+ jobId: string;
28
+ stepId: string;
29
+ attempt: number;
30
+ env: Record<string, string>;
31
+ secrets: Record<string, string>;
32
+ artifacts?: ArtifactClient;
33
+ events?: RuntimeEvents;
34
+ logger: RuntimeLogger;
35
+ trace?: RuntimeTrace;
36
+ pluginContext?: PluginContextV3;
37
+ onLog?: (entry: {
38
+ level: string;
39
+ message: string;
40
+ stream: 'stdout' | 'stderr';
41
+ lineNo: number;
42
+ timestamp: string;
43
+ meta?: Record<string, unknown>;
44
+ }) => void;
45
+ }
46
+ interface StepExecutionRequest {
47
+ spec: StepSpec;
48
+ context: StepContext;
49
+ workspace?: string;
50
+ target?: ExecutionTarget;
51
+ signal?: AbortSignal;
52
+ }
53
+ interface StepExecutionSuccess {
54
+ status: Extract<StepState, 'success'>;
55
+ outputs?: Record<string, unknown>;
56
+ }
57
+ interface StepExecutionFailure {
58
+ status: Extract<StepState, 'failed' | 'cancelled'>;
59
+ error: {
60
+ message: string;
61
+ code?: string;
62
+ stack?: string;
63
+ details?: Record<string, unknown>;
64
+ };
65
+ }
66
+ type StepExecutionResult = StepExecutionSuccess | StepExecutionFailure;
67
+ interface Runner {
68
+ execute(request: StepExecutionRequest): Promise<StepExecutionResult>;
69
+ }
70
+
71
+ interface CreateStepContextInput {
72
+ runId: string;
73
+ jobId: string;
74
+ stepId: string;
75
+ attempt?: number;
76
+ env?: Record<string, string>;
77
+ secrets?: Record<string, string>;
78
+ artifacts?: ArtifactClient;
79
+ events?: RuntimeEvents;
80
+ logger: RuntimeLogger;
81
+ trace?: RuntimeTrace;
82
+ }
83
+ declare function createStepContext(input: CreateStepContextInput): StepContext;
84
+
85
+ interface LocalRunnerOptions {
86
+ shell?: string;
87
+ }
88
+ declare class LocalRunner implements Runner {
89
+ private readonly shell;
90
+ constructor(options?: LocalRunnerOptions);
91
+ execute(request: StepExecutionRequest): Promise<StepExecutionResult>;
92
+ }
93
+
94
+ /**
95
+ * @module @kb-labs/workflow-runtime/runners/sandbox-runner
96
+ *
97
+ * V3 SandboxRunner - executes plugin handlers using platform ExecutionBackend.
98
+ *
99
+ * This runner is for steps that specify `uses: "plugin:..."` or `uses: "command:..."`.
100
+ * It delegates execution to the platform's unified ExecutionBackend instead of
101
+ * implementing custom plugin execution logic.
102
+ *
103
+ * ## Integration Pattern (REST API-style)
104
+ *
105
+ * Instead of resolving plugins inline inside the runner, we:
106
+ * 1. Accept ExecutionBackend from platform (via options)
107
+ * 2. Build ExecutionRequest with PluginContextDescriptor
108
+ * 3. Call backend.execute() - platform handles the rest
109
+ *
110
+ * This matches the REST API pattern where execution is delegated to the platform layer.
111
+ *
112
+ * @example
113
+ * ```typescript
114
+ * const runner = new SandboxRunner({
115
+ * backend: platform.executionBackend,
116
+ * cliApi, // For plugin resolution
117
+ * });
118
+ *
119
+ * const result = await runner.execute({
120
+ * spec: { uses: 'plugin:release-manager/create-release', with: { version: '1.0.0' } },
121
+ * context: stepContext,
122
+ * });
123
+ * ```
124
+ */
125
+
126
+ interface SandboxRunnerOptions {
127
+ /**
128
+ * Platform ExecutionBackend (REQUIRED).
129
+ * Obtained from platform.executionBackend.
130
+ */
131
+ backend: ExecutionBackend;
132
+ /**
133
+ * CLI API for plugin resolution (REQUIRED).
134
+ * Needed to resolve plugin IDs to plugin roots and handler paths.
135
+ */
136
+ cliApi: IEntityRegistry;
137
+ /**
138
+ * Workspace root directory.
139
+ * Default: process.cwd()
140
+ */
141
+ workspaceRoot?: string;
142
+ /**
143
+ * Default timeout for plugin execution (ms).
144
+ * Default: 120000 (2 minutes)
145
+ */
146
+ defaultTimeout?: number;
147
+ /**
148
+ * Platform analytics adapter (OPTIONAL)
149
+ */
150
+ analytics?: IAnalytics;
151
+ }
152
+ /**
153
+ * SandboxRunner - V3 implementation using platform ExecutionBackend.
154
+ *
155
+ * Executes plugin handlers through the unified execution layer.
156
+ * Supports both `uses: "plugin:id/handler"` and `uses: "command:name"` syntax.
157
+ */
158
+ declare class SandboxRunner implements Runner {
159
+ private readonly backend;
160
+ private readonly cliApi;
161
+ private readonly workspaceRoot;
162
+ private readonly defaultTimeout;
163
+ private readonly analytics?;
164
+ private readonly logger?;
165
+ constructor(options: SandboxRunnerOptions);
166
+ execute(request: StepExecutionRequest): Promise<StepExecutionResult>;
167
+ /**
168
+ * Validate step spec and build error result if invalid
169
+ */
170
+ private buildValidationError;
171
+ /**
172
+ * Try to resolve command, returning result wrapper
173
+ */
174
+ private tryResolveCommand;
175
+ /**
176
+ * Build ExecutionRequest from resolved command
177
+ */
178
+ private buildExecutionRequest;
179
+ /**
180
+ * Map ExecutionResult to StepExecutionResult
181
+ */
182
+ private mapExecutionResult;
183
+ /**
184
+ * Resolve command reference to plugin handler.
185
+ *
186
+ * Supports three formats:
187
+ * - `plugin:id/handler` - workflow handler (native)
188
+ * - `command:name` - CLI command (via adapter)
189
+ * - `builtin:shell` - built-in shell execution
190
+ */
191
+ private resolveCommand;
192
+ /**
193
+ * Resolve plugin handler reference.
194
+ * Format: `plugin:id/handler` or `plugin:id/path/to/handler`
195
+ */
196
+ private resolvePluginHandler;
197
+ /**
198
+ * Resolve CLI command to plugin handler (with adapter).
199
+ *
200
+ * Format: `command:name` (e.g., `command:mind:rag-index`)
201
+ *
202
+ * This uses the CLI Adapter pattern to make CLI commands work in workflow context:
203
+ * - Searches for CLI command in plugin manifests
204
+ * - Wraps workflow input in CLI-compatible format { argv, flags, cwd }
205
+ * - Allows reusing existing CLI commands without writing workflow handlers
206
+ */
207
+ private resolveCLICommand;
208
+ /**
209
+ * CLI Adapter: Convert workflow input to CLI-compatible format.
210
+ *
211
+ * Transforms:
212
+ * { scope: "default", incremental: true }
213
+ * Into:
214
+ * { argv: [], flags: { scope: "default", incremental: true }, cwd: "/workspace" }
215
+ *
216
+ * This allows CLI commands to work in workflow context without modification.
217
+ */
218
+ private adaptToCLIFormat;
219
+ /**
220
+ * Resolve builtin:shell to built-in shell handler.
221
+ *
222
+ * Returns a resolution pointing to the builtin-handlers/shell.js file
223
+ * that will be executed through ExecutionBackend.
224
+ */
225
+ private resolveBuiltinShell;
226
+ }
227
+
228
+ declare const RemoteMarketplaceSourceSchema: z.ZodObject<{
229
+ name: z.ZodString;
230
+ url: z.ZodString;
231
+ ref: z.ZodOptional<z.ZodString>;
232
+ path: z.ZodOptional<z.ZodString>;
233
+ }, "strip", z.ZodTypeAny, {
234
+ name: string;
235
+ url: string;
236
+ ref?: string | undefined;
237
+ path?: string | undefined;
238
+ }, {
239
+ name: string;
240
+ url: string;
241
+ ref?: string | undefined;
242
+ path?: string | undefined;
243
+ }>;
244
+ declare const BudgetConfigSchema: z.ZodObject<{
245
+ enabled: z.ZodDefault<z.ZodBoolean>;
246
+ limit: z.ZodOptional<z.ZodNumber>;
247
+ period: z.ZodDefault<z.ZodEnum<["run", "day", "week", "month"]>>;
248
+ action: z.ZodDefault<z.ZodEnum<["warn", "fail", "cancel"]>>;
249
+ costCalculator: z.ZodOptional<z.ZodString>;
250
+ }, "strip", z.ZodTypeAny, {
251
+ enabled: boolean;
252
+ period: "run" | "day" | "week" | "month";
253
+ action: "warn" | "fail" | "cancel";
254
+ limit?: number | undefined;
255
+ costCalculator?: string | undefined;
256
+ }, {
257
+ enabled?: boolean | undefined;
258
+ limit?: number | undefined;
259
+ period?: "run" | "day" | "week" | "month" | undefined;
260
+ action?: "warn" | "fail" | "cancel" | undefined;
261
+ costCalculator?: string | undefined;
262
+ }>;
263
+ declare const WorkflowConfigSchema: z.ZodObject<{
264
+ workspaces: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
265
+ plugins: z.ZodDefault<z.ZodBoolean>;
266
+ remotes: z.ZodOptional<z.ZodArray<z.ZodObject<{
267
+ name: z.ZodString;
268
+ url: z.ZodString;
269
+ ref: z.ZodOptional<z.ZodString>;
270
+ path: z.ZodOptional<z.ZodString>;
271
+ }, "strip", z.ZodTypeAny, {
272
+ name: string;
273
+ url: string;
274
+ ref?: string | undefined;
275
+ path?: string | undefined;
276
+ }, {
277
+ name: string;
278
+ url: string;
279
+ ref?: string | undefined;
280
+ path?: string | undefined;
281
+ }>, "many">>;
282
+ maxDepth: z.ZodDefault<z.ZodNumber>;
283
+ budget: z.ZodOptional<z.ZodObject<{
284
+ enabled: z.ZodDefault<z.ZodBoolean>;
285
+ limit: z.ZodOptional<z.ZodNumber>;
286
+ period: z.ZodDefault<z.ZodEnum<["run", "day", "week", "month"]>>;
287
+ action: z.ZodDefault<z.ZodEnum<["warn", "fail", "cancel"]>>;
288
+ costCalculator: z.ZodOptional<z.ZodString>;
289
+ }, "strip", z.ZodTypeAny, {
290
+ enabled: boolean;
291
+ period: "run" | "day" | "week" | "month";
292
+ action: "warn" | "fail" | "cancel";
293
+ limit?: number | undefined;
294
+ costCalculator?: string | undefined;
295
+ }, {
296
+ enabled?: boolean | undefined;
297
+ limit?: number | undefined;
298
+ period?: "run" | "day" | "week" | "month" | undefined;
299
+ action?: "warn" | "fail" | "cancel" | undefined;
300
+ costCalculator?: string | undefined;
301
+ }>>;
302
+ defaults: z.ZodOptional<z.ZodObject<{
303
+ mode: z.ZodDefault<z.ZodEnum<["wait", "fire-and-forget"]>>;
304
+ inheritEnv: z.ZodDefault<z.ZodBoolean>;
305
+ }, "strip", z.ZodTypeAny, {
306
+ mode: "wait" | "fire-and-forget";
307
+ inheritEnv: boolean;
308
+ }, {
309
+ mode?: "wait" | "fire-and-forget" | undefined;
310
+ inheritEnv?: boolean | undefined;
311
+ }>>;
312
+ }, "strip", z.ZodTypeAny, {
313
+ workspaces: string[];
314
+ plugins: boolean;
315
+ maxDepth: number;
316
+ remotes?: {
317
+ name: string;
318
+ url: string;
319
+ ref?: string | undefined;
320
+ path?: string | undefined;
321
+ }[] | undefined;
322
+ budget?: {
323
+ enabled: boolean;
324
+ period: "run" | "day" | "week" | "month";
325
+ action: "warn" | "fail" | "cancel";
326
+ limit?: number | undefined;
327
+ costCalculator?: string | undefined;
328
+ } | undefined;
329
+ defaults?: {
330
+ mode: "wait" | "fire-and-forget";
331
+ inheritEnv: boolean;
332
+ } | undefined;
333
+ }, {
334
+ workspaces?: string[] | undefined;
335
+ plugins?: boolean | undefined;
336
+ remotes?: {
337
+ name: string;
338
+ url: string;
339
+ ref?: string | undefined;
340
+ path?: string | undefined;
341
+ }[] | undefined;
342
+ maxDepth?: number | undefined;
343
+ budget?: {
344
+ enabled?: boolean | undefined;
345
+ limit?: number | undefined;
346
+ period?: "run" | "day" | "week" | "month" | undefined;
347
+ action?: "warn" | "fail" | "cancel" | undefined;
348
+ costCalculator?: string | undefined;
349
+ } | undefined;
350
+ defaults?: {
351
+ mode?: "wait" | "fire-and-forget" | undefined;
352
+ inheritEnv?: boolean | undefined;
353
+ } | undefined;
354
+ }>;
355
+ type WorkflowConfig = z.infer<typeof WorkflowConfigSchema>;
356
+ type RemoteMarketplaceSource = z.infer<typeof RemoteMarketplaceSourceSchema>;
357
+ type BudgetConfig = z.infer<typeof BudgetConfigSchema>;
358
+ /**
359
+ * Load workflow configuration from kb.config.json
360
+ */
361
+ declare function loadWorkflowConfig(workspaceRoot: string): Promise<WorkflowConfig>;
362
+ /**
363
+ * Save workflow configuration to kb.config.json
364
+ * Safely merges with existing config without overwriting other sections
365
+ */
366
+ declare function saveWorkflowConfig(workspaceRoot: string, updates: Partial<WorkflowConfig>): Promise<void>;
367
+
368
+ /**
369
+ * Resolved workflow information from registry
370
+ */
371
+ interface ResolvedWorkflow {
372
+ /** Workflow ID (e.g., "workspace:ai-ci", "plugin:@kb-labs/ai-review/full-audit") */
373
+ id: string;
374
+ /** Source of the workflow */
375
+ source: 'workspace' | 'plugin';
376
+ /** Absolute path to workflow file (YAML/JSON) */
377
+ filePath: string;
378
+ /** Optional description from workflow spec */
379
+ description?: string;
380
+ /** Optional tags for filtering */
381
+ tags?: string[];
382
+ /** Optional metadata (plugin ID, version, etc.) */
383
+ metadata?: {
384
+ pluginId?: string;
385
+ pluginVersion?: string;
386
+ };
387
+ }
388
+ /**
389
+ * Base interface for workflow registry
390
+ */
391
+ interface WorkflowRegistry {
392
+ /**
393
+ * List all discovered workflows (cached)
394
+ */
395
+ list(): Promise<ResolvedWorkflow[]>;
396
+ /**
397
+ * Resolve workflow by ID
398
+ * @param id - Workflow ID (with or without prefix)
399
+ */
400
+ resolve(id: string): Promise<ResolvedWorkflow | null>;
401
+ /**
402
+ * Refresh the cache (explicit update)
403
+ */
404
+ refresh(): Promise<void>;
405
+ /**
406
+ * Cleanup resources
407
+ */
408
+ dispose?(): Promise<void>;
409
+ }
410
+ /**
411
+ * Configuration for workflow registry
412
+ */
413
+ interface WorkflowRegistryConfig {
414
+ /** Workspace root directory */
415
+ workspaceRoot: string;
416
+ /** Glob patterns for workspace workflows */
417
+ workspaces?: string[];
418
+ /** Include plugin workflows */
419
+ plugins?: boolean;
420
+ /** Cache configuration */
421
+ cache?: {
422
+ /** Time-to-live in milliseconds (optional, for future) */
423
+ ttl?: number;
424
+ };
425
+ }
426
+
427
+ interface WorkspaceWorkflowRegistryConfig {
428
+ workspaceRoot: string;
429
+ patterns: string[];
430
+ }
431
+ /**
432
+ * Registry for workspace workflows (from .kb/workflows glob patterns)
433
+ */
434
+ declare class WorkspaceWorkflowRegistry implements WorkflowRegistry {
435
+ private readonly config;
436
+ private cache;
437
+ constructor(config: WorkspaceWorkflowRegistryConfig);
438
+ list(): Promise<ResolvedWorkflow[]>;
439
+ resolve(id: string): Promise<ResolvedWorkflow | null>;
440
+ refresh(): Promise<void>;
441
+ dispose(): Promise<void>;
442
+ private loadWorkflowSpec;
443
+ private generateId;
444
+ }
445
+
446
+ interface LoggerLike {
447
+ debug?(msg: string, meta?: Record<string, unknown>): void;
448
+ info?(msg: string, meta?: Record<string, unknown>): void;
449
+ warn?(msg: string, meta?: Record<string, unknown>): void;
450
+ error?(msg: string, meta?: Record<string, unknown>): void;
451
+ }
452
+ interface RemoteWorkflowRegistryConfig {
453
+ workspaceRoot: string;
454
+ remotes: RemoteMarketplaceSource[];
455
+ cacheDir?: string;
456
+ logger?: LoggerLike;
457
+ }
458
+ /**
459
+ * Registry for remote workflows (from git repositories)
460
+ */
461
+ declare class RemoteWorkflowRegistry implements WorkflowRegistry {
462
+ private readonly config;
463
+ private cache;
464
+ private readonly cacheDir;
465
+ private readonly logger?;
466
+ constructor(config: RemoteWorkflowRegistryConfig);
467
+ list(): Promise<ResolvedWorkflow[]>;
468
+ resolve(id: string): Promise<ResolvedWorkflow | null>;
469
+ refresh(): Promise<void>;
470
+ dispose(): Promise<void>;
471
+ private loadWorkflowsFromRemote;
472
+ private ensureRemoteCloned;
473
+ private updateRemote;
474
+ private loadWorkflowSpec;
475
+ private generateId;
476
+ private getRepoName;
477
+ }
478
+
479
+ /**
480
+ * Composite registry that combines workspace, plugin (via IEntityRegistry), and remote registries
481
+ */
482
+ declare class CompositeWorkflowRegistry implements WorkflowRegistry {
483
+ private readonly workspace;
484
+ private readonly cliApi;
485
+ private readonly remote?;
486
+ private cache;
487
+ constructor(workspace: WorkspaceWorkflowRegistry, cliApi: IEntityRegistry | null, remote?: RemoteWorkflowRegistry | undefined);
488
+ list(): Promise<ResolvedWorkflow[]>;
489
+ resolve(id: string): Promise<ResolvedWorkflow | null>;
490
+ refresh(): Promise<void>;
491
+ dispose(): Promise<void>;
492
+ }
493
+
494
+ /**
495
+ * Error thrown when workflow ID conflicts are detected
496
+ */
497
+ declare class WorkflowRegistryError extends Error {
498
+ readonly workflowId?: string | undefined;
499
+ constructor(message: string, workflowId?: string | undefined);
500
+ }
501
+
502
+ /**
503
+ * Extract workflows from CLI API registry snapshot
504
+ *
505
+ * Uses the same pattern as REST API - no local discovery, just snapshot extraction.
506
+ */
507
+
508
+ /**
509
+ * Extract workflows from registry snapshot
510
+ *
511
+ * @param snapshot - CLI API registry snapshot
512
+ * @returns Array of resolved workflows from plugin manifests
513
+ */
514
+ declare function extractWorkflows(snapshot: RegistrySnapshot): Promise<ResolvedWorkflow[]>;
515
+ /**
516
+ * Find workflow by ID in registry snapshot
517
+ *
518
+ * @param snapshot - CLI API registry snapshot
519
+ * @param id - Workflow ID (with or without "plugin:" prefix)
520
+ * @returns Resolved workflow or null if not found
521
+ */
522
+ declare function findWorkflow(snapshot: RegistrySnapshot, id: string): Promise<ResolvedWorkflow | null>;
523
+
524
+ export { type BudgetConfig, BudgetConfigSchema, CompositeWorkflowRegistry, type CreateStepContextInput, LocalRunner, type LocalRunnerOptions, type RemoteMarketplaceSource, RemoteMarketplaceSourceSchema, type ResolvedWorkflow, type Runner, type RuntimeEvents, type RuntimeLogger, type RuntimeTrace, SandboxRunner, type SandboxRunnerOptions, type StepContext, type StepExecutionFailure, type StepExecutionRequest, type StepExecutionResult, type StepExecutionSuccess, type WorkflowConfig, WorkflowConfigSchema, type WorkflowRegistry, type WorkflowRegistryConfig, WorkflowRegistryError, WorkspaceWorkflowRegistry, createStepContext, extractWorkflows, findWorkflow, loadWorkflowConfig, saveWorkflowConfig };