@calmo/task-runner 3.7.0 → 3.8.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.
Files changed (68) hide show
  1. package/.github/workflows/ci.yml +3 -0
  2. package/.jules/nexus.md +5 -0
  3. package/.jules/sentinel.md +6 -0
  4. package/AGENTS.md +1 -0
  5. package/CHANGELOG.md +16 -0
  6. package/README.md +2 -0
  7. package/coverage/coverage-final.json +8 -7
  8. package/coverage/index.html +20 -20
  9. package/coverage/lcov-report/index.html +20 -20
  10. package/coverage/lcov-report/src/EventBus.ts.html +4 -4
  11. package/coverage/lcov-report/src/TaskGraphValidationError.ts.html +1 -1
  12. package/coverage/lcov-report/src/TaskGraphValidator.ts.html +142 -82
  13. package/coverage/lcov-report/src/TaskRunner.ts.html +94 -79
  14. package/coverage/lcov-report/src/TaskRunnerBuilder.ts.html +1 -1
  15. package/coverage/lcov-report/src/TaskRunnerExecutionConfig.ts.html +1 -1
  16. package/coverage/lcov-report/src/TaskStateManager.ts.html +42 -54
  17. package/coverage/lcov-report/src/WorkflowExecutor.ts.html +56 -47
  18. package/coverage/lcov-report/src/contracts/ErrorTypes.ts.html +103 -0
  19. package/coverage/lcov-report/src/contracts/RunnerEvents.ts.html +1 -1
  20. package/coverage/lcov-report/src/contracts/index.html +23 -8
  21. package/coverage/lcov-report/src/index.html +15 -15
  22. package/coverage/lcov-report/src/strategies/DryRunExecutionStrategy.ts.html +1 -1
  23. package/coverage/lcov-report/src/strategies/RetryingExecutionStrategy.ts.html +5 -5
  24. package/coverage/lcov-report/src/strategies/StandardExecutionStrategy.ts.html +3 -3
  25. package/coverage/lcov-report/src/strategies/index.html +1 -1
  26. package/coverage/lcov.info +361 -332
  27. package/coverage/src/EventBus.ts.html +4 -4
  28. package/coverage/src/TaskGraphValidationError.ts.html +1 -1
  29. package/coverage/src/TaskGraphValidator.ts.html +142 -82
  30. package/coverage/src/TaskRunner.ts.html +94 -79
  31. package/coverage/src/TaskRunnerBuilder.ts.html +1 -1
  32. package/coverage/src/TaskRunnerExecutionConfig.ts.html +1 -1
  33. package/coverage/src/TaskStateManager.ts.html +42 -54
  34. package/coverage/src/WorkflowExecutor.ts.html +56 -47
  35. package/coverage/src/contracts/ErrorTypes.ts.html +103 -0
  36. package/coverage/src/contracts/RunnerEvents.ts.html +1 -1
  37. package/coverage/src/contracts/index.html +23 -8
  38. package/coverage/src/index.html +15 -15
  39. package/coverage/src/strategies/DryRunExecutionStrategy.ts.html +1 -1
  40. package/coverage/src/strategies/RetryingExecutionStrategy.ts.html +5 -5
  41. package/coverage/src/strategies/StandardExecutionStrategy.ts.html +3 -3
  42. package/coverage/src/strategies/index.html +1 -1
  43. package/dist/TaskGraphValidator.d.ts +3 -0
  44. package/dist/TaskGraphValidator.js +33 -26
  45. package/dist/TaskGraphValidator.js.map +1 -1
  46. package/dist/TaskRunner.d.ts +4 -0
  47. package/dist/TaskRunner.js +39 -45
  48. package/dist/TaskRunner.js.map +1 -1
  49. package/dist/TaskStateManager.js +1 -5
  50. package/dist/TaskStateManager.js.map +1 -1
  51. package/dist/TaskStep.d.ts +6 -0
  52. package/dist/WorkflowExecutor.js +2 -0
  53. package/dist/WorkflowExecutor.js.map +1 -1
  54. package/dist/contracts/ErrorTypes.d.ts +6 -0
  55. package/dist/contracts/ErrorTypes.js +7 -0
  56. package/dist/contracts/ErrorTypes.js.map +1 -0
  57. package/dist/contracts/ValidationError.d.ts +2 -1
  58. package/openspec/changes/feat-task-metrics/proposal.md +17 -0
  59. package/openspec/changes/feat-task-metrics/tasks.md +6 -0
  60. package/package.json +14 -3
  61. package/src/TaskGraphValidator.ts +52 -32
  62. package/src/TaskRunner.ts +52 -47
  63. package/src/TaskStateManager.ts +1 -5
  64. package/src/TaskStep.ts +7 -0
  65. package/src/WorkflowExecutor.ts +3 -0
  66. package/src/contracts/ErrorTypes.ts +6 -0
  67. package/src/contracts/ValidationError.ts +10 -1
  68. package/test-report.xml +145 -123
