@calmo/task-runner 3.3.0 → 3.4.1
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/.github/dependabot.yml +7 -7
- package/.github/workflows/ci.yml +4 -4
- package/.jules/backlog_maniac.md +4 -0
- package/.jules/nexus.md +1 -0
- package/.jules/sentinel.md +1 -0
- package/.releaserc.json +2 -7
- package/AGENTS.md +8 -2
- package/CHANGELOG.md +181 -167
- package/README.md +23 -23
- package/coverage/coverage-final.json +8 -7
- package/coverage/index.html +7 -7
- package/coverage/lcov-report/index.html +7 -7
- package/coverage/lcov-report/src/EventBus.ts.html +28 -22
- package/coverage/lcov-report/src/TaskGraphValidationError.ts.html +130 -0
- package/coverage/lcov-report/src/TaskGraphValidator.ts.html +166 -151
- package/coverage/lcov-report/src/TaskRunner.ts.html +69 -54
- package/coverage/lcov-report/src/TaskRunnerBuilder.ts.html +29 -5
- package/coverage/lcov-report/src/TaskRunnerExecutionConfig.ts.html +1 -1
- package/coverage/lcov-report/src/TaskStateManager.ts.html +1 -1
- package/coverage/lcov-report/src/WorkflowExecutor.ts.html +21 -12
- package/coverage/lcov-report/src/contracts/RunnerEvents.ts.html +1 -1
- package/coverage/lcov-report/src/contracts/index.html +1 -1
- package/coverage/lcov-report/src/index.html +23 -8
- package/coverage/lcov-report/src/strategies/DryRunExecutionStrategy.ts.html +4 -4
- package/coverage/lcov-report/src/strategies/RetryingExecutionStrategy.ts.html +30 -12
- package/coverage/lcov-report/src/strategies/StandardExecutionStrategy.ts.html +5 -5
- package/coverage/lcov-report/src/strategies/index.html +1 -1
- package/coverage/lcov.info +296 -278
- package/coverage/src/EventBus.ts.html +28 -22
- package/coverage/src/TaskGraphValidationError.ts.html +130 -0
- package/coverage/src/TaskGraphValidator.ts.html +166 -151
- package/coverage/src/TaskRunner.ts.html +69 -54
- package/coverage/src/TaskRunnerBuilder.ts.html +29 -5
- package/coverage/src/TaskRunnerExecutionConfig.ts.html +1 -1
- package/coverage/src/TaskStateManager.ts.html +1 -1
- package/coverage/src/WorkflowExecutor.ts.html +21 -12
- package/coverage/src/contracts/RunnerEvents.ts.html +1 -1
- package/coverage/src/contracts/index.html +1 -1
- package/coverage/src/index.html +23 -8
- package/coverage/src/strategies/DryRunExecutionStrategy.ts.html +4 -4
- package/coverage/src/strategies/RetryingExecutionStrategy.ts.html +30 -12
- package/coverage/src/strategies/StandardExecutionStrategy.ts.html +5 -5
- package/coverage/src/strategies/index.html +1 -1
- package/dist/EventBus.js +13 -11
- package/dist/EventBus.js.map +1 -1
- package/dist/TaskGraphValidationError.d.ts +9 -0
- package/dist/TaskGraphValidationError.js +13 -0
- package/dist/TaskGraphValidationError.js.map +1 -0
- package/dist/TaskGraphValidator.js +9 -9
- package/dist/TaskGraphValidator.js.map +1 -1
- package/dist/TaskRunner.js +2 -1
- package/dist/TaskRunner.js.map +1 -1
- package/dist/TaskRunnerBuilder.js.map +1 -1
- package/dist/WorkflowExecutor.js +2 -1
- package/dist/WorkflowExecutor.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/strategies/RetryingExecutionStrategy.js +3 -1
- package/dist/strategies/RetryingExecutionStrategy.js.map +1 -1
- package/dist/strategies/StandardExecutionStrategy.js +1 -1
- package/dist/strategies/StandardExecutionStrategy.js.map +1 -1
- package/openspec/AGENTS.md +81 -15
- package/openspec/changes/{add-concurrency-control → archive/2026-01-18-add-concurrency-control}/proposal.md +7 -4
- package/openspec/changes/archive/2026-01-18-add-concurrency-control/tasks.md +10 -0
- package/openspec/changes/archive/2026-01-18-add-external-task-cancellation/proposal.md +4 -1
- package/openspec/changes/archive/2026-01-18-add-external-task-cancellation/tasks.md +2 -1
- package/openspec/changes/archive/2026-01-18-add-integration-tests/proposal.md +3 -0
- package/openspec/changes/archive/2026-01-18-add-integration-tests/tasks.md +1 -0
- package/openspec/changes/archive/2026-01-18-add-task-retry-policy/proposal.md +3 -0
- package/openspec/changes/archive/2026-01-18-add-task-retry-policy/tasks.md +1 -0
- package/openspec/changes/archive/2026-01-18-add-workflow-preview/proposal.md +3 -0
- package/openspec/changes/archive/2026-01-18-add-workflow-preview/tasks.md +1 -0
- package/openspec/changes/archive/2026-01-18-refactor-core-architecture/proposal.md +3 -0
- package/openspec/changes/archive/2026-01-18-refactor-core-architecture/tasks.md +1 -0
- package/openspec/changes/feat-per-task-timeout/proposal.md +11 -6
- package/openspec/changes/feat-per-task-timeout/tasks.md +1 -1
- package/openspec/project.md +21 -15
- package/package.json +1 -1
- package/src/EventBus.ts +18 -16
- package/src/TaskGraph.ts +8 -8
- package/src/TaskGraphValidationError.ts +15 -0
- package/src/TaskGraphValidator.ts +148 -143
- package/src/TaskRunner.ts +47 -42
- package/src/TaskRunnerBuilder.ts +11 -3
- package/src/WorkflowExecutor.ts +13 -10
- package/src/contracts/ITaskGraphValidator.ts +12 -12
- package/src/contracts/ValidationError.ts +6 -6
- package/src/contracts/ValidationResult.ts +4 -4
- package/src/index.ts +1 -0
- package/src/strategies/DryRunExecutionStrategy.ts +3 -3
- package/src/strategies/RetryingExecutionStrategy.ts +15 -9
- package/src/strategies/StandardExecutionStrategy.ts +4 -4
- package/test-report.xml +109 -107
- package/openspec/changes/add-concurrency-control/tasks.md +0 -9
|
@@ -260,7 +260,12 @@
|
|
|
260
260
|
<a name='L195'></a><a href='#L195'>195</a>
|
|
261
261
|
<a name='L196'></a><a href='#L196'>196</a>
|
|
262
262
|
<a name='L197'></a><a href='#L197'>197</a>
|
|
263
|
-
<a name='L198'></a><a href='#L198'>198</a
|
|
263
|
+
<a name='L198'></a><a href='#L198'>198</a>
|
|
264
|
+
<a name='L199'></a><a href='#L199'>199</a>
|
|
265
|
+
<a name='L200'></a><a href='#L200'>200</a>
|
|
266
|
+
<a name='L201'></a><a href='#L201'>201</a>
|
|
267
|
+
<a name='L202'></a><a href='#L202'>202</a>
|
|
268
|
+
<a name='L203'></a><a href='#L203'>203</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral"> </span>
|
|
264
269
|
<span class="cline-any cline-neutral"> </span>
|
|
265
270
|
<span class="cline-any cline-neutral"> </span>
|
|
266
271
|
<span class="cline-any cline-neutral"> </span>
|
|
@@ -283,16 +288,19 @@
|
|
|
283
288
|
<span class="cline-any cline-neutral"> </span>
|
|
284
289
|
<span class="cline-any cline-neutral"> </span>
|
|
285
290
|
<span class="cline-any cline-neutral"> </span>
|
|
286
|
-
<span class="cline-any cline-yes">56x</span>
|
|
287
|
-
<span class="cline-any cline-yes">56x</span>
|
|
288
|
-
<span class="cline-any cline-yes">56x</span>
|
|
289
291
|
<span class="cline-any cline-neutral"> </span>
|
|
290
292
|
<span class="cline-any cline-neutral"> </span>
|
|
291
293
|
<span class="cline-any cline-neutral"> </span>
|
|
292
294
|
<span class="cline-any cline-neutral"> </span>
|
|
295
|
+
<span class="cline-any cline-yes">57x</span>
|
|
296
|
+
<span class="cline-any cline-yes">57x</span>
|
|
293
297
|
<span class="cline-any cline-neutral"> </span>
|
|
298
|
+
<span class="cline-any cline-yes">57x</span>
|
|
294
299
|
<span class="cline-any cline-neutral"> </span>
|
|
295
|
-
<span class="cline-any cline-
|
|
300
|
+
<span class="cline-any cline-neutral"> </span>
|
|
301
|
+
<span class="cline-any cline-neutral"> </span>
|
|
302
|
+
<span class="cline-any cline-neutral"> </span>
|
|
303
|
+
<span class="cline-any cline-yes">57x</span>
|
|
296
304
|
<span class="cline-any cline-neutral"> </span>
|
|
297
305
|
<span class="cline-any cline-neutral"> </span>
|
|
298
306
|
<span class="cline-any cline-neutral"> </span>
|
|
@@ -347,7 +355,6 @@
|
|
|
347
355
|
<span class="cline-any cline-yes">24x</span>
|
|
348
356
|
<span class="cline-any cline-neutral"> </span>
|
|
349
357
|
<span class="cline-any cline-neutral"> </span>
|
|
350
|
-
<span class="cline-any cline-neutral"> </span>
|
|
351
358
|
<span class="cline-any cline-yes">4x</span>
|
|
352
359
|
<span class="cline-any cline-neutral"> </span>
|
|
353
360
|
<span class="cline-any cline-neutral"> </span>
|
|
@@ -364,8 +371,6 @@
|
|
|
364
371
|
<span class="cline-any cline-neutral"> </span>
|
|
365
372
|
<span class="cline-any cline-neutral"> </span>
|
|
366
373
|
<span class="cline-any cline-neutral"> </span>
|
|
367
|
-
<span class="cline-any cline-neutral"> </span>
|
|
368
|
-
<span class="cline-any cline-neutral"> </span>
|
|
369
374
|
<span class="cline-any cline-yes">4x</span>
|
|
370
375
|
<span class="cline-any cline-neutral"> </span>
|
|
371
376
|
<span class="cline-any cline-neutral"> </span>
|
|
@@ -391,16 +396,19 @@
|
|
|
391
396
|
<span class="cline-any cline-neutral"> </span>
|
|
392
397
|
<span class="cline-any cline-neutral"> </span>
|
|
393
398
|
<span class="cline-any cline-neutral"> </span>
|
|
394
|
-
<span class="cline-any cline-yes">
|
|
395
|
-
<span class="cline-any cline-yes">
|
|
399
|
+
<span class="cline-any cline-yes">52x</span>
|
|
400
|
+
<span class="cline-any cline-yes">140x</span>
|
|
401
|
+
<span class="cline-any cline-neutral"> </span>
|
|
402
|
+
<span class="cline-any cline-neutral"> </span>
|
|
396
403
|
<span class="cline-any cline-neutral"> </span>
|
|
397
404
|
<span class="cline-any cline-neutral"> </span>
|
|
398
405
|
<span class="cline-any cline-neutral"> </span>
|
|
406
|
+
<span class="cline-any cline-yes">52x</span>
|
|
407
|
+
<span class="cline-any cline-yes">52x</span>
|
|
408
|
+
<span class="cline-any cline-yes">9x</span>
|
|
409
|
+
<span class="cline-any cline-neutral"> </span>
|
|
399
410
|
<span class="cline-any cline-neutral"> </span>
|
|
400
411
|
<span class="cline-any cline-neutral"> </span>
|
|
401
|
-
<span class="cline-any cline-yes">51x</span>
|
|
402
|
-
<span class="cline-any cline-yes">51x</span>
|
|
403
|
-
<span class="cline-any cline-yes">8x</span>
|
|
404
412
|
<span class="cline-any cline-neutral"> </span>
|
|
405
413
|
<span class="cline-any cline-neutral"> </span>
|
|
406
414
|
<span class="cline-any cline-yes">43x</span>
|
|
@@ -419,12 +427,14 @@
|
|
|
419
427
|
<span class="cline-any cline-neutral"> </span>
|
|
420
428
|
<span class="cline-any cline-neutral"> </span>
|
|
421
429
|
<span class="cline-any cline-neutral"> </span>
|
|
422
|
-
<span class="cline-any cline-yes">
|
|
430
|
+
<span class="cline-any cline-yes">52x</span>
|
|
423
431
|
<span class="cline-any cline-yes">5x</span>
|
|
424
432
|
<span class="cline-any cline-yes">5x</span>
|
|
425
433
|
<span class="cline-any cline-yes">3x</span>
|
|
426
434
|
<span class="cline-any cline-neutral"> </span>
|
|
427
435
|
<span class="cline-any cline-neutral"> </span>
|
|
436
|
+
<span class="cline-any cline-neutral"> </span>
|
|
437
|
+
<span class="cline-any cline-neutral"> </span>
|
|
428
438
|
<span class="cline-any cline-yes">5x</span>
|
|
429
439
|
<span class="cline-any cline-neutral"> </span>
|
|
430
440
|
<span class="cline-any cline-neutral"> </span>
|
|
@@ -461,11 +471,15 @@
|
|
|
461
471
|
import { TaskResult } from "./TaskResult.js";
|
|
462
472
|
import { TaskGraphValidator } from "./TaskGraphValidator.js";
|
|
463
473
|
import { TaskGraph } from "./TaskGraph.js";
|
|
464
|
-
import {
|
|
474
|
+
import {
|
|
475
|
+
RunnerEventPayloads,
|
|
476
|
+
RunnerEventListener,
|
|
477
|
+
} from "./contracts/RunnerEvents.js";
|
|
465
478
|
import { EventBus } from "./EventBus.js";
|
|
466
479
|
import { WorkflowExecutor } from "./WorkflowExecutor.js";
|
|
467
480
|
import { TaskRunnerExecutionConfig } from "./TaskRunnerExecutionConfig.js";
|
|
468
481
|
import { TaskStateManager } from "./TaskStateManager.js";
|
|
482
|
+
import { TaskGraphValidationError } from "./TaskGraphValidationError.js";
|
|
469
483
|
import { IExecutionStrategy } from "./strategies/IExecutionStrategy.js";
|
|
470
484
|
import { StandardExecutionStrategy } from "./strategies/StandardExecutionStrategy.js";
|
|
471
485
|
import { RetryingExecutionStrategy } from "./strategies/RetryingExecutionStrategy.js";
|
|
@@ -482,9 +496,8 @@ export { RunnerEventPayloads, RunnerEventListener, TaskRunnerExecutionConfig };
|
|
|
482
496
|
export class TaskRunner<TContext> {
|
|
483
497
|
private eventBus = new EventBus<TContext>();
|
|
484
498
|
private validator = new TaskGraphValidator();
|
|
485
|
-
private executionStrategy: IExecutionStrategy<TContext> =
|
|
486
|
-
new StandardExecutionStrategy()
|
|
487
|
-
);
|
|
499
|
+
private executionStrategy: IExecutionStrategy<TContext> =
|
|
500
|
+
new RetryingExecutionStrategy(new StandardExecutionStrategy());
|
|
488
501
|
|
|
489
502
|
/**
|
|
490
503
|
* @param context The shared context object to be passed to each task.
|
|
@@ -542,7 +555,6 @@ export class TaskRunner<TContext> {
|
|
|
542
555
|
// Actually, Mermaid ID cannot have spaces without quotes.
|
|
543
556
|
const safeId = (name: string) => JSON.stringify(name);
|
|
544
557
|
const sanitize = (name: string) => this.sanitizeMermaidId(name);
|
|
545
|
-
|
|
546
558
|
|
|
547
559
|
// Add all nodes first to ensure they exist
|
|
548
560
|
for (const step of steps) {
|
|
@@ -556,9 +568,7 @@ export class TaskRunner<TContext> {
|
|
|
556
568
|
for (const step of steps) {
|
|
557
569
|
if (step.dependencies) {
|
|
558
570
|
for (const dep of step.dependencies) {
|
|
559
|
-
graphLines.push(
|
|
560
|
-
` ${sanitize(dep)} --> ${sanitize(step.name)}`
|
|
561
|
-
);
|
|
571
|
+
graphLines.push(` ${sanitize(dep)} --> ${sanitize(step.name)}`);
|
|
562
572
|
}
|
|
563
573
|
}
|
|
564
574
|
}
|
|
@@ -597,7 +607,10 @@ export class TaskRunner<TContext> {
|
|
|
597
607
|
|
|
598
608
|
const validationResult = this.validator.validate(taskGraph);
|
|
599
609
|
if (!validationResult.isValid) {
|
|
600
|
-
throw new
|
|
610
|
+
throw new TaskGraphValidationError(
|
|
611
|
+
validationResult,
|
|
612
|
+
this.validator.createErrorMessage(validationResult)
|
|
613
|
+
);
|
|
601
614
|
}
|
|
602
615
|
|
|
603
616
|
const stateManager = new TaskStateManager(this.eventBus);
|
|
@@ -617,40 +630,42 @@ export class TaskRunner<TContext> {
|
|
|
617
630
|
|
|
618
631
|
// We need to handle the timeout cleanup properly.
|
|
619
632
|
if (config?.timeout !== undefined) {
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
633
|
+
const controller = new AbortController();
|
|
634
|
+
const timeoutId = setTimeout(() => {
|
|
635
|
+
controller.abort(
|
|
636
|
+
new Error(`Workflow timed out after ${config.timeout}ms`)
|
|
637
|
+
);
|
|
638
|
+
}, config.timeout);
|
|
624
639
|
|
|
625
|
-
|
|
626
|
-
|
|
640
|
+
let effectiveSignal = controller.signal;
|
|
641
|
+
let onAbort: (() => void) | undefined;
|
|
627
642
|
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
+
// Handle combination of signals if user provided one
|
|
644
|
+
if (config.signal) {
|
|
645
|
+
if (config.signal.aborted) {
|
|
646
|
+
// If already aborted, use it directly (WorkflowExecutor handles early abort)
|
|
647
|
+
// We can cancel timeout immediately
|
|
648
|
+
clearTimeout(timeoutId);
|
|
649
|
+
effectiveSignal = config.signal;
|
|
650
|
+
} else {
|
|
651
|
+
// Listen to user signal to abort our controller
|
|
652
|
+
onAbort = () => {
|
|
653
|
+
controller.abort(config.signal?.reason);
|
|
654
|
+
};
|
|
655
|
+
config.signal.addEventListener("abort", onAbort);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
643
658
|
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
659
|
+
try {
|
|
660
|
+
return await executor.execute(steps, effectiveSignal);
|
|
661
|
+
} finally {
|
|
662
|
+
clearTimeout(timeoutId);
|
|
663
|
+
if (config.signal && onAbort) {
|
|
664
|
+
config.signal.removeEventListener("abort", onAbort);
|
|
665
|
+
}
|
|
666
|
+
}
|
|
652
667
|
} else {
|
|
653
|
-
|
|
668
|
+
return executor.execute(steps, config?.signal);
|
|
654
669
|
}
|
|
655
670
|
}
|
|
656
671
|
}
|
|
@@ -661,7 +676,7 @@ export class TaskRunner<TContext> {
|
|
|
661
676
|
<div class='footer quiet pad2 space-top1 center small'>
|
|
662
677
|
Code coverage generated by
|
|
663
678
|
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
664
|
-
at 2026-01-
|
|
679
|
+
at 2026-01-18T21:02:31.377Z
|
|
665
680
|
</div>
|
|
666
681
|
<script src="../prettify.js"></script>
|
|
667
682
|
<script>
|
|
@@ -139,7 +139,21 @@
|
|
|
139
139
|
<a name='L74'></a><a href='#L74'>74</a>
|
|
140
140
|
<a name='L75'></a><a href='#L75'>75</a>
|
|
141
141
|
<a name='L76'></a><a href='#L76'>76</a>
|
|
142
|
-
<a name='L77'></a><a href='#L77'>77</a
|
|
142
|
+
<a name='L77'></a><a href='#L77'>77</a>
|
|
143
|
+
<a name='L78'></a><a href='#L78'>78</a>
|
|
144
|
+
<a name='L79'></a><a href='#L79'>79</a>
|
|
145
|
+
<a name='L80'></a><a href='#L80'>80</a>
|
|
146
|
+
<a name='L81'></a><a href='#L81'>81</a>
|
|
147
|
+
<a name='L82'></a><a href='#L82'>82</a>
|
|
148
|
+
<a name='L83'></a><a href='#L83'>83</a>
|
|
149
|
+
<a name='L84'></a><a href='#L84'>84</a>
|
|
150
|
+
<a name='L85'></a><a href='#L85'>85</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral"> </span>
|
|
151
|
+
<span class="cline-any cline-neutral"> </span>
|
|
152
|
+
<span class="cline-any cline-neutral"> </span>
|
|
153
|
+
<span class="cline-any cline-neutral"> </span>
|
|
154
|
+
<span class="cline-any cline-neutral"> </span>
|
|
155
|
+
<span class="cline-any cline-neutral"> </span>
|
|
156
|
+
<span class="cline-any cline-neutral"> </span>
|
|
143
157
|
<span class="cline-any cline-neutral"> </span>
|
|
144
158
|
<span class="cline-any cline-neutral"> </span>
|
|
145
159
|
<span class="cline-any cline-neutral"> </span>
|
|
@@ -198,7 +212,9 @@
|
|
|
198
212
|
<span class="cline-any cline-yes">1x</span>
|
|
199
213
|
<span class="cline-any cline-neutral"> </span>
|
|
200
214
|
<span class="cline-any cline-neutral"> </span>
|
|
215
|
+
<span class="cline-any cline-neutral"> </span>
|
|
201
216
|
<span class="cline-any cline-yes">2x</span>
|
|
217
|
+
<span class="cline-any cline-neutral"> </span>
|
|
202
218
|
<span class="cline-any cline-yes">1x</span>
|
|
203
219
|
<span class="cline-any cline-neutral"> </span>
|
|
204
220
|
<span class="cline-any cline-yes">1x</span>
|
|
@@ -216,7 +232,10 @@
|
|
|
216
232
|
<span class="cline-any cline-neutral"> </span>
|
|
217
233
|
<span class="cline-any cline-neutral"> </span>
|
|
218
234
|
<span class="cline-any cline-neutral"> </span></td><td class="text"><pre class="prettyprint lang-js">import { TaskRunner } from "./TaskRunner.js";
|
|
219
|
-
import {
|
|
235
|
+
import {
|
|
236
|
+
RunnerEventPayloads,
|
|
237
|
+
RunnerEventListener,
|
|
238
|
+
} from "./contracts/RunnerEvents.js";
|
|
220
239
|
import { IExecutionStrategy } from "./strategies/IExecutionStrategy.js";
|
|
221
240
|
|
|
222
241
|
/**
|
|
@@ -226,7 +245,10 @@ export class TaskRunnerBuilder<TContext> {
|
|
|
226
245
|
private context: TContext;
|
|
227
246
|
private strategy?: IExecutionStrategy<TContext>;
|
|
228
247
|
private listeners: {
|
|
229
|
-
[K in keyof RunnerEventPayloads<TContext>]?: RunnerEventListener<
|
|
248
|
+
[K in keyof RunnerEventPayloads<TContext>]?: RunnerEventListener<
|
|
249
|
+
TContext,
|
|
250
|
+
K
|
|
251
|
+
>[];
|
|
230
252
|
} = {};
|
|
231
253
|
|
|
232
254
|
/**
|
|
@@ -274,7 +296,9 @@ export class TaskRunnerBuilder<TContext> {
|
|
|
274
296
|
runner.setExecutionStrategy(this.strategy);
|
|
275
297
|
}
|
|
276
298
|
|
|
277
|
-
(
|
|
299
|
+
(
|
|
300
|
+
Object.keys(this.listeners) as Array<keyof RunnerEventPayloads<TContext>>
|
|
301
|
+
).forEach((event) => {
|
|
278
302
|
const callbacks = this.listeners[event];
|
|
279
303
|
// callbacks is always defined because we are iterating keys of the object
|
|
280
304
|
callbacks!.forEach((callback) =>
|
|
@@ -298,7 +322,7 @@ export class TaskRunnerBuilder<TContext> {
|
|
|
298
322
|
<div class='footer quiet pad2 space-top1 center small'>
|
|
299
323
|
Code coverage generated by
|
|
300
324
|
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
301
|
-
at 2026-01-
|
|
325
|
+
at 2026-01-18T21:02:31.377Z
|
|
302
326
|
</div>
|
|
303
327
|
<script src="../prettify.js"></script>
|
|
304
328
|
<script>
|
|
@@ -139,7 +139,7 @@ export interface TaskRunnerExecutionConfig {
|
|
|
139
139
|
<div class='footer quiet pad2 space-top1 center small'>
|
|
140
140
|
Code coverage generated by
|
|
141
141
|
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
142
|
-
at 2026-01-
|
|
142
|
+
at 2026-01-18T21:02:31.377Z
|
|
143
143
|
</div>
|
|
144
144
|
<script src="../prettify.js"></script>
|
|
145
145
|
<script>
|
|
@@ -496,7 +496,7 @@ export class TaskStateManager<TContext> {
|
|
|
496
496
|
<div class='footer quiet pad2 space-top1 center small'>
|
|
497
497
|
Code coverage generated by
|
|
498
498
|
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
499
|
-
at 2026-01-
|
|
499
|
+
at 2026-01-18T21:02:31.377Z
|
|
500
500
|
</div>
|
|
501
501
|
<script src="../prettify.js"></script>
|
|
502
502
|
<script>
|
|
@@ -203,7 +203,10 @@
|
|
|
203
203
|
<a name='L138'></a><a href='#L138'>138</a>
|
|
204
204
|
<a name='L139'></a><a href='#L139'>139</a>
|
|
205
205
|
<a name='L140'></a><a href='#L140'>140</a>
|
|
206
|
-
<a name='L141'></a><a href='#L141'>141</a
|
|
206
|
+
<a name='L141'></a><a href='#L141'>141</a>
|
|
207
|
+
<a name='L142'></a><a href='#L142'>142</a>
|
|
208
|
+
<a name='L143'></a><a href='#L143'>143</a>
|
|
209
|
+
<a name='L144'></a><a href='#L144'>144</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral"> </span>
|
|
207
210
|
<span class="cline-any cline-neutral"> </span>
|
|
208
211
|
<span class="cline-any cline-neutral"> </span>
|
|
209
212
|
<span class="cline-any cline-neutral"> </span>
|
|
@@ -247,6 +250,8 @@
|
|
|
247
250
|
<span class="cline-any cline-neutral"> </span>
|
|
248
251
|
<span class="cline-any cline-yes">47x</span>
|
|
249
252
|
<span class="cline-any cline-yes">2x</span>
|
|
253
|
+
<span class="cline-any cline-neutral"> </span>
|
|
254
|
+
<span class="cline-any cline-neutral"> </span>
|
|
250
255
|
<span class="cline-any cline-yes">2x</span>
|
|
251
256
|
<span class="cline-any cline-yes">2x</span>
|
|
252
257
|
<span class="cline-any cline-yes">2x</span>
|
|
@@ -331,6 +336,7 @@
|
|
|
331
336
|
<span class="cline-any cline-neutral"> </span>
|
|
332
337
|
<span class="cline-any cline-yes">119x</span>
|
|
333
338
|
<span class="cline-any cline-neutral"> </span>
|
|
339
|
+
<span class="cline-any cline-neutral"> </span>
|
|
334
340
|
<span class="cline-any cline-yes">119x</span>
|
|
335
341
|
<span class="cline-any cline-neutral"> </span>
|
|
336
342
|
<span class="cline-any cline-neutral"> </span>
|
|
@@ -386,7 +392,9 @@ export class WorkflowExecutor<TContext> {
|
|
|
386
392
|
|
|
387
393
|
// Check if already aborted
|
|
388
394
|
if (signal?.aborted) {
|
|
389
|
-
this.stateManager.cancelAllPending(
|
|
395
|
+
this.stateManager.cancelAllPending(
|
|
396
|
+
"Workflow cancelled before execution started."
|
|
397
|
+
);
|
|
390
398
|
const results = this.stateManager.getResults();
|
|
391
399
|
this.eventBus.emit("workflowEnd", { context: this.context, results });
|
|
392
400
|
return results;
|
|
@@ -400,7 +408,7 @@ export class WorkflowExecutor<TContext> {
|
|
|
400
408
|
};
|
|
401
409
|
|
|
402
410
|
if (signal) {
|
|
403
|
-
|
|
411
|
+
signal.addEventListener("abort", onAbort);
|
|
404
412
|
}
|
|
405
413
|
|
|
406
414
|
try {
|
|
@@ -422,10 +430,10 @@ export class WorkflowExecutor<TContext> {
|
|
|
422
430
|
}
|
|
423
431
|
|
|
424
432
|
if (signal?.aborted) {
|
|
425
|
-
|
|
433
|
+
this.stateManager.cancelAllPending("Workflow cancelled.");
|
|
426
434
|
} else {
|
|
427
|
-
|
|
428
|
-
|
|
435
|
+
// After a task finishes, check for new work
|
|
436
|
+
this.processLoop(executingPromises, signal);
|
|
429
437
|
}
|
|
430
438
|
}
|
|
431
439
|
|
|
@@ -469,14 +477,15 @@ export class WorkflowExecutor<TContext> {
|
|
|
469
477
|
|
|
470
478
|
this.stateManager.markRunning(step);
|
|
471
479
|
|
|
472
|
-
const taskPromise = this.strategy
|
|
480
|
+
const taskPromise = this.strategy
|
|
481
|
+
.execute(step, this.context, signal)
|
|
473
482
|
.then((result) => {
|
|
474
|
-
|
|
483
|
+
this.stateManager.markCompleted(step, result);
|
|
475
484
|
})
|
|
476
485
|
.finally(() => {
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
486
|
+
executingPromises.delete(taskPromise);
|
|
487
|
+
// When a task finishes, we try to run more
|
|
488
|
+
this.processLoop(executingPromises, signal);
|
|
480
489
|
});
|
|
481
490
|
|
|
482
491
|
executingPromises.add(taskPromise);
|
|
@@ -490,7 +499,7 @@ export class WorkflowExecutor<TContext> {
|
|
|
490
499
|
<div class='footer quiet pad2 space-top1 center small'>
|
|
491
500
|
Code coverage generated by
|
|
492
501
|
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
493
|
-
at 2026-01-
|
|
502
|
+
at 2026-01-18T21:02:31.377Z
|
|
494
503
|
</div>
|
|
495
504
|
<script src="../prettify.js"></script>
|
|
496
505
|
<script>
|
|
@@ -202,7 +202,7 @@ export type ListenerMap<TContext> = {
|
|
|
202
202
|
<div class='footer quiet pad2 space-top1 center small'>
|
|
203
203
|
Code coverage generated by
|
|
204
204
|
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
205
|
-
at 2026-01-
|
|
205
|
+
at 2026-01-18T21:02:31.377Z
|
|
206
206
|
</div>
|
|
207
207
|
<script src="../../prettify.js"></script>
|
|
208
208
|
<script>
|
|
@@ -101,7 +101,7 @@
|
|
|
101
101
|
<div class='footer quiet pad2 space-top1 center small'>
|
|
102
102
|
Code coverage generated by
|
|
103
103
|
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
104
|
-
at 2026-01-
|
|
104
|
+
at 2026-01-18T21:02:31.377Z
|
|
105
105
|
</div>
|
|
106
106
|
<script src="../../prettify.js"></script>
|
|
107
107
|
<script>
|
package/coverage/src/index.html
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
<div class='fl pad1y space-right2'>
|
|
26
26
|
<span class="strong">100% </span>
|
|
27
27
|
<span class="quiet">Statements</span>
|
|
28
|
-
<span class='fraction'>
|
|
28
|
+
<span class='fraction'>231/231</span>
|
|
29
29
|
</div>
|
|
30
30
|
|
|
31
31
|
|
|
@@ -39,14 +39,14 @@
|
|
|
39
39
|
<div class='fl pad1y space-right2'>
|
|
40
40
|
<span class="strong">100% </span>
|
|
41
41
|
<span class="quiet">Functions</span>
|
|
42
|
-
<span class='fraction'>
|
|
42
|
+
<span class='fraction'>44/44</span>
|
|
43
43
|
</div>
|
|
44
44
|
|
|
45
45
|
|
|
46
46
|
<div class='fl pad1y space-right2'>
|
|
47
47
|
<span class="strong">100% </span>
|
|
48
48
|
<span class="quiet">Lines</span>
|
|
49
|
-
<span class='fraction'>
|
|
49
|
+
<span class='fraction'>228/228</span>
|
|
50
50
|
</div>
|
|
51
51
|
|
|
52
52
|
|
|
@@ -84,13 +84,28 @@
|
|
|
84
84
|
<div class="chart"><div class="cover-fill cover-full" style="width: 100%"></div><div class="cover-empty" style="width: 0%"></div></div>
|
|
85
85
|
</td>
|
|
86
86
|
<td data-value="100" class="pct high">100%</td>
|
|
87
|
-
<td data-value="
|
|
87
|
+
<td data-value="16" class="abs high">16/16</td>
|
|
88
88
|
<td data-value="100" class="pct high">100%</td>
|
|
89
89
|
<td data-value="8" class="abs high">8/8</td>
|
|
90
90
|
<td data-value="100" class="pct high">100%</td>
|
|
91
|
-
<td data-value="
|
|
91
|
+
<td data-value="5" class="abs high">5/5</td>
|
|
92
|
+
<td data-value="100" class="pct high">100%</td>
|
|
93
|
+
<td data-value="16" class="abs high">16/16</td>
|
|
94
|
+
</tr>
|
|
95
|
+
|
|
96
|
+
<tr>
|
|
97
|
+
<td class="file high" data-value="TaskGraphValidationError.ts"><a href="TaskGraphValidationError.ts.html">TaskGraphValidationError.ts</a></td>
|
|
98
|
+
<td data-value="100" class="pic high">
|
|
99
|
+
<div class="chart"><div class="cover-fill cover-full" style="width: 100%"></div><div class="cover-empty" style="width: 0%"></div></div>
|
|
100
|
+
</td>
|
|
101
|
+
<td data-value="100" class="pct high">100%</td>
|
|
102
|
+
<td data-value="3" class="abs high">3/3</td>
|
|
103
|
+
<td data-value="100" class="pct high">100%</td>
|
|
104
|
+
<td data-value="0" class="abs high">0/0</td>
|
|
105
|
+
<td data-value="100" class="pct high">100%</td>
|
|
106
|
+
<td data-value="1" class="abs high">1/1</td>
|
|
92
107
|
<td data-value="100" class="pct high">100%</td>
|
|
93
|
-
<td data-value="
|
|
108
|
+
<td data-value="3" class="abs high">3/3</td>
|
|
94
109
|
</tr>
|
|
95
110
|
|
|
96
111
|
<tr>
|
|
@@ -105,7 +120,7 @@
|
|
|
105
120
|
<td data-value="100" class="pct high">100%</td>
|
|
106
121
|
<td data-value="5" class="abs high">5/5</td>
|
|
107
122
|
<td data-value="100" class="pct high">100%</td>
|
|
108
|
-
<td data-value="
|
|
123
|
+
<td data-value="55" class="abs high">55/55</td>
|
|
109
124
|
</tr>
|
|
110
125
|
|
|
111
126
|
<tr>
|
|
@@ -191,7 +206,7 @@
|
|
|
191
206
|
<div class='footer quiet pad2 space-top1 center small'>
|
|
192
207
|
Code coverage generated by
|
|
193
208
|
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
194
|
-
at 2026-01-
|
|
209
|
+
at 2026-01-18T21:02:31.377Z
|
|
195
210
|
</div>
|
|
196
211
|
<script src="../prettify.js"></script>
|
|
197
212
|
<script>
|
|
@@ -132,9 +132,9 @@ import { TaskResult } from "../TaskResult.js";
|
|
|
132
132
|
/**
|
|
133
133
|
* Execution strategy that simulates task execution without running the actual logic.
|
|
134
134
|
*/
|
|
135
|
-
export class DryRunExecutionStrategy<
|
|
136
|
-
|
|
137
|
-
{
|
|
135
|
+
export class DryRunExecutionStrategy<
|
|
136
|
+
TContext,
|
|
137
|
+
> implements IExecutionStrategy<TContext> {
|
|
138
138
|
/**
|
|
139
139
|
* Simulates execution by returning a success result immediately.
|
|
140
140
|
* @param step The task step (ignored).
|
|
@@ -163,7 +163,7 @@ export class DryRunExecutionStrategy<TContext>
|
|
|
163
163
|
<div class='footer quiet pad2 space-top1 center small'>
|
|
164
164
|
Code coverage generated by
|
|
165
165
|
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
166
|
-
at 2026-01-
|
|
166
|
+
at 2026-01-18T21:02:31.377Z
|
|
167
167
|
</div>
|
|
168
168
|
<script src="../../prettify.js"></script>
|
|
169
169
|
<script>
|
|
@@ -153,7 +153,13 @@
|
|
|
153
153
|
<a name='L88'></a><a href='#L88'>88</a>
|
|
154
154
|
<a name='L89'></a><a href='#L89'>89</a>
|
|
155
155
|
<a name='L90'></a><a href='#L90'>90</a>
|
|
156
|
-
<a name='L91'></a><a href='#L91'>91</a
|
|
156
|
+
<a name='L91'></a><a href='#L91'>91</a>
|
|
157
|
+
<a name='L92'></a><a href='#L92'>92</a>
|
|
158
|
+
<a name='L93'></a><a href='#L93'>93</a>
|
|
159
|
+
<a name='L94'></a><a href='#L94'>94</a>
|
|
160
|
+
<a name='L95'></a><a href='#L95'>95</a>
|
|
161
|
+
<a name='L96'></a><a href='#L96'>96</a>
|
|
162
|
+
<a name='L97'></a><a href='#L97'>97</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral"> </span>
|
|
157
163
|
<span class="cline-any cline-neutral"> </span>
|
|
158
164
|
<span class="cline-any cline-neutral"> </span>
|
|
159
165
|
<span class="cline-any cline-neutral"> </span>
|
|
@@ -161,7 +167,9 @@
|
|
|
161
167
|
<span class="cline-any cline-neutral"> </span>
|
|
162
168
|
<span class="cline-any cline-neutral"> </span>
|
|
163
169
|
<span class="cline-any cline-neutral"> </span>
|
|
164
|
-
<span class="cline-any cline-
|
|
170
|
+
<span class="cline-any cline-neutral"> </span>
|
|
171
|
+
<span class="cline-any cline-neutral"> </span>
|
|
172
|
+
<span class="cline-any cline-yes">67x</span>
|
|
165
173
|
<span class="cline-any cline-neutral"> </span>
|
|
166
174
|
<span class="cline-any cline-neutral"> </span>
|
|
167
175
|
<span class="cline-any cline-neutral"> </span>
|
|
@@ -186,6 +194,10 @@
|
|
|
186
194
|
<span class="cline-any cline-yes">12x</span>
|
|
187
195
|
<span class="cline-any cline-neutral"> </span>
|
|
188
196
|
<span class="cline-any cline-yes">12x</span>
|
|
197
|
+
<span class="cline-any cline-neutral"> </span>
|
|
198
|
+
<span class="cline-any cline-neutral"> </span>
|
|
199
|
+
<span class="cline-any cline-neutral"> </span>
|
|
200
|
+
<span class="cline-any cline-neutral"> </span>
|
|
189
201
|
<span class="cline-any cline-yes">1x</span>
|
|
190
202
|
<span class="cline-any cline-neutral"> </span>
|
|
191
203
|
<span class="cline-any cline-neutral"> </span>
|
|
@@ -250,7 +262,9 @@ import { TaskResult } from "../TaskResult.js";
|
|
|
250
262
|
/**
|
|
251
263
|
* Execution strategy that retries tasks upon failure based on their retry configuration.
|
|
252
264
|
*/
|
|
253
|
-
export class RetryingExecutionStrategy<
|
|
265
|
+
export class RetryingExecutionStrategy<
|
|
266
|
+
TContext,
|
|
267
|
+
> implements IExecutionStrategy<TContext> {
|
|
254
268
|
constructor(private innerStrategy: IExecutionStrategy<TContext>) {}
|
|
255
269
|
|
|
256
270
|
async execute(
|
|
@@ -275,7 +289,11 @@ export class RetryingExecutionStrategy<TContext> implements IExecutionStra
|
|
|
275
289
|
|
|
276
290
|
const result = await this.innerStrategy.execute(step, context, signal);
|
|
277
291
|
|
|
278
|
-
if (
|
|
292
|
+
if (
|
|
293
|
+
result.status === "success" ||
|
|
294
|
+
result.status === "cancelled" ||
|
|
295
|
+
result.status === "skipped"
|
|
296
|
+
) {
|
|
279
297
|
return result;
|
|
280
298
|
}
|
|
281
299
|
|
|
@@ -296,13 +314,13 @@ export class RetryingExecutionStrategy<TContext> implements IExecutionStra
|
|
|
296
314
|
try {
|
|
297
315
|
await this.sleep(delay, signal);
|
|
298
316
|
} catch (e) {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
317
|
+
if (signal?.aborted) {
|
|
318
|
+
return {
|
|
319
|
+
status: "cancelled",
|
|
320
|
+
message: "Task cancelled during retry delay",
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
throw e;
|
|
306
324
|
}
|
|
307
325
|
}
|
|
308
326
|
}
|
|
@@ -340,7 +358,7 @@ export class RetryingExecutionStrategy<TContext> implements IExecutionStra
|
|
|
340
358
|
<div class='footer quiet pad2 space-top1 center small'>
|
|
341
359
|
Code coverage generated by
|
|
342
360
|
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
343
|
-
at 2026-01-
|
|
361
|
+
at 2026-01-18T21:02:31.377Z
|
|
344
362
|
</div>
|
|
345
363
|
<script src="../../prettify.js"></script>
|
|
346
364
|
<script>
|