@kb-labs/workflow-engine 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,1057 @@
1
+ import { WorkflowSpec, WorkflowRun, JobRun, StepRun, RunTrigger, IdempotencyKey, ConcurrencyGroup, RetryPolicy, ArtifactMergeConfig } from '@kb-labs/workflow-contracts';
2
+ import { ILogger, ICache, IEventBus, IAnalytics, Unsubscribe, ICronManager, IJobScheduler, JobDefinition, JobHandle, CronExpression, JobFilter } from '@kb-labs/core-platform';
3
+ import { JobPriority, WorkflowEventName } from '@kb-labs/workflow-constants';
4
+ import { ArtifactClient } from '@kb-labs/workflow-artifacts';
5
+ import { IEntityRegistry } from '@kb-labs/core-registry';
6
+ import { PlatformServices, JobHandlerDecl, PluginContextDescriptor } from '@kb-labs/plugin-contracts';
7
+ import { IExecutionBackend } from '@kb-labs/core-contracts';
8
+
9
+ /**
10
+ * @deprecated Use ILogger from @kb-labs/core-platform instead.
11
+ * This type alias is kept for backward compatibility.
12
+ */
13
+ type EngineLogger = ILogger;
14
+ interface WorkflowLoaderResult {
15
+ spec: WorkflowSpec;
16
+ source: string;
17
+ }
18
+ interface RunContext {
19
+ run: WorkflowRun;
20
+ jobs: JobRun[];
21
+ steps: StepRun[];
22
+ }
23
+ interface CreateRunInput {
24
+ spec: WorkflowSpec;
25
+ trigger: RunTrigger;
26
+ idempotencyKey?: IdempotencyKey;
27
+ concurrencyGroup?: ConcurrencyGroup;
28
+ metadata?: Record<string, unknown>;
29
+ env?: Record<string, string>;
30
+ }
31
+
32
+ interface WorkflowLoaderOptions {
33
+ cwd?: string;
34
+ }
35
+ declare class WorkflowLoader {
36
+ private readonly logger;
37
+ constructor(logger: EngineLogger);
38
+ fromFile(filePath: string, options?: WorkflowLoaderOptions): Promise<WorkflowLoaderResult>;
39
+ fromInline(spec: unknown, source?: string): WorkflowLoaderResult;
40
+ private parse;
41
+ private validate;
42
+ }
43
+
44
+ declare class StateStore {
45
+ private readonly logger;
46
+ private readonly cache;
47
+ constructor(cache: ICache, logger: EngineLogger);
48
+ saveRun(run: WorkflowRun): Promise<void>;
49
+ getRun(runId: string): Promise<WorkflowRun | null>;
50
+ deleteRun(runId: string): Promise<void>;
51
+ getAllRunIds(): Promise<string[]>;
52
+ updateRun(runId: string, mutator: (draft: WorkflowRun) => WorkflowRun | void): Promise<WorkflowRun | null>;
53
+ updateJob(runId: string, jobId: string, mutator: (job: JobRun) => JobRun | void): Promise<JobRun | null>;
54
+ updateStep(runId: string, jobId: string, stepId: string, mutator: (step: StepRun) => StepRun | void): Promise<StepRun | null>;
55
+ releaseBlockedJobs(runId: string, completedJobName: string): Promise<JobRun[]>;
56
+ }
57
+
58
+ interface AcquireOptions {
59
+ ttlMs?: number;
60
+ }
61
+ declare class ConcurrencyManager {
62
+ private readonly logger;
63
+ private readonly cache;
64
+ private readonly ttlMs;
65
+ constructor(cache: ICache, logger: EngineLogger, options?: AcquireOptions);
66
+ acquire(group: ConcurrencyGroup, runId: string, options?: AcquireOptions): Promise<boolean>;
67
+ release(group: ConcurrencyGroup, runId: string): Promise<void>;
68
+ getActiveRun(group: ConcurrencyGroup): Promise<string | null>;
69
+ }
70
+
71
+ interface RunCoordinatorOptions {
72
+ idempotencyTtlMs?: number;
73
+ }
74
+ declare class RunCoordinator {
75
+ private readonly stateStore;
76
+ private readonly concurrencyManager;
77
+ private readonly logger;
78
+ private readonly cache;
79
+ private readonly idempotencyTtlMs;
80
+ constructor(cache: ICache, stateStore: StateStore, concurrencyManager: ConcurrencyManager, logger: EngineLogger, options?: RunCoordinatorOptions);
81
+ ensureRun(input: CreateRunInput): Promise<WorkflowRun>;
82
+ private buildInitialRun;
83
+ private registerIdempotencyKey;
84
+ private loadByIdempotencyKey;
85
+ releaseConcurrency(run: WorkflowRun): Promise<void>;
86
+ }
87
+
88
+ interface JobQueueEntry {
89
+ id: string;
90
+ runId: string;
91
+ jobId: string;
92
+ priority: JobPriority;
93
+ enqueuedAt: string;
94
+ availableAt: number;
95
+ jobName: string;
96
+ }
97
+ interface SchedulerOptions {
98
+ defaultPriority?: JobPriority;
99
+ lookAheadMs?: number;
100
+ }
101
+ declare class Scheduler {
102
+ private readonly logger;
103
+ private readonly cache;
104
+ private readonly defaultPriority;
105
+ private readonly lookAheadMs;
106
+ private readonly priorityOrder;
107
+ constructor(cache: ICache, logger: EngineLogger, options?: SchedulerOptions);
108
+ scheduleRun(run: WorkflowRun): Promise<void>;
109
+ enqueueJob(runId: string, job: JobRun, priority?: JobPriority): Promise<void>;
110
+ dequeueJob(): Promise<JobQueueEntry | null>;
111
+ reschedule(entry: JobQueueEntry, delayMs: number): Promise<void>;
112
+ private dequeueFromPriority;
113
+ getDefaultPriority(): JobPriority;
114
+ }
115
+
116
+ interface SecretProvider {
117
+ resolve(names: string[]): Promise<Record<string, string>>;
118
+ }
119
+ interface EnvSecretProviderOptions {
120
+ /**
121
+ * Prefix applied when looking up secrets in environment variables.
122
+ * Defaults to `KB_SECRET_`.
123
+ */
124
+ prefix?: string;
125
+ /**
126
+ * When true (default), check both plain and prefixed environment variable names.
127
+ */
128
+ allowPlain?: boolean;
129
+ }
130
+ declare class EnvSecretProvider implements SecretProvider {
131
+ private readonly prefix;
132
+ private readonly allowPlain;
133
+ constructor(options?: EnvSecretProviderOptions);
134
+ resolve(names: string[]): Promise<Record<string, string>>;
135
+ }
136
+ declare function createDefaultSecretProvider(): SecretProvider;
137
+
138
+ interface WorkflowEvent<TPayload = Record<string, unknown>> {
139
+ type: WorkflowEventName;
140
+ runId: string;
141
+ jobId?: string;
142
+ stepId?: string;
143
+ payload?: TPayload;
144
+ timestamp?: string;
145
+ }
146
+ declare class EventBusBridge {
147
+ private readonly logger;
148
+ private readonly events;
149
+ private readonly channel;
150
+ constructor(events: IEventBus, logger: EngineLogger);
151
+ publish<TPayload = Record<string, unknown>>(event: WorkflowEvent<TPayload>): Promise<void>;
152
+ }
153
+
154
+ interface RetryDecision {
155
+ shouldRetry: boolean;
156
+ nextDelayMs?: number;
157
+ }
158
+ declare function calculateBackoff(attempt: number, policy?: RetryPolicy): number;
159
+ declare function shouldRetry(attempt: number, policy?: RetryPolicy): RetryDecision;
160
+
161
+ interface RunSnapshot {
162
+ runId: string;
163
+ run: WorkflowRun;
164
+ stepOutputs: Record<string, Record<string, unknown>>;
165
+ env: Record<string, string>;
166
+ refs?: {
167
+ workspaceSnapshotId?: string;
168
+ environmentSnapshotId?: string;
169
+ };
170
+ createdAt: string;
171
+ version: string;
172
+ }
173
+ declare class RunSnapshotStorage {
174
+ private readonly cache;
175
+ private readonly logger;
176
+ constructor(cache: ICache, logger: EngineLogger);
177
+ private getSnapshotKey;
178
+ createSnapshot(run: WorkflowRun, stepOutputs: Record<string, Record<string, unknown>>, env: Record<string, string>, refs?: RunSnapshot['refs']): Promise<RunSnapshot>;
179
+ getSnapshot(runId: string): Promise<RunSnapshot | null>;
180
+ deleteSnapshot(runId: string): Promise<void>;
181
+ }
182
+
183
+ interface SnapshotManagerClient {
184
+ restoreSnapshot(request: {
185
+ snapshotId: string;
186
+ workspaceId?: string;
187
+ environmentId?: string;
188
+ targetPath?: string;
189
+ overwrite?: boolean;
190
+ metadata?: Record<string, unknown>;
191
+ }): Promise<unknown>;
192
+ }
193
+ interface WorkflowEngineOptions {
194
+ scheduler?: SchedulerOptions;
195
+ concurrency?: AcquireOptions;
196
+ runCoordinator?: RunCoordinatorOptions;
197
+ maxWorkflowDepth?: number;
198
+ /** Platform cache adapter (REQUIRED) */
199
+ cache: ICache;
200
+ /** Platform event bus adapter (REQUIRED) */
201
+ events: IEventBus;
202
+ /** Platform logger (REQUIRED) */
203
+ logger: ILogger;
204
+ /** Platform analytics adapter (OPTIONAL) */
205
+ analytics?: IAnalytics;
206
+ /** Platform snapshot manager (OPTIONAL - for infra snapshot restore in replay) */
207
+ snapshotManager?: SnapshotManagerClient;
208
+ /** Workspace root (monorepo root) - used for plugin execution context */
209
+ workspaceRoot?: string;
210
+ }
211
+ declare class WorkflowEngine {
212
+ private readonly options;
213
+ readonly loader: WorkflowLoader;
214
+ readonly maxWorkflowDepth: number;
215
+ private readonly logger;
216
+ private readonly analytics?;
217
+ private readonly stateStore;
218
+ private readonly concurrency;
219
+ private readonly runCoordinator;
220
+ private readonly scheduler;
221
+ private readonly events;
222
+ private readonly snapshotStorage;
223
+ constructor(options: WorkflowEngineOptions);
224
+ dispose(): Promise<void>;
225
+ /**
226
+ * Subscribe to real-time events for a specific workflow run.
227
+ * Events are filtered by runId from the shared event bus channel.
228
+ */
229
+ subscribeToRunEvents(runId: string, handler: (event: WorkflowEvent) => void): Unsubscribe;
230
+ createRun(input: CreateRunInput): Promise<WorkflowRun>;
231
+ runFromSpec(spec: WorkflowSpec, input: Omit<CreateRunInput, 'spec'>): Promise<WorkflowRun>;
232
+ runFromFile(filePath: string, input: Omit<CreateRunInput, 'spec'>): Promise<WorkflowRun>;
233
+ runFromInline(spec: unknown, input: Omit<CreateRunInput, 'spec'>): Promise<WorkflowRun>;
234
+ getRun(runId: string): Promise<WorkflowRun | null>;
235
+ cancelRun(runId: string): Promise<void>;
236
+ /**
237
+ * Mark job as failed and optionally schedule retry.
238
+ * Implements exponential/linear backoff retry logic.
239
+ */
240
+ markJobFailed(runId: string, jobId: string, error: Error, shouldRetry?: boolean): Promise<void>;
241
+ /**
242
+ * Mark job as interrupted (e.g., during graceful shutdown).
243
+ * Interrupted jobs will be retried on next daemon startup.
244
+ */
245
+ markJobInterrupted(runId: string, jobId: string): Promise<void>;
246
+ /**
247
+ * Mark job as started (running).
248
+ */
249
+ markJobStarted(runId: string, jobId: string): Promise<void>;
250
+ /**
251
+ * Mark job as completed successfully.
252
+ */
253
+ markJobCompleted(runId: string, jobId: string): Promise<void>;
254
+ /**
255
+ * Check if all jobs in a run are completed and update run status accordingly.
256
+ */
257
+ private checkRunCompletion;
258
+ /**
259
+ * Mark step as started (running).
260
+ */
261
+ markStepStarted(runId: string, jobId: string, stepId: string): Promise<void>;
262
+ /**
263
+ * Mark step as completed successfully with output.
264
+ */
265
+ markStepCompleted(runId: string, jobId: string, stepId: string, output?: unknown): Promise<void>;
266
+ /**
267
+ * Mark step as failed with error.
268
+ */
269
+ markStepFailed(runId: string, jobId: string, stepId: string, error: Error, outputs?: Record<string, unknown>): Promise<void>;
270
+ /**
271
+ * Mark step as waiting for human approval.
272
+ */
273
+ markStepWaitingApproval(runId: string, jobId: string, stepId: string): Promise<void>;
274
+ /**
275
+ * Resolve a pending approval — approve or reject.
276
+ * On approve: marks step as success with approval outputs.
277
+ * On reject: marks step as failed with rejection error.
278
+ */
279
+ resolveApproval(runId: string, jobId: string, stepId: string, action: 'approve' | 'reject', data?: Record<string, unknown>, comment?: string): Promise<void>;
280
+ /**
281
+ * Get the state store for direct access (used by worker for gate restart-from).
282
+ */
283
+ getStateStore(): StateStore;
284
+ /**
285
+ * Get the scheduler for direct access (used by worker for gate re-enqueue).
286
+ */
287
+ getScheduler(): Scheduler;
288
+ /**
289
+ * Mark stale running/queued runs as failed on daemon startup.
290
+ * Runs that were in-flight when the daemon crashed are unrecoverable —
291
+ * their executor process is gone, so we mark them failed immediately.
292
+ */
293
+ cleanupStaleRuns(): Promise<void>;
294
+ /**
295
+ * Resume interrupted jobs on daemon startup.
296
+ * Re-queues jobs that were interrupted during previous shutdown.
297
+ */
298
+ resumeInterruptedJobs(): Promise<void>;
299
+ /**
300
+ * Determine if job should be retried based on retry policy.
301
+ */
302
+ private shouldRetryJob;
303
+ /**
304
+ * Calculate backoff delay using exponential or linear strategy.
305
+ */
306
+ private calculateBackoff;
307
+ /**
308
+ * Move permanently failed job to Dead Letter Queue.
309
+ */
310
+ private moveToDLQ;
311
+ updateRun(runId: string, mutator: (run: WorkflowRun) => WorkflowRun | void): Promise<WorkflowRun | null>;
312
+ finalizeRun(runId: string, status: WorkflowRun['status'], context?: Partial<RunContext>): Promise<WorkflowRun | null>;
313
+ nextJob(): Promise<JobQueueEntry | null>;
314
+ rescheduleJob(entry: JobQueueEntry, delayMs: number): Promise<void>;
315
+ publishRunEvent(type: WorkflowEventName, run: WorkflowRun): Promise<void>;
316
+ /**
317
+ * Publish a log entry for real-time streaming to Studio UI.
318
+ */
319
+ publishLog(runId: string, jobId: string, stepId: string, entry: {
320
+ level: string;
321
+ message: string;
322
+ stream: string;
323
+ lineNo: number;
324
+ timestamp: string;
325
+ meta?: Record<string, unknown>;
326
+ }): Promise<void>;
327
+ /**
328
+ * Create a snapshot of the current run state
329
+ */
330
+ createSnapshot(runId: string, stepOutputs: Record<string, Record<string, unknown>>, env: Record<string, string>, refs?: RunSnapshot['refs']): Promise<RunSnapshot | null>;
331
+ /**
332
+ * Get a snapshot for a run
333
+ */
334
+ getSnapshot(runId: string): Promise<RunSnapshot | null>;
335
+ /**
336
+ * Replay a run from a snapshot, optionally starting from a specific step
337
+ */
338
+ replayRun(runId: string, options?: {
339
+ fromStepId?: string;
340
+ stepOutputs?: Record<string, Record<string, unknown>>;
341
+ env?: Record<string, string>;
342
+ }): Promise<WorkflowRun | null>;
343
+ /**
344
+ * Delete a snapshot
345
+ */
346
+ deleteSnapshot(runId: string): Promise<void>;
347
+ /**
348
+ * Get all active workflow executions (running or queued).
349
+ * Returns array of WorkflowRun objects with status 'running' or 'queued'.
350
+ */
351
+ getActiveExecutions(): Promise<WorkflowRun[]>;
352
+ /**
353
+ * Get all workflow runs (all statuses).
354
+ * Returns array of all WorkflowRun objects ordered by creation time.
355
+ */
356
+ getAllRuns(): Promise<WorkflowRun[]>;
357
+ /**
358
+ * List all workflow runs.
359
+ * Returns array of all runs in the system.
360
+ * Alias for getAllRuns() - maintained for backward compatibility.
361
+ */
362
+ listRuns(): Promise<WorkflowRun[]>;
363
+ /**
364
+ * Get workflow engine metrics.
365
+ * Returns statistics about runs, jobs, and system health.
366
+ */
367
+ getMetrics(): Promise<{
368
+ runs: {
369
+ total: number;
370
+ queued: number;
371
+ running: number;
372
+ completed: number;
373
+ failed: number;
374
+ cancelled: number;
375
+ dlq: number;
376
+ };
377
+ jobs: {
378
+ total: number;
379
+ queued: number;
380
+ running: number;
381
+ completed: number;
382
+ failed: number;
383
+ };
384
+ }>;
385
+ }
386
+
387
+ interface ArtifactMergerOptions {
388
+ stateStore: StateStore;
389
+ logger: EngineLogger;
390
+ artifactsRoot: string;
391
+ }
392
+ declare class ArtifactMerger {
393
+ private readonly options;
394
+ constructor(options: ArtifactMergerOptions);
395
+ mergeArtifacts(config: ArtifactMergeConfig, targetArtifacts: ArtifactClient, currentRunId: string): Promise<void>;
396
+ private loadArtifactsFromRun;
397
+ private loadArtifactContent;
398
+ private applyMergeStrategy;
399
+ private mergeAppend;
400
+ private mergeJson;
401
+ private deepMerge;
402
+ private saveMergedArtifact;
403
+ }
404
+
405
+ /**
406
+ * @module @kb-labs/workflow-engine/manifest-scanner
407
+ *
408
+ * Scans plugin manifests for workflows and jobs, converting them to unified WorkflowRuntime format.
409
+ *
410
+ * ## Features
411
+ * - Discovers workflows from `manifest.workflows.handlers`
412
+ * - Discovers jobs from `manifest.jobs`
413
+ * - Converts to unified WorkflowRuntime representation
414
+ * - Caches results via Platform state for performance
415
+ *
416
+ * ## Usage
417
+ * ```typescript
418
+ * const scanner = new ManifestScanner({ cliApi, platform });
419
+ * const workflows = await scanner.scanPlugins();
420
+ * ```
421
+ */
422
+
423
+ /**
424
+ * Workflow trigger type
425
+ */
426
+ type WorkflowTriggerType = 'manual' | 'webhook' | 'push' | 'schedule' | 'event';
427
+ /**
428
+ * Workflow trigger configuration
429
+ */
430
+ interface WorkflowTrigger {
431
+ type: WorkflowTriggerType;
432
+ config?: Record<string, unknown>;
433
+ }
434
+ /**
435
+ * Schedule configuration for workflows
436
+ */
437
+ interface WorkflowSchedule {
438
+ /** Cron expression (e.g., "0 2 * * *") */
439
+ cron: string;
440
+ /** Whether schedule is enabled */
441
+ enabled: boolean;
442
+ /** Next run time (calculated) */
443
+ nextRun?: Date;
444
+ /** Last run time */
445
+ lastRun?: Date;
446
+ }
447
+ /**
448
+ * Workflow runtime statistics
449
+ */
450
+ interface WorkflowStats {
451
+ totalRuns: number;
452
+ successRuns: number;
453
+ failedRuns: number;
454
+ lastRunStatus?: 'success' | 'failed' | 'cancelled';
455
+ lastRunAt?: Date;
456
+ avgDurationMs?: number;
457
+ }
458
+ /**
459
+ * Unified workflow runtime representation.
460
+ *
461
+ * Used for both manifest-based and standalone workflows.
462
+ */
463
+ interface WorkflowRuntime {
464
+ id: string;
465
+ source: 'manifest' | 'standalone';
466
+ pluginId?: string;
467
+ manifestPath?: string;
468
+ name: string;
469
+ description?: string;
470
+ tags?: string[];
471
+ triggers: WorkflowTrigger[];
472
+ handler?: string;
473
+ schedule?: WorkflowSchedule;
474
+ status: 'active' | 'paused' | 'disabled';
475
+ stats?: WorkflowStats;
476
+ permissions?: unknown;
477
+ input?: unknown;
478
+ output?: unknown;
479
+ inputSchema?: Record<string, {
480
+ type: 'string' | 'number' | 'boolean';
481
+ description?: string;
482
+ required?: boolean;
483
+ default?: unknown;
484
+ }>;
485
+ }
486
+ /**
487
+ * Options for ManifestScanner
488
+ */
489
+ interface ManifestScannerOptions {
490
+ /** CLI API instance */
491
+ cliApi: IEntityRegistry;
492
+ /** Platform services (for state, logger, etc.) */
493
+ platform: PlatformServices;
494
+ /** Cache TTL in milliseconds (default: 60000 = 1 minute) */
495
+ cacheTtlMs?: number;
496
+ }
497
+ /**
498
+ * Manifest Scanner Service
499
+ *
500
+ * Discovers workflows and jobs from installed plugin manifests.
501
+ */
502
+ declare class ManifestScanner {
503
+ private readonly cliApi;
504
+ private readonly platform;
505
+ private readonly cacheTtlMs;
506
+ constructor(options: ManifestScannerOptions);
507
+ /**
508
+ * Scan all installed plugins for workflows and jobs.
509
+ *
510
+ * Returns unified WorkflowRuntime representations.
511
+ */
512
+ scanPlugins(): Promise<WorkflowRuntime[]>;
513
+ /**
514
+ * Convert workflow handler declaration to WorkflowRuntime.
515
+ */
516
+ private convertWorkflowHandler;
517
+ /**
518
+ * Convert job handler declaration to WorkflowRuntime.
519
+ */
520
+ private convertJobHandler;
521
+ /**
522
+ * Convert cron schedule declaration to WorkflowRuntime.
523
+ */
524
+ private convertCronSchedule;
525
+ /**
526
+ * Scan all installed plugins for job handlers only.
527
+ *
528
+ * Returns information needed to register handlers in JobManager.
529
+ */
530
+ scanJobHandlers(): Promise<Array<{
531
+ pluginId: string;
532
+ pluginVersion: string;
533
+ pluginRoot: string;
534
+ handler: JobHandlerDecl;
535
+ }>>;
536
+ /**
537
+ * Clear cache (useful for testing or force refresh).
538
+ */
539
+ clearCache(): Promise<void>;
540
+ /**
541
+ * Watch for plugin changes and invalidate cache.
542
+ *
543
+ * @param callback Optional callback when workflows change
544
+ * @returns Unsubscribe function
545
+ */
546
+ watchPlugins(callback?: (workflows: WorkflowRuntime[]) => void): () => void;
547
+ }
548
+
549
+ /**
550
+ * @module @kb-labs/workflow-engine/workflow-repository
551
+ *
552
+ * Repository for standalone workflow definitions.
553
+ *
554
+ * ## Features
555
+ * - CRUD operations for user-created workflows
556
+ * - File-based storage via platform.storage (`.kb/workflows/*.yaml`)
557
+ * - Validation using WorkflowSpecSchema
558
+ * - Conversion to unified WorkflowRuntime format
559
+ *
560
+ * ## Usage
561
+ * ```typescript
562
+ * const repo = new WorkflowRepository({ platform });
563
+ * const workflow = await repo.create(spec);
564
+ * ```
565
+ */
566
+
567
+ /**
568
+ * List options for filtering workflows
569
+ */
570
+ interface WorkflowListOptions {
571
+ status?: 'active' | 'paused' | 'disabled';
572
+ tags?: string[];
573
+ limit?: number;
574
+ offset?: number;
575
+ }
576
+ /**
577
+ * Options for WorkflowRepository
578
+ */
579
+ interface WorkflowRepositoryOptions {
580
+ /** Platform services (for storage, logger, etc.) */
581
+ platform: PlatformServices;
582
+ /** Storage directory for workflows (default: '.kb/workflows') */
583
+ storageDir?: string;
584
+ /** Workspace root directory (default: process.cwd()) */
585
+ workspaceRoot?: string;
586
+ }
587
+ /**
588
+ * Workflow Repository
589
+ *
590
+ * Manages standalone workflow definitions (user-created via UI/API).
591
+ * Uses platform.storage for persistence.
592
+ */
593
+ declare class WorkflowRepository {
594
+ private readonly platform;
595
+ private readonly storageDir;
596
+ private readonly workspaceRoot;
597
+ private readonly absoluteStorageDir;
598
+ constructor(options: WorkflowRepositoryOptions);
599
+ /**
600
+ * Create a new standalone workflow.
601
+ */
602
+ create(spec: WorkflowSpec): Promise<WorkflowRuntime>;
603
+ /**
604
+ * Get workflow by ID.
605
+ */
606
+ get(id: string): Promise<WorkflowRuntime | null>;
607
+ /**
608
+ * List all workflows with optional filtering.
609
+ */
610
+ list(options?: WorkflowListOptions): Promise<WorkflowRuntime[]>;
611
+ /**
612
+ * Update existing workflow.
613
+ */
614
+ update(id: string, spec: Partial<WorkflowSpec>): Promise<WorkflowRuntime>;
615
+ /**
616
+ * Delete workflow.
617
+ */
618
+ delete(id: string): Promise<void>;
619
+ /**
620
+ * Enable workflow (set status to active).
621
+ */
622
+ enable(id: string): Promise<void>;
623
+ /**
624
+ * Disable workflow.
625
+ */
626
+ disable(id: string): Promise<void>;
627
+ /**
628
+ * Pause workflow.
629
+ */
630
+ pause(id: string): Promise<void>;
631
+ /**
632
+ * Resume workflow (unpause).
633
+ */
634
+ resume(id: string): Promise<void>;
635
+ /**
636
+ * Update workflow statistics.
637
+ */
638
+ updateStats(id: string, stats: Partial<WorkflowStats>): Promise<void>;
639
+ private updateStatus;
640
+ private getWorkflowPath;
641
+ private saveWorkflow;
642
+ private loadWorkflow;
643
+ private listWorkflowFiles;
644
+ /**
645
+ * Convert stored workflow to WorkflowRuntime format.
646
+ */
647
+ private toRuntime;
648
+ }
649
+
650
+ /**
651
+ * @module @kb-labs/workflow-engine/workflow-service
652
+ *
653
+ * Unified service for managing all workflows (manifest-based + standalone).
654
+ *
655
+ * ## Features
656
+ * - Combines ManifestScanner and WorkflowRepository
657
+ * - Unified interface for listing/getting workflows from both sources
658
+ * - Provides available handlers for UI autocomplete
659
+ * - Validates workflow specs
660
+ *
661
+ * ## Usage
662
+ * ```typescript
663
+ * const service = new WorkflowService({ cliApi, platform });
664
+ * const allWorkflows = await service.listAll();
665
+ * const workflow = await service.get('release-manager/create-release');
666
+ * ```
667
+ */
668
+
669
+ /**
670
+ * Handler information for UI autocomplete
671
+ */
672
+ interface WorkflowHandlerInfo {
673
+ /** Handler ID (e.g., "release-manager/create-release") */
674
+ id: string;
675
+ /** Plugin ID */
676
+ pluginId: string;
677
+ /** Human-readable name */
678
+ name: string;
679
+ /** Description */
680
+ description?: string;
681
+ /** Input schema */
682
+ inputSchema?: unknown;
683
+ /** Output schema */
684
+ outputSchema?: unknown;
685
+ }
686
+ /**
687
+ * Validation result
688
+ */
689
+ interface ValidationResult {
690
+ valid: boolean;
691
+ errors?: Array<{
692
+ path: string;
693
+ message: string;
694
+ }>;
695
+ }
696
+ /**
697
+ * List options for workflows
698
+ */
699
+ interface WorkflowServiceListOptions extends WorkflowListOptions {
700
+ /** Filter by source type */
701
+ source?: 'manifest' | 'standalone';
702
+ }
703
+ /**
704
+ * Options for WorkflowService
705
+ */
706
+ interface WorkflowServiceOptions {
707
+ /** CLI API for plugin manifest scanning */
708
+ cliApi: IEntityRegistry;
709
+ /** Platform services */
710
+ platform: PlatformServices;
711
+ /** Cache TTL for manifest scanner (ms) */
712
+ manifestCacheTtlMs?: number;
713
+ /** Storage directory for standalone workflows */
714
+ workflowStorageDir?: string;
715
+ /** Workspace root directory (default: process.cwd()) */
716
+ workspaceRoot?: string;
717
+ }
718
+ /**
719
+ * Unified Workflow Service
720
+ *
721
+ * Combines manifest-based and standalone workflows into a single interface.
722
+ */
723
+ declare class WorkflowService {
724
+ private readonly scanner;
725
+ private readonly repository;
726
+ private readonly platform;
727
+ constructor(options: WorkflowServiceOptions);
728
+ /**
729
+ * List all workflows (manifest + standalone).
730
+ */
731
+ listAll(options?: WorkflowServiceListOptions): Promise<WorkflowRuntime[]>;
732
+ /**
733
+ * Get workflow by ID (from either source).
734
+ */
735
+ get(id: string): Promise<WorkflowRuntime | null>;
736
+ /**
737
+ * Create standalone workflow.
738
+ */
739
+ create(spec: WorkflowSpec): Promise<WorkflowRuntime>;
740
+ /**
741
+ * Update standalone workflow.
742
+ */
743
+ update(id: string, spec: Partial<WorkflowSpec>): Promise<WorkflowRuntime>;
744
+ /**
745
+ * Delete standalone workflow.
746
+ */
747
+ delete(id: string): Promise<void>;
748
+ /**
749
+ * Enable workflow (set status to active).
750
+ */
751
+ enable(id: string): Promise<void>;
752
+ /**
753
+ * Disable workflow.
754
+ */
755
+ disable(id: string): Promise<void>;
756
+ /**
757
+ * Pause workflow.
758
+ */
759
+ pause(id: string): Promise<void>;
760
+ /**
761
+ * Resume workflow (unpause).
762
+ */
763
+ resume(id: string): Promise<void>;
764
+ /**
765
+ * Get available workflow handlers (for UI autocomplete).
766
+ *
767
+ * Returns manifest-based handlers that can be used in standalone workflows
768
+ * (via `uses: "plugin:id/handler"`).
769
+ */
770
+ getAvailableHandlers(): Promise<WorkflowHandlerInfo[]>;
771
+ /**
772
+ * Validate workflow spec.
773
+ */
774
+ validate(spec: WorkflowSpec): ValidationResult;
775
+ /**
776
+ * Refresh manifest scanner cache (force re-scan).
777
+ */
778
+ refreshManifests(): Promise<void>;
779
+ }
780
+
781
+ /**
782
+ * @module @kb-labs/workflow-engine/workflow-schedule-manager
783
+ *
784
+ * Manages scheduled workflow execution via CronManager.
785
+ *
786
+ * ## Features
787
+ * - Registers scheduled workflows with CronManager
788
+ * - Executes workflows on cron triggers
789
+ * - Tracks next/last run times
790
+ * - Supports both manifest-based jobs and standalone workflows
791
+ *
792
+ * ## Usage
793
+ * ```typescript
794
+ * const scheduleManager = new WorkflowScheduleManager({
795
+ * cronManager,
796
+ * workflowService,
797
+ * executor,
798
+ * platform,
799
+ * });
800
+ *
801
+ * await scheduleManager.registerAll();
802
+ * ```
803
+ */
804
+
805
+ /**
806
+ * Workflow executor interface.
807
+ * Executes workflows (will be implemented by workflow engine).
808
+ */
809
+ interface WorkflowExecutor {
810
+ /**
811
+ * Execute workflow by ID.
812
+ */
813
+ execute(request: {
814
+ workflowId: string;
815
+ trigger: 'manual' | 'schedule' | 'webhook' | 'push';
816
+ input?: Record<string, unknown>;
817
+ }): Promise<{
818
+ runId: string;
819
+ }>;
820
+ }
821
+ /**
822
+ * Options for WorkflowScheduleManager
823
+ */
824
+ interface WorkflowScheduleManagerOptions {
825
+ /** CronManager instance */
826
+ cronManager: ICronManager;
827
+ /** WorkflowService for discovering workflows */
828
+ workflowService: WorkflowService;
829
+ /** Workflow executor */
830
+ executor: WorkflowExecutor;
831
+ /** Platform services */
832
+ platform: PlatformServices;
833
+ }
834
+ /**
835
+ * Workflow Schedule Manager
836
+ *
837
+ * Integrates workflows with CronManager for scheduled execution.
838
+ */
839
+ declare class WorkflowScheduleManager {
840
+ private readonly cronManager;
841
+ private readonly workflowService;
842
+ private readonly executor;
843
+ private readonly platform;
844
+ constructor(options: WorkflowScheduleManagerOptions);
845
+ /**
846
+ * Register all scheduled workflows with CronManager.
847
+ *
848
+ * Scans both manifest-based jobs and standalone workflows with schedules.
849
+ */
850
+ registerAll(): Promise<void>;
851
+ /**
852
+ * Register single workflow schedule.
853
+ */
854
+ register(workflow: WorkflowRuntime): Promise<void>;
855
+ /**
856
+ * Unregister workflow schedule.
857
+ */
858
+ unregister(workflowId: string): Promise<void>;
859
+ /**
860
+ * Re-register all schedules (refresh).
861
+ *
862
+ * Useful after workflow changes or service restart.
863
+ */
864
+ refresh(): Promise<void>;
865
+ /**
866
+ * Get next run time for scheduled workflow.
867
+ */
868
+ getNextRun(workflowId: string): Date | null;
869
+ /**
870
+ * Get last run time for scheduled workflow.
871
+ */
872
+ getLastRun(workflowId: string): Date | null;
873
+ /**
874
+ * Pause scheduled workflow.
875
+ */
876
+ pause(workflowId: string): void;
877
+ /**
878
+ * Resume paused workflow schedule.
879
+ */
880
+ resume(workflowId: string): void;
881
+ /**
882
+ * List all scheduled workflows.
883
+ */
884
+ listScheduled(): Array<{
885
+ workflowId: string;
886
+ schedule: string;
887
+ status: 'active' | 'paused';
888
+ lastRun?: Date;
889
+ nextRun?: Date;
890
+ runCount: number;
891
+ }>;
892
+ private getCronId;
893
+ private getWorkflowId;
894
+ }
895
+
896
+ interface WorkflowRegistryEntry {
897
+ id: string;
898
+ name: string;
899
+ description?: string;
900
+ filePath: string;
901
+ spec: WorkflowSpec;
902
+ metadata?: Record<string, unknown>;
903
+ }
904
+ interface WorkflowRegistryOptions {
905
+ scanDirs: string[];
906
+ cwd?: string;
907
+ logger: ILogger;
908
+ }
909
+ /**
910
+ * WorkflowRegistry - Auto-discovery and indexing of workflow definitions
911
+ *
912
+ * Scans directories for .yml workflow files and indexes them by ID.
913
+ * Provides clean API for finding and running workflows.
914
+ */
915
+ declare class WorkflowRegistry {
916
+ private readonly options;
917
+ private entries;
918
+ private loader;
919
+ constructor(options: WorkflowRegistryOptions);
920
+ /**
921
+ * Scan configured directories and index all workflow files
922
+ */
923
+ scan(): Promise<void>;
924
+ /**
925
+ * Index a single workflow file
926
+ */
927
+ private indexFile;
928
+ /**
929
+ * Parse workflow file (YAML format with additional fields)
930
+ */
931
+ private parseWorkflowFile;
932
+ /**
933
+ * Get workflow by ID
934
+ */
935
+ get(id: string): WorkflowRegistryEntry | undefined;
936
+ /**
937
+ * List all registered workflows
938
+ */
939
+ list(): WorkflowRegistryEntry[];
940
+ /**
941
+ * Check if workflow exists
942
+ */
943
+ has(id: string): boolean;
944
+ /**
945
+ * Get workflow spec by ID
946
+ */
947
+ getSpec(id: string): WorkflowSpec | undefined;
948
+ /**
949
+ * Clear all indexed workflows
950
+ */
951
+ clear(): void;
952
+ }
953
+
954
+ /**
955
+ * @module @kb-labs/workflow-engine/job-manager
956
+ * Job manager for background task execution with sandboxed handlers.
957
+ */
958
+
959
+ interface JobManagerConfig {
960
+ /** Execution backend for sandboxed handler execution */
961
+ executionBackend?: IExecutionBackend<PluginContextDescriptor>;
962
+ /** Default job timeout in ms (default: 300000 = 5 min) */
963
+ defaultTimeout?: number;
964
+ /** Default max retries (default: 3) */
965
+ defaultMaxRetries?: number;
966
+ /** Default priority (default: 50) */
967
+ defaultPriority?: number;
968
+ /** Workspace root (monorepo root) for plugin execution context */
969
+ workspaceRoot?: string;
970
+ }
971
+ /**
972
+ * Job manager - handles background job execution with sandboxed handlers.
973
+ *
974
+ * Features:
975
+ * - Declarative job handlers from plugin manifests
976
+ * - Priority-based queue (0-100, higher = more important)
977
+ * - Retry with exponential/linear backoff
978
+ * - Sandboxed subprocess execution via ExecutionBackend
979
+ * - Progress tracking and status updates
980
+ * - Idempotency support
981
+ *
982
+ * Architecture:
983
+ * 1. Plugin declares job handlers in manifest.json
984
+ * 2. Plugin runtime registers handlers via registerJobHandler()
985
+ * 3. Plugin submits jobs via ctx.api.jobs.submit()
986
+ * 4. JobManager enqueues job in priority queue (platform.cache sorted sets)
987
+ * 5. Worker dequeues job and executes via ExecutionBackend.execute()
988
+ * 6. Handler runs in subprocess with JobContext
989
+ * 7. Results stored in cache, events emitted
990
+ */
991
+ declare class JobManager implements IJobScheduler {
992
+ private readonly cache;
993
+ private readonly events;
994
+ private readonly logger;
995
+ private readonly config;
996
+ private handlerRegistry;
997
+ private readonly defaultTimeout;
998
+ private readonly defaultMaxRetries;
999
+ private readonly defaultPriority;
1000
+ private readonly workspaceRoot;
1001
+ constructor(cache: ICache, events: IEventBus, logger: ILogger, config?: JobManagerConfig);
1002
+ /**
1003
+ * Register job handler from plugin manifest.
1004
+ *
1005
+ * Called by plugin-runtime during plugin initialization.
1006
+ *
1007
+ * @param pluginId - Plugin identifier
1008
+ * @param pluginVersion - Plugin version
1009
+ * @param pluginRoot - Plugin root directory
1010
+ * @param handlerDecl - Job handler declaration from manifest
1011
+ */
1012
+ registerJobHandler(pluginId: string, pluginVersion: string, pluginRoot: string, handlerDecl: JobHandlerDecl): void;
1013
+ /**
1014
+ * Submit a job for immediate execution.
1015
+ */
1016
+ submit(job: JobDefinition): Promise<JobHandle>;
1017
+ /**
1018
+ * Schedule a job for future/recurring execution.
1019
+ */
1020
+ schedule(job: JobDefinition, schedule: CronExpression | Date): Promise<JobHandle>;
1021
+ /**
1022
+ * Cancel a pending/running job.
1023
+ */
1024
+ cancel(jobId: string): Promise<boolean>;
1025
+ /**
1026
+ * Get job status.
1027
+ */
1028
+ getStatus(jobId: string): Promise<JobHandle | null>;
1029
+ /**
1030
+ * List jobs.
1031
+ */
1032
+ list(filter?: JobFilter): Promise<JobHandle[]>;
1033
+ /**
1034
+ * Execute a job (called by worker).
1035
+ *
1036
+ * @internal
1037
+ */
1038
+ executeJob(jobId: string): Promise<void>;
1039
+ /**
1040
+ * Update job progress.
1041
+ *
1042
+ * Called by job handler via ctx.updateProgress()
1043
+ */
1044
+ updateProgress(jobId: string, percent: number, message?: string): Promise<void>;
1045
+ private handleJobFailure;
1046
+ private markJobFailed;
1047
+ private calculateBackoff;
1048
+ private saveJobRecord;
1049
+ private getJobRecord;
1050
+ private enqueueJob;
1051
+ private removeFromQueue;
1052
+ private findByIdempotencyKey;
1053
+ private getAllJobKeys;
1054
+ private jobRecordToHandle;
1055
+ }
1056
+
1057
+ export { type AcquireOptions, ArtifactMerger, type ArtifactMergerOptions, ConcurrencyManager, type CreateRunInput, type EngineLogger, EnvSecretProvider, type EnvSecretProviderOptions, EventBusBridge, JobManager, type JobManagerConfig, type JobQueueEntry, ManifestScanner, type ManifestScannerOptions, type RetryDecision, type RunContext, RunCoordinator, type RunCoordinatorOptions, type RunSnapshot, RunSnapshotStorage, Scheduler, type SchedulerOptions, type SecretProvider, StateStore, type ValidationResult, WorkflowEngine, type WorkflowEngineOptions, type WorkflowEvent, type WorkflowExecutor, type WorkflowHandlerInfo, type WorkflowListOptions, WorkflowLoader, type WorkflowLoaderOptions, type WorkflowLoaderResult, WorkflowRegistry, type WorkflowRegistryEntry, type WorkflowRegistryOptions, WorkflowRepository, type WorkflowRepositoryOptions, type WorkflowRuntime, type WorkflowSchedule, WorkflowScheduleManager, type WorkflowScheduleManagerOptions, WorkflowService, type WorkflowServiceListOptions, type WorkflowServiceOptions, type WorkflowStats, type WorkflowTrigger, type WorkflowTriggerType, calculateBackoff, createDefaultSecretProvider, shouldRetry };