@@ -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'>49/49</span>
28
+ <span class='fraction'>48/48</span>
29
29
  </div>
30
30
 
31
31
 
@@ -265,7 +265,12 @@
265
265
  <a name='L200'></a><a href='#L200'>200</a>
266
266
  <a name='L201'></a><a href='#L201'>201</a>
267
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">&nbsp;</span>
268
+ <a name='L203'></a><a href='#L203'>203</a>
269
+ <a name='L204'></a><a href='#L204'>204</a>
270
+ <a name='L205'></a><a href='#L205'>205</a>
271
+ <a name='L206'></a><a href='#L206'>206</a>
272
+ <a name='L207'></a><a href='#L207'>207</a>
273
+ <a name='L208'></a><a href='#L208'>208</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
269
274
  <span class="cline-any cline-neutral">&nbsp;</span>
270
275
  <span class="cline-any cline-neutral">&nbsp;</span>
271
276
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -292,15 +297,15 @@
292
297
  <span class="cline-any cline-neutral">&nbsp;</span>
293
298
  <span class="cline-any cline-neutral">&nbsp;</span>
294
299
  <span class="cline-any cline-neutral">&nbsp;</span>
295
- <span class="cline-any cline-yes">57x</span>
296
- <span class="cline-any cline-yes">57x</span>
300
+ <span class="cline-any cline-yes">63x</span>
301
+ <span class="cline-any cline-yes">63x</span>
297
302
  <span class="cline-any cline-neutral">&nbsp;</span>
298
- <span class="cline-any cline-yes">57x</span>
303
+ <span class="cline-any cline-yes">63x</span>
299
304
  <span class="cline-any cline-neutral">&nbsp;</span>
300
305
  <span class="cline-any cline-neutral">&nbsp;</span>
301
306
  <span class="cline-any cline-neutral">&nbsp;</span>
302
307
  <span class="cline-any cline-neutral">&nbsp;</span>
303
- <span class="cline-any cline-yes">57x</span>
308
+ <span class="cline-any cline-yes">63x</span>
304
309
  <span class="cline-any cline-neutral">&nbsp;</span>
305
310
  <span class="cline-any cline-neutral">&nbsp;</span>
306
311
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -344,34 +349,34 @@
344
349
  <span class="cline-any cline-neutral">&nbsp;</span>
345
350
  <span class="cline-any cline-neutral">&nbsp;</span>
346
351
  <span class="cline-any cline-neutral">&nbsp;</span>
347
- <span class="cline-any cline-yes">4x</span>
352
+ <span class="cline-any cline-yes">5x</span>
348
353
  <span class="cline-any cline-neutral">&nbsp;</span>
354
+ <span class="cline-any cline-yes">27x</span>
349
355
  <span class="cline-any cline-neutral">&nbsp;</span>
356
+ <span class="cline-any cline-yes">5x</span>
357
+ <span class="cline-any cline-yes">15x</span>
350
358
  <span class="cline-any cline-neutral">&nbsp;</span>
351
359
  <span class="cline-any cline-neutral">&nbsp;</span>
352
360
  <span class="cline-any cline-neutral">&nbsp;</span>
353
361
  <span class="cline-any cline-neutral">&nbsp;</span>
354
- <span class="cline-any cline-yes">12x</span>
355
- <span class="cline-any cline-yes">24x</span>
362
+ <span class="cline-any cline-yes">5x</span>
363
+ <span class="cline-any cline-yes">15x</span>
364
+ <span class="cline-any cline-yes">5x</span>
365
+ <span class="cline-any cline-yes">6x</span>
356
366
  <span class="cline-any cline-neutral">&nbsp;</span>
357
367
  <span class="cline-any cline-neutral">&nbsp;</span>
358
- <span class="cline-any cline-yes">4x</span>
359
368
  <span class="cline-any cline-neutral">&nbsp;</span>
360
369
  <span class="cline-any cline-neutral">&nbsp;</span>
370
+ <span class="cline-any cline-yes">5x</span>
361
371
  <span class="cline-any cline-neutral">&nbsp;</span>
362
- <span class="cline-any cline-yes">12x</span>
363
372
  <span class="cline-any cline-neutral">&nbsp;</span>
364
373
  <span class="cline-any cline-neutral">&nbsp;</span>
365
374
  <span class="cline-any cline-neutral">&nbsp;</span>
366
- <span class="cline-any cline-yes">4x</span>
367
- <span class="cline-any cline-yes">12x</span>
368
- <span class="cline-any cline-yes">5x</span>
369
- <span class="cline-any cline-yes">6x</span>
370
375
  <span class="cline-any cline-neutral">&nbsp;</span>
371
376
  <span class="cline-any cline-neutral">&nbsp;</span>
372
377
  <span class="cline-any cline-neutral">&nbsp;</span>
373
378
  <span class="cline-any cline-neutral">&nbsp;</span>
374
- <span class="cline-any cline-yes">4x</span>
379
+ <span class="cline-any cline-yes">27x</span>
375
380
  <span class="cline-any cline-neutral">&nbsp;</span>
376
381
  <span class="cline-any cline-neutral">&nbsp;</span>
377
382
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -380,7 +385,6 @@
380
385
  <span class="cline-any cline-neutral">&nbsp;</span>
381
386
  <span class="cline-any cline-neutral">&nbsp;</span>
382
387
  <span class="cline-any cline-neutral">&nbsp;</span>
383
- <span class="cline-any cline-yes">24x</span>
384
388
  <span class="cline-any cline-neutral">&nbsp;</span>
385
389
  <span class="cline-any cline-neutral">&nbsp;</span>
386
390
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -388,37 +392,49 @@
388
392
  <span class="cline-any cline-neutral">&nbsp;</span>
389
393
  <span class="cline-any cline-neutral">&nbsp;</span>
390
394
  <span class="cline-any cline-neutral">&nbsp;</span>
395
+ <span class="cline-any cline-yes">58x</span>
396
+ <span class="cline-any cline-yes">160x</span>
391
397
  <span class="cline-any cline-neutral">&nbsp;</span>
392
398
  <span class="cline-any cline-neutral">&nbsp;</span>
393
399
  <span class="cline-any cline-neutral">&nbsp;</span>
394
400
  <span class="cline-any cline-neutral">&nbsp;</span>
395
401
  <span class="cline-any cline-neutral">&nbsp;</span>
402
+ <span class="cline-any cline-yes">58x</span>
403
+ <span class="cline-any cline-yes">58x</span>
404
+ <span class="cline-any cline-yes">9x</span>
396
405
  <span class="cline-any cline-neutral">&nbsp;</span>
397
406
  <span class="cline-any cline-neutral">&nbsp;</span>
398
407
  <span class="cline-any cline-neutral">&nbsp;</span>
399
- <span class="cline-any cline-yes">52x</span>
400
- <span class="cline-any cline-yes">140x</span>
401
408
  <span class="cline-any cline-neutral">&nbsp;</span>
402
409
  <span class="cline-any cline-neutral">&nbsp;</span>
410
+ <span class="cline-any cline-yes">49x</span>
403
411
  <span class="cline-any cline-neutral">&nbsp;</span>
412
+ <span class="cline-any cline-yes">49x</span>
413
+ <span class="cline-any cline-yes">49x</span>
414
+ <span class="cline-any cline-yes">2x</span>
404
415
  <span class="cline-any cline-neutral">&nbsp;</span>
405
416
  <span class="cline-any cline-neutral">&nbsp;</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>
417
+ <span class="cline-any cline-yes">49x</span>
409
418
  <span class="cline-any cline-neutral">&nbsp;</span>
410
419
  <span class="cline-any cline-neutral">&nbsp;</span>
411
420
  <span class="cline-any cline-neutral">&nbsp;</span>
412
421
  <span class="cline-any cline-neutral">&nbsp;</span>
413
422
  <span class="cline-any cline-neutral">&nbsp;</span>
414
- <span class="cline-any cline-yes">43x</span>
415
423
  <span class="cline-any cline-neutral">&nbsp;</span>
416
- <span class="cline-any cline-yes">43x</span>
417
- <span class="cline-any cline-yes">43x</span>
418
- <span class="cline-any cline-yes">2x</span>
424
+ <span class="cline-any cline-neutral">&nbsp;</span>
425
+ <span class="cline-any cline-yes">58x</span>
426
+ <span class="cline-any cline-yes">5x</span>
427
+ <span class="cline-any cline-neutral">&nbsp;</span>
428
+ <span class="cline-any cline-neutral">&nbsp;</span>
429
+ <span class="cline-any cline-neutral">&nbsp;</span>
430
+ <span class="cline-any cline-neutral">&nbsp;</span>
431
+ <span class="cline-any cline-neutral">&nbsp;</span>
432
+ <span class="cline-any cline-neutral">&nbsp;</span>
433
+ <span class="cline-any cline-yes">44x</span>
434
+ <span class="cline-any cline-neutral">&nbsp;</span>
435
+ <span class="cline-any cline-neutral">&nbsp;</span>
419
436
  <span class="cline-any cline-neutral">&nbsp;</span>
420
437
  <span class="cline-any cline-neutral">&nbsp;</span>
421
- <span class="cline-any cline-yes">43x</span>
422
438
  <span class="cline-any cline-neutral">&nbsp;</span>
423
439
  <span class="cline-any cline-neutral">&nbsp;</span>
424
440
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -427,14 +443,11 @@
427
443
  <span class="cline-any cline-neutral">&nbsp;</span>
428
444
  <span class="cline-any cline-neutral">&nbsp;</span>
429
445
  <span class="cline-any cline-neutral">&nbsp;</span>
430
- <span class="cline-any cline-yes">52x</span>
431
446
  <span class="cline-any cline-yes">5x</span>
432
447
  <span class="cline-any cline-yes">5x</span>
433
448
  <span class="cline-any cline-yes">3x</span>
434
449
  <span class="cline-any cline-neutral">&nbsp;</span>
435
450
  <span class="cline-any cline-neutral">&nbsp;</span>
436
- <span class="cline-any cline-neutral">&nbsp;</span>
437
- <span class="cline-any cline-neutral">&nbsp;</span>
438
451
  <span class="cline-any cline-yes">5x</span>
439
452
  <span class="cline-any cline-neutral">&nbsp;</span>
440
453
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -463,9 +476,6 @@
463
476
  <span class="cline-any cline-neutral">&nbsp;</span>
464
477
  <span class="cline-any cline-neutral">&nbsp;</span>
465
478
  <span class="cline-any cline-neutral">&nbsp;</span>
466
- <span class="cline-any cline-yes">38x</span>
467
- <span class="cline-any cline-neutral">&nbsp;</span>
468
- <span class="cline-any cline-neutral">&nbsp;</span>
469
479
  <span class="cline-any cline-neutral">&nbsp;</span>
470
480
  <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">import { TaskStep } from "./TaskStep.js";
471
481
  import { TaskResult } from "./TaskResult.js";
@@ -548,23 +558,14 @@ export class TaskRunner&lt;TContext&gt; {
548
558
  public static getMermaidGraph&lt;T&gt;(steps: TaskStep&lt;T&gt;[]): string {
549
559
  const graphLines = ["graph TD"];
550
560
  &nbsp;
551
- // Helper to sanitize node names or wrap them if needed
552
- // For simplicity, we just wrap in quotes and use the name as ID if it's simple
553
- // or generate an ID if strictly needed. Here we assume names are unique IDs.
554
- // We will wrap names in quotes for the label, but use the name as the ID.
555
- // Actually, Mermaid ID cannot have spaces without quotes.
556
- const safeId = (name: string) =&gt; JSON.stringify(name);
557
561
  const sanitize = (name: string) =&gt; this.sanitizeMermaidId(name);
558
562
  &nbsp;
559
- // Add all nodes first to ensure they exist
560
563
  for (const step of steps) {
561
- // Using the name as both ID and Label for simplicity
562
- // Format: ID["Label"]
563
- // safeId returns a quoted string (e.g. "Task Name"), so we use it directly as the label
564
- graphLines.push(` ${sanitize(step.name)}[${safeId(step.name)}]`);
564
+ graphLines.push(
565
+ ` ${sanitize(step.name)}[${JSON.stringify(step.name)}]`
566
+ );
565
567
  }
566
568
  &nbsp;
567
- // Add edges
568
569
  for (const step of steps) {
569
570
  if (step.dependencies) {
570
571
  for (const dep of step.dependencies) {
@@ -582,7 +583,7 @@ export class TaskRunner&lt;TContext&gt; {
582
583
  * @returns The sanitized string.
583
584
  */
584
585
  private static sanitizeMermaidId(id: string): string {
585
- return id.replaceAll(/ /g, "_").replaceAll(/:/g, "_").replaceAll(/"/g, "_");
586
+ return id.replaceAll(/[^a-zA-Z0-9_-]/g, "_");
586
587
  }
587
588
  &nbsp;
588
589
  /**
@@ -628,44 +629,58 @@ export class TaskRunner&lt;TContext&gt; {
628
629
  config?.concurrency
629
630
  );
630
631
  &nbsp;
631
- // We need to handle the timeout cleanup properly.
632
632
  if (config?.timeout !== undefined) {
633
- const controller = new AbortController();
634
- const timeoutId = setTimeout(() =&gt; {
635
- controller.abort(
636
- new Error(`Workflow timed out after ${config.timeout}ms`)
637
- );
638
- }, config.timeout);
633
+ return this.executeWithTimeout(
634
+ executor,
635
+ steps,
636
+ config.timeout,
637
+ config.signal
638
+ );
639
+ } else {
640
+ return executor.execute(steps, config?.signal);
641
+ }
642
+ }
639
643
  &nbsp;
640
- let effectiveSignal = controller.signal;
641
- let onAbort: (() =&gt; void) | undefined;
644
+ /**
645
+ * Executes tasks with a timeout, ensuring resources are cleaned up.
646
+ */
647
+ private async executeWithTimeout(
648
+ executor: WorkflowExecutor&lt;TContext&gt;,
649
+ steps: TaskStep&lt;TContext&gt;[],
650
+ timeout: number,
651
+ signal?: AbortSignal
652
+ ): Promise&lt;Map&lt;string, TaskResult&gt;&gt; {
653
+ const controller = new AbortController();
654
+ const timeoutId = setTimeout(() =&gt; {
655
+ controller.abort(new Error(`Workflow timed out after ${timeout}ms`));
656
+ }, timeout);
642
657
  &nbsp;
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 = () =&gt; {
653
- controller.abort(config.signal?.reason);
654
- };
655
- config.signal.addEventListener("abort", onAbort);
656
- }
657
- }
658
+ let effectiveSignal = controller.signal;
659
+ let onAbort: (() =&gt; void) | undefined;
658
660
  &nbsp;
659
- try {
660
- return await executor.execute(steps, effectiveSignal);
661
- } finally {
661
+ // Handle combination of signals if user provided one
662
+ if (signal) {
663
+ if (signal.aborted) {
664
+ // If already aborted, use it directly (WorkflowExecutor handles early abort)
665
+ // We can cancel timeout immediately
662
666
  clearTimeout(timeoutId);
663
- if (config.signal &amp;&amp; onAbort) {
664
- config.signal.removeEventListener("abort", onAbort);
665
- }
667
+ effectiveSignal = signal;
668
+ } else {
669
+ // Listen to user signal to abort our controller
670
+ onAbort = () =&gt; {
671
+ controller.abort(signal.reason);
672
+ };
673
+ signal.addEventListener("abort", onAbort);
674
+ }
675
+ }
676
+ &nbsp;
677
+ try {
678
+ return await executor.execute(steps, effectiveSignal);
679
+ } finally {
680
+ clearTimeout(timeoutId);
681
+ if (signal &amp;&amp; onAbort) {
682
+ signal.removeEventListener("abort", onAbort);
666
683
  }
667
- } else {
668
- return executor.execute(steps, config?.signal);
669
684
  }
670
685
  }
671
686
  }
@@ -676,7 +691,7 @@ export class TaskRunner&lt;TContext&gt; {
676
691
  <div class='footer quiet pad2 space-top1 center small'>
677
692
  Code coverage generated by
678
693
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
679
- at 2026-01-19T22:41:01.775Z
694
+ at 2026-01-21T01:05:21.402Z
680
695
  </div>
681
696
  <script src="../prettify.js"></script>
682
697
  <script>
@@ -322,7 +322,7 @@ export class TaskRunnerBuilder&lt;TContext&gt; {
322
322
  <div class='footer quiet pad2 space-top1 center small'>
323
323
  Code coverage generated by
324
324
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
325
- at 2026-01-19T22:41:01.775Z
325
+ at 2026-01-21T01:05:21.402Z
326
326
  </div>
327
327
  <script src="../prettify.js"></script>
328
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-19T22:41:01.775Z
142
+ at 2026-01-21T01:05:21.402Z
143
143
  </div>
144
144
  <script src="../prettify.js"></script>
145
145
  <script>
@@ -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'>47/47</span>
28
+ <span class='fraction'>48/48</span>
29
29
  </div>
30
30
 
31
31
 
@@ -46,7 +46,7 @@
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'>47/47</span>
49
+ <span class='fraction'>48/48</span>
50
50
  </div>
51
51
 
52
52
 
@@ -211,11 +211,7 @@
211
211
  <a name='L146'></a><a href='#L146'>146</a>
212
212
  <a name='L147'></a><a href='#L147'>147</a>
213
213
  <a name='L148'></a><a href='#L148'>148</a>
214
- <a name='L149'></a><a href='#L149'>149</a>
215
- <a name='L150'></a><a href='#L150'>150</a>
216
- <a name='L151'></a><a href='#L151'>151</a>
217
- <a name='L152'></a><a href='#L152'>152</a>
218
- <a name='L153'></a><a href='#L153'>153</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
214
+ <a name='L149'></a><a href='#L149'>149</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
219
215
  <span class="cline-any cline-neutral">&nbsp;</span>
220
216
  <span class="cline-any cline-neutral">&nbsp;</span>
221
217
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -224,20 +220,20 @@
224
220
  <span class="cline-any cline-neutral">&nbsp;</span>
225
221
  <span class="cline-any cline-neutral">&nbsp;</span>
226
222
  <span class="cline-any cline-neutral">&nbsp;</span>
227
- <span class="cline-any cline-yes">59x</span>
228
- <span class="cline-any cline-yes">59x</span>
229
- <span class="cline-any cline-yes">59x</span>
223
+ <span class="cline-any cline-yes">66x</span>
224
+ <span class="cline-any cline-yes">66x</span>
225
+ <span class="cline-any cline-yes">66x</span>
230
226
  <span class="cline-any cline-neutral">&nbsp;</span>
231
- <span class="cline-any cline-yes">59x</span>
227
+ <span class="cline-any cline-yes">66x</span>
232
228
  <span class="cline-any cline-neutral">&nbsp;</span>
233
229
  <span class="cline-any cline-neutral">&nbsp;</span>
234
230
  <span class="cline-any cline-neutral">&nbsp;</span>
235
231
  <span class="cline-any cline-neutral">&nbsp;</span>
236
232
  <span class="cline-any cline-neutral">&nbsp;</span>
237
233
  <span class="cline-any cline-neutral">&nbsp;</span>
238
- <span class="cline-any cline-yes">58x</span>
239
- <span class="cline-any cline-yes">58x</span>
240
- <span class="cline-any cline-yes">58x</span>
234
+ <span class="cline-any cline-yes">65x</span>
235
+ <span class="cline-any cline-yes">65x</span>
236
+ <span class="cline-any cline-yes">65x</span>
241
237
  <span class="cline-any cline-neutral">&nbsp;</span>
242
238
  <span class="cline-any cline-neutral">&nbsp;</span>
243
239
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -246,26 +242,26 @@
246
242
  <span class="cline-any cline-neutral">&nbsp;</span>
247
243
  <span class="cline-any cline-neutral">&nbsp;</span>
248
244
  <span class="cline-any cline-neutral">&nbsp;</span>
249
- <span class="cline-any cline-yes">272x</span>
250
- <span class="cline-any cline-yes">272x</span>
245
+ <span class="cline-any cline-yes">318x</span>
246
+ <span class="cline-any cline-yes">318x</span>
251
247
  <span class="cline-any cline-neutral">&nbsp;</span>
252
- <span class="cline-any cline-yes">272x</span>
253
- <span class="cline-any cline-yes">393x</span>
254
- <span class="cline-any cline-yes">393x</span>
248
+ <span class="cline-any cline-yes">318x</span>
249
+ <span class="cline-any cline-yes">418x</span>
250
+ <span class="cline-any cline-yes">418x</span>
255
251
  <span class="cline-any cline-neutral">&nbsp;</span>
256
252
  <span class="cline-any cline-neutral">&nbsp;</span>
257
- <span class="cline-any cline-yes">393x</span>
258
- <span class="cline-any cline-yes">1162x</span>
259
- <span class="cline-any cline-yes">1162x</span>
253
+ <span class="cline-any cline-yes">418x</span>
254
+ <span class="cline-any cline-yes">1170x</span>
255
+ <span class="cline-any cline-yes">1170x</span>
260
256
  <span class="cline-any cline-neutral">&nbsp;</span>
261
- <span class="cline-any cline-yes">1008x</span>
262
- <span class="cline-any cline-yes">154x</span>
257
+ <span class="cline-any cline-yes">1013x</span>
258
+ <span class="cline-any cline-yes">157x</span>
263
259
  <span class="cline-any cline-yes">9x</span>
264
260
  <span class="cline-any cline-yes">9x</span>
265
261
  <span class="cline-any cline-neutral">&nbsp;</span>
266
262
  <span class="cline-any cline-neutral">&nbsp;</span>
267
263
  <span class="cline-any cline-neutral">&nbsp;</span>
268
- <span class="cline-any cline-yes">393x</span>
264
+ <span class="cline-any cline-yes">418x</span>
269
265
  <span class="cline-any cline-yes">9x</span>
270
266
  <span class="cline-any cline-yes">9x</span>
271
267
  <span class="cline-any cline-yes">9x</span>
@@ -274,18 +270,18 @@
274
270
  <span class="cline-any cline-neutral">&nbsp;</span>
275
271
  <span class="cline-any cline-yes">9x</span>
276
272
  <span class="cline-any cline-yes">9x</span>
277
- <span class="cline-any cline-yes">384x</span>
278
- <span class="cline-any cline-yes">129x</span>
279
- <span class="cline-any cline-yes">129x</span>
273
+ <span class="cline-any cline-yes">409x</span>
274
+ <span class="cline-any cline-yes">149x</span>
275
+ <span class="cline-any cline-yes">149x</span>
280
276
  <span class="cline-any cline-neutral">&nbsp;</span>
281
277
  <span class="cline-any cline-neutral">&nbsp;</span>
282
278
  <span class="cline-any cline-neutral">&nbsp;</span>
283
279
  <span class="cline-any cline-neutral">&nbsp;</span>
284
- <span class="cline-any cline-yes">272x</span>
285
- <span class="cline-any cline-yes">138x</span>
280
+ <span class="cline-any cline-yes">318x</span>
281
+ <span class="cline-any cline-yes">158x</span>
286
282
  <span class="cline-any cline-neutral">&nbsp;</span>
287
283
  <span class="cline-any cline-neutral">&nbsp;</span>
288
- <span class="cline-any cline-yes">272x</span>
284
+ <span class="cline-any cline-yes">318x</span>
289
285
  <span class="cline-any cline-neutral">&nbsp;</span>
290
286
  <span class="cline-any cline-neutral">&nbsp;</span>
291
287
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -293,8 +289,8 @@
293
289
  <span class="cline-any cline-neutral">&nbsp;</span>
294
290
  <span class="cline-any cline-neutral">&nbsp;</span>
295
291
  <span class="cline-any cline-neutral">&nbsp;</span>
296
- <span class="cline-any cline-yes">122x</span>
297
- <span class="cline-any cline-yes">122x</span>
292
+ <span class="cline-any cline-yes">142x</span>
293
+ <span class="cline-any cline-yes">142x</span>
298
294
  <span class="cline-any cline-neutral">&nbsp;</span>
299
295
  <span class="cline-any cline-neutral">&nbsp;</span>
300
296
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -304,9 +300,9 @@
304
300
  <span class="cline-any cline-neutral">&nbsp;</span>
305
301
  <span class="cline-any cline-neutral">&nbsp;</span>
306
302
  <span class="cline-any cline-neutral">&nbsp;</span>
307
- <span class="cline-any cline-yes">127x</span>
308
- <span class="cline-any cline-yes">127x</span>
309
- <span class="cline-any cline-yes">127x</span>
303
+ <span class="cline-any cline-yes">147x</span>
304
+ <span class="cline-any cline-yes">147x</span>
305
+ <span class="cline-any cline-yes">147x</span>
310
306
  <span class="cline-any cline-neutral">&nbsp;</span>
311
307
  <span class="cline-any cline-neutral">&nbsp;</span>
312
308
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -315,45 +311,41 @@
315
311
  <span class="cline-any cline-neutral">&nbsp;</span>
316
312
  <span class="cline-any cline-neutral">&nbsp;</span>
317
313
  <span class="cline-any cline-neutral">&nbsp;</span>
318
- <span class="cline-any cline-yes">81x</span>
319
- <span class="cline-any cline-neutral">&nbsp;</span>
314
+ <span class="cline-any cline-yes">88x</span>
320
315
  <span class="cline-any cline-neutral">&nbsp;</span>
321
316
  <span class="cline-any cline-neutral">&nbsp;</span>
317
+ <span class="cline-any cline-yes">8x</span>
322
318
  <span class="cline-any cline-yes">7x</span>
323
- <span class="cline-any cline-yes">6x</span>
324
- <span class="cline-any cline-neutral">&nbsp;</span>
325
- <span class="cline-any cline-neutral">&nbsp;</span>
326
- <span class="cline-any cline-neutral">&nbsp;</span>
327
- <span class="cline-any cline-yes">6x</span>
328
- <span class="cline-any cline-neutral">&nbsp;</span>
329
319
  <span class="cline-any cline-neutral">&nbsp;</span>
330
320
  <span class="cline-any cline-neutral">&nbsp;</span>
331
321
  <span class="cline-any cline-neutral">&nbsp;</span>
322
+ <span class="cline-any cline-yes">7x</span>
323
+ <span class="cline-any cline-yes">7x</span>
332
324
  <span class="cline-any cline-neutral">&nbsp;</span>
333
325
  <span class="cline-any cline-neutral">&nbsp;</span>
334
326
  <span class="cline-any cline-neutral">&nbsp;</span>
335
- <span class="cline-any cline-yes">81x</span>
327
+ <span class="cline-any cline-yes">88x</span>
336
328
  <span class="cline-any cline-neutral">&nbsp;</span>
337
329
  <span class="cline-any cline-neutral">&nbsp;</span>
338
330
  <span class="cline-any cline-neutral">&nbsp;</span>
339
331
  <span class="cline-any cline-neutral">&nbsp;</span>
340
332
  <span class="cline-any cline-neutral">&nbsp;</span>
341
333
  <span class="cline-any cline-neutral">&nbsp;</span>
342
- <span class="cline-any cline-yes">59x</span>
334
+ <span class="cline-any cline-yes">65x</span>
343
335
  <span class="cline-any cline-neutral">&nbsp;</span>
344
336
  <span class="cline-any cline-neutral">&nbsp;</span>
345
337
  <span class="cline-any cline-neutral">&nbsp;</span>
346
338
  <span class="cline-any cline-neutral">&nbsp;</span>
347
339
  <span class="cline-any cline-neutral">&nbsp;</span>
348
340
  <span class="cline-any cline-neutral">&nbsp;</span>
349
- <span class="cline-any cline-yes">121x</span>
341
+ <span class="cline-any cline-yes">144x</span>
350
342
  <span class="cline-any cline-neutral">&nbsp;</span>
351
343
  <span class="cline-any cline-neutral">&nbsp;</span>
352
344
  <span class="cline-any cline-neutral">&nbsp;</span>
353
345
  <span class="cline-any cline-neutral">&nbsp;</span>
354
346
  <span class="cline-any cline-neutral">&nbsp;</span>
355
347
  <span class="cline-any cline-neutral">&nbsp;</span>
356
- <span class="cline-any cline-yes">154x</span>
348
+ <span class="cline-any cline-yes">180x</span>
357
349
  <span class="cline-any cline-neutral">&nbsp;</span>
358
350
  <span class="cline-any cline-neutral">&nbsp;</span>
359
351
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -470,20 +462,16 @@ export class TaskStateManager&lt;TContext&gt; {
470
462
  for (const step of this.pendingSteps) {
471
463
  // Also check running? No, running tasks are handled by AbortSignal in Executor.
472
464
  // We only cancel what is pending and hasn't started.
473
- /* v8 ignore next 1 */
474
465
  if (!this.results.has(step.name) &amp;&amp; !this.running.has(step.name)) {
475
466
  const result: TaskResult = {
476
467
  status: "cancelled",
477
468
  message,
478
469
  };
479
470
  this.results.set(step.name, result);
471
+ this.eventBus.emit("taskEnd", { step, result });
480
472
  }
481
473
  }
482
474
  // Clear pending set as they are now "done" (cancelled)
483
- // Wait, if we clear pending steps, processDependencies won't pick them up.
484
- // The loop in Executor relies on results.size or pendingSteps.
485
- // The previous implementation iterated `steps` (all steps) to cancel.
486
- // Here we iterate `pendingSteps`.
487
475
  this.pendingSteps.clear();
488
476
  }
489
477
  &nbsp;
@@ -526,7 +514,7 @@ export class TaskStateManager&lt;TContext&gt; {
526
514
  <div class='footer quiet pad2 space-top1 center small'>
527
515
  Code coverage generated by
528
516
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
529
- at 2026-01-19T22:41:01.775Z
517
+ at 2026-01-21T01:05:21.402Z
530
518
  </div>
531
519
  <script src="../prettify.js"></script>
532
520
  <script>