@calmo/task-runner 3.4.0 → 3.5.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.
Files changed (95) hide show
  1. package/.github/dependabot.yml +7 -7
  2. package/.github/workflows/ci.yml +4 -4
  3. package/.jules/backlog_maniac.md +1 -0
  4. package/.jules/nexus.md +1 -0
  5. package/.jules/sentinel.md +1 -0
  6. package/.releaserc.json +2 -7
  7. package/AGENTS.md +21 -16
  8. package/CHANGELOG.md +192 -174
  9. package/README.md +95 -88
  10. package/coverage/coverage-final.json +9 -9
  11. package/coverage/index.html +9 -9
  12. package/coverage/lcov-report/index.html +9 -9
  13. package/coverage/lcov-report/src/EventBus.ts.html +30 -24
  14. package/coverage/lcov-report/src/TaskGraphValidationError.ts.html +12 -3
  15. package/coverage/lcov-report/src/TaskGraphValidator.ts.html +152 -137
  16. package/coverage/lcov-report/src/TaskRunner.ts.html +48 -45
  17. package/coverage/lcov-report/src/TaskRunnerBuilder.ts.html +29 -5
  18. package/coverage/lcov-report/src/TaskRunnerExecutionConfig.ts.html +1 -1
  19. package/coverage/lcov-report/src/TaskStateManager.ts.html +82 -52
  20. package/coverage/lcov-report/src/WorkflowExecutor.ts.html +210 -66
  21. package/coverage/lcov-report/src/contracts/RunnerEvents.ts.html +1 -1
  22. package/coverage/lcov-report/src/contracts/index.html +1 -1
  23. package/coverage/lcov-report/src/index.html +16 -16
  24. package/coverage/lcov-report/src/strategies/DryRunExecutionStrategy.ts.html +4 -4
  25. package/coverage/lcov-report/src/strategies/RetryingExecutionStrategy.ts.html +29 -11
  26. package/coverage/lcov-report/src/strategies/StandardExecutionStrategy.ts.html +7 -7
  27. package/coverage/lcov-report/src/strategies/index.html +1 -1
  28. package/coverage/lcov.info +426 -383
  29. package/coverage/src/EventBus.ts.html +30 -24
  30. package/coverage/src/TaskGraphValidationError.ts.html +12 -3
  31. package/coverage/src/TaskGraphValidator.ts.html +152 -137
  32. package/coverage/src/TaskRunner.ts.html +48 -45
  33. package/coverage/src/TaskRunnerBuilder.ts.html +29 -5
  34. package/coverage/src/TaskRunnerExecutionConfig.ts.html +1 -1
  35. package/coverage/src/TaskStateManager.ts.html +82 -52
  36. package/coverage/src/WorkflowExecutor.ts.html +210 -66
  37. package/coverage/src/contracts/RunnerEvents.ts.html +1 -1
  38. package/coverage/src/contracts/index.html +1 -1
  39. package/coverage/src/index.html +16 -16
  40. package/coverage/src/strategies/DryRunExecutionStrategy.ts.html +4 -4
  41. package/coverage/src/strategies/RetryingExecutionStrategy.ts.html +29 -11
  42. package/coverage/src/strategies/StandardExecutionStrategy.ts.html +7 -7
  43. package/coverage/src/strategies/index.html +1 -1
  44. package/dist/EventBus.js +13 -11
  45. package/dist/EventBus.js.map +1 -1
  46. package/dist/TaskGraphValidationError.js.map +1 -1
  47. package/dist/TaskGraphValidator.js +9 -9
  48. package/dist/TaskGraphValidator.js.map +1 -1
  49. package/dist/TaskRunner.js.map +1 -1
  50. package/dist/TaskRunnerBuilder.js.map +1 -1
  51. package/dist/TaskStateManager.d.ts +6 -0
  52. package/dist/TaskStateManager.js +11 -2
  53. package/dist/TaskStateManager.js.map +1 -1
  54. package/dist/TaskStep.d.ts +5 -0
  55. package/dist/WorkflowExecutor.js +49 -7
  56. package/dist/WorkflowExecutor.js.map +1 -1
  57. package/dist/strategies/RetryingExecutionStrategy.js +3 -1
  58. package/dist/strategies/RetryingExecutionStrategy.js.map +1 -1
  59. package/dist/strategies/StandardExecutionStrategy.js +1 -1
  60. package/dist/strategies/StandardExecutionStrategy.js.map +1 -1
  61. package/openspec/AGENTS.md +81 -15
  62. package/openspec/changes/archive/2026-01-18-add-concurrency-control/proposal.md +7 -4
  63. package/openspec/changes/archive/2026-01-18-add-concurrency-control/tasks.md +1 -0
  64. package/openspec/changes/archive/2026-01-18-add-external-task-cancellation/proposal.md +4 -1
  65. package/openspec/changes/archive/2026-01-18-add-external-task-cancellation/tasks.md +2 -1
  66. package/openspec/changes/archive/2026-01-18-add-integration-tests/proposal.md +3 -0
  67. package/openspec/changes/archive/2026-01-18-add-integration-tests/tasks.md +1 -0
  68. package/openspec/changes/archive/2026-01-18-add-task-retry-policy/proposal.md +3 -0
  69. package/openspec/changes/archive/2026-01-18-add-task-retry-policy/tasks.md +1 -0
  70. package/openspec/changes/archive/2026-01-18-add-workflow-preview/proposal.md +3 -0
  71. package/openspec/changes/archive/2026-01-18-add-workflow-preview/tasks.md +1 -0
  72. package/openspec/changes/archive/2026-01-18-feat-conditional-execution/proposal.md +35 -0
  73. package/openspec/changes/archive/2026-01-18-feat-conditional-execution/tasks.md +32 -0
  74. package/openspec/changes/archive/2026-01-18-refactor-core-architecture/proposal.md +3 -0
  75. package/openspec/changes/archive/2026-01-18-refactor-core-architecture/tasks.md +1 -0
  76. package/openspec/changes/feat-per-task-timeout/proposal.md +11 -6
  77. package/openspec/changes/feat-per-task-timeout/tasks.md +1 -1
  78. package/openspec/project.md +21 -15
  79. package/package.json +2 -1
  80. package/src/EventBus.ts +18 -16
  81. package/src/TaskGraph.ts +8 -8
  82. package/src/TaskGraphValidationError.ts +4 -1
  83. package/src/TaskGraphValidator.ts +148 -143
  84. package/src/TaskRunner.ts +42 -41
  85. package/src/TaskRunnerBuilder.ts +11 -3
  86. package/src/TaskStateManager.ts +12 -2
  87. package/src/TaskStep.ts +6 -0
  88. package/src/WorkflowExecutor.ts +63 -15
  89. package/src/contracts/ITaskGraphValidator.ts +12 -12
  90. package/src/contracts/ValidationError.ts +6 -6
  91. package/src/contracts/ValidationResult.ts +4 -4
  92. package/src/strategies/DryRunExecutionStrategy.ts +3 -3
  93. package/src/strategies/RetryingExecutionStrategy.ts +15 -9
  94. package/src/strategies/StandardExecutionStrategy.ts +4 -4
  95. package/test-report.xml +132 -108
@@ -264,7 +264,11 @@
264
264
  <a name='L199'></a><a href='#L199'>199</a>
265
265
  <a name='L200'></a><a href='#L200'>200</a>
266
266
  <a name='L201'></a><a href='#L201'>201</a>
267
- <a name='L202'></a><a href='#L202'>202</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
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>
269
+ <span class="cline-any cline-neutral">&nbsp;</span>
270
+ <span class="cline-any cline-neutral">&nbsp;</span>
271
+ <span class="cline-any cline-neutral">&nbsp;</span>
268
272
  <span class="cline-any cline-neutral">&nbsp;</span>
269
273
  <span class="cline-any cline-neutral">&nbsp;</span>
270
274
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -288,11 +292,10 @@
288
292
  <span class="cline-any cline-neutral">&nbsp;</span>
289
293
  <span class="cline-any cline-neutral">&nbsp;</span>
290
294
  <span class="cline-any cline-neutral">&nbsp;</span>
291
- <span class="cline-any cline-yes">57x</span>
292
295
  <span class="cline-any cline-yes">57x</span>
293
296
  <span class="cline-any cline-yes">57x</span>
294
297
  <span class="cline-any cline-neutral">&nbsp;</span>
295
- <span class="cline-any cline-neutral">&nbsp;</span>
298
+ <span class="cline-any cline-yes">57x</span>
296
299
  <span class="cline-any cline-neutral">&nbsp;</span>
297
300
  <span class="cline-any cline-neutral">&nbsp;</span>
298
301
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -352,7 +355,6 @@
352
355
  <span class="cline-any cline-yes">24x</span>
353
356
  <span class="cline-any cline-neutral">&nbsp;</span>
354
357
  <span class="cline-any cline-neutral">&nbsp;</span>
355
- <span class="cline-any cline-neutral">&nbsp;</span>
356
358
  <span class="cline-any cline-yes">4x</span>
357
359
  <span class="cline-any cline-neutral">&nbsp;</span>
358
360
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -369,8 +371,6 @@
369
371
  <span class="cline-any cline-neutral">&nbsp;</span>
370
372
  <span class="cline-any cline-neutral">&nbsp;</span>
371
373
  <span class="cline-any cline-neutral">&nbsp;</span>
372
- <span class="cline-any cline-neutral">&nbsp;</span>
373
- <span class="cline-any cline-neutral">&nbsp;</span>
374
374
  <span class="cline-any cline-yes">4x</span>
375
375
  <span class="cline-any cline-neutral">&nbsp;</span>
376
376
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -433,6 +433,8 @@
433
433
  <span class="cline-any cline-yes">3x</span>
434
434
  <span class="cline-any cline-neutral">&nbsp;</span>
435
435
  <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>
436
438
  <span class="cline-any cline-yes">5x</span>
437
439
  <span class="cline-any cline-neutral">&nbsp;</span>
438
440
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -469,7 +471,10 @@
469
471
  import { TaskResult } from "./TaskResult.js";
470
472
  import { TaskGraphValidator } from "./TaskGraphValidator.js";
471
473
  import { TaskGraph } from "./TaskGraph.js";
472
- import { RunnerEventPayloads, RunnerEventListener } from "./contracts/RunnerEvents.js";
474
+ import {
475
+ RunnerEventPayloads,
476
+ RunnerEventListener,
477
+ } from "./contracts/RunnerEvents.js";
473
478
  import { EventBus } from "./EventBus.js";
474
479
  import { WorkflowExecutor } from "./WorkflowExecutor.js";
475
480
  import { TaskRunnerExecutionConfig } from "./TaskRunnerExecutionConfig.js";
@@ -491,9 +496,8 @@ export { RunnerEventPayloads, RunnerEventListener, TaskRunnerExecutionConfig };
491
496
  export class TaskRunner&lt;TContext&gt; {
492
497
  private eventBus = new EventBus&lt;TContext&gt;();
493
498
  private validator = new TaskGraphValidator();
494
- private executionStrategy: IExecutionStrategy&lt;TContext&gt; = new RetryingExecutionStrategy(
495
- new StandardExecutionStrategy()
496
- );
499
+ private executionStrategy: IExecutionStrategy&lt;TContext&gt; =
500
+ new RetryingExecutionStrategy(new StandardExecutionStrategy());
497
501
  &nbsp;
498
502
  /**
499
503
  * @param context The shared context object to be passed to each task.
@@ -551,7 +555,6 @@ export class TaskRunner&lt;TContext&gt; {
551
555
  // Actually, Mermaid ID cannot have spaces without quotes.
552
556
  const safeId = (name: string) =&gt; JSON.stringify(name);
553
557
  const sanitize = (name: string) =&gt; this.sanitizeMermaidId(name);
554
- &nbsp;
555
558
  &nbsp;
556
559
  // Add all nodes first to ensure they exist
557
560
  for (const step of steps) {
@@ -565,9 +568,7 @@ export class TaskRunner&lt;TContext&gt; {
565
568
  for (const step of steps) {
566
569
  if (step.dependencies) {
567
570
  for (const dep of step.dependencies) {
568
- graphLines.push(
569
- ` ${sanitize(dep)} --&gt; ${sanitize(step.name)}`
570
- );
571
+ graphLines.push(` ${sanitize(dep)} --&gt; ${sanitize(step.name)}`);
571
572
  }
572
573
  }
573
574
  }
@@ -629,40 +630,42 @@ export class TaskRunner&lt;TContext&gt; {
629
630
  &nbsp;
630
631
  // We need to handle the timeout cleanup properly.
631
632
  if (config?.timeout !== undefined) {
632
- const controller = new AbortController();
633
- const timeoutId = setTimeout(() =&gt; {
634
- controller.abort(new Error(`Workflow timed out after ${config.timeout}ms`));
635
- }, config.timeout);
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);
636
639
  &nbsp;
637
- let effectiveSignal = controller.signal;
638
- let onAbort: (() =&gt; void) | undefined;
640
+ let effectiveSignal = controller.signal;
641
+ let onAbort: (() =&gt; void) | undefined;
639
642
  &nbsp;
640
- // Handle combination of signals if user provided one
641
- if (config.signal) {
642
- if (config.signal.aborted) {
643
- // If already aborted, use it directly (WorkflowExecutor handles early abort)
644
- // We can cancel timeout immediately
645
- clearTimeout(timeoutId);
646
- effectiveSignal = config.signal;
647
- } else {
648
- // Listen to user signal to abort our controller
649
- onAbort = () =&gt; {
650
- controller.abort(config.signal?.reason);
651
- };
652
- config.signal.addEventListener("abort", onAbort);
653
- }
654
- }
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
+ }
655
658
  &nbsp;
656
- try {
657
- return await executor.execute(steps, effectiveSignal);
658
- } finally {
659
- clearTimeout(timeoutId);
660
- if (config.signal &amp;&amp; onAbort) {
661
- config.signal.removeEventListener("abort", onAbort);
662
- }
663
- }
659
+ try {
660
+ return await executor.execute(steps, effectiveSignal);
661
+ } finally {
662
+ clearTimeout(timeoutId);
663
+ if (config.signal &amp;&amp; onAbort) {
664
+ config.signal.removeEventListener("abort", onAbort);
665
+ }
666
+ }
664
667
  } else {
665
- return executor.execute(steps, config?.signal);
668
+ return executor.execute(steps, config?.signal);
666
669
  }
667
670
  }
668
671
  }
@@ -673,7 +676,7 @@ export class TaskRunner&lt;TContext&gt; {
673
676
  <div class='footer quiet pad2 space-top1 center small'>
674
677
  Code coverage generated by
675
678
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
676
- at 2026-01-18T20:19:46.886Z
679
+ at 2026-01-18T23:00:28.573Z
677
680
  </div>
678
681
  <script src="../prettify.js"></script>
679
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></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
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">&nbsp;</span>
151
+ <span class="cline-any cline-neutral">&nbsp;</span>
152
+ <span class="cline-any cline-neutral">&nbsp;</span>
153
+ <span class="cline-any cline-neutral">&nbsp;</span>
154
+ <span class="cline-any cline-neutral">&nbsp;</span>
155
+ <span class="cline-any cline-neutral">&nbsp;</span>
156
+ <span class="cline-any cline-neutral">&nbsp;</span>
143
157
  <span class="cline-any cline-neutral">&nbsp;</span>
144
158
  <span class="cline-any cline-neutral">&nbsp;</span>
145
159
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -198,7 +212,9 @@
198
212
  <span class="cline-any cline-yes">1x</span>
199
213
  <span class="cline-any cline-neutral">&nbsp;</span>
200
214
  <span class="cline-any cline-neutral">&nbsp;</span>
215
+ <span class="cline-any cline-neutral">&nbsp;</span>
201
216
  <span class="cline-any cline-yes">2x</span>
217
+ <span class="cline-any cline-neutral">&nbsp;</span>
202
218
  <span class="cline-any cline-yes">1x</span>
203
219
  <span class="cline-any cline-neutral">&nbsp;</span>
204
220
  <span class="cline-any cline-yes">1x</span>
@@ -216,7 +232,10 @@
216
232
  <span class="cline-any cline-neutral">&nbsp;</span>
217
233
  <span class="cline-any cline-neutral">&nbsp;</span>
218
234
  <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">import { TaskRunner } from "./TaskRunner.js";
219
- import { RunnerEventPayloads, RunnerEventListener } from "./contracts/RunnerEvents.js";
235
+ import {
236
+ RunnerEventPayloads,
237
+ RunnerEventListener,
238
+ } from "./contracts/RunnerEvents.js";
220
239
  import { IExecutionStrategy } from "./strategies/IExecutionStrategy.js";
221
240
  &nbsp;
222
241
  /**
@@ -226,7 +245,10 @@ export class TaskRunnerBuilder&lt;TContext&gt; {
226
245
  private context: TContext;
227
246
  private strategy?: IExecutionStrategy&lt;TContext&gt;;
228
247
  private listeners: {
229
- [K in keyof RunnerEventPayloads&lt;TContext&gt;]?: RunnerEventListener&lt;TContext, K&gt;[];
248
+ [K in keyof RunnerEventPayloads&lt;TContext&gt;]?: RunnerEventListener&lt;
249
+ TContext,
250
+ K
251
+ &gt;[];
230
252
  } = {};
231
253
  &nbsp;
232
254
  /**
@@ -274,7 +296,9 @@ export class TaskRunnerBuilder&lt;TContext&gt; {
274
296
  runner.setExecutionStrategy(this.strategy);
275
297
  }
276
298
  &nbsp;
277
- (Object.keys(this.listeners) as Array&lt;keyof RunnerEventPayloads&lt;TContext&gt;&gt;).forEach((event) =&gt; {
299
+ (
300
+ Object.keys(this.listeners) as Array&lt;keyof RunnerEventPayloads&lt;TContext&gt;&gt;
301
+ ).forEach((event) =&gt; {
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) =&gt;
@@ -298,7 +322,7 @@ export class TaskRunnerBuilder&lt;TContext&gt; {
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-18T20:19:46.886Z
325
+ at 2026-01-18T23:00:28.573Z
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-18T20:19:46.886Z
142
+ at 2026-01-18T23:00:28.573Z
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'>45/45</span>
28
+ <span class='fraction'>47/47</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'>9/9</span>
42
+ <span class='fraction'>10/10</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'>45/45</span>
49
+ <span class='fraction'>47/47</span>
50
50
  </div>
51
51
 
52
52
 
@@ -205,7 +205,17 @@
205
205
  <a name='L140'></a><a href='#L140'>140</a>
206
206
  <a name='L141'></a><a href='#L141'>141</a>
207
207
  <a name='L142'></a><a href='#L142'>142</a>
208
- <a name='L143'></a><a href='#L143'>143</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
208
+ <a name='L143'></a><a href='#L143'>143</a>
209
+ <a name='L144'></a><a href='#L144'>144</a>
210
+ <a name='L145'></a><a href='#L145'>145</a>
211
+ <a name='L146'></a><a href='#L146'>146</a>
212
+ <a name='L147'></a><a href='#L147'>147</a>
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>
209
219
  <span class="cline-any cline-neutral">&nbsp;</span>
210
220
  <span class="cline-any cline-neutral">&nbsp;</span>
211
221
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -214,20 +224,20 @@
214
224
  <span class="cline-any cline-neutral">&nbsp;</span>
215
225
  <span class="cline-any cline-neutral">&nbsp;</span>
216
226
  <span class="cline-any cline-neutral">&nbsp;</span>
217
- <span class="cline-any cline-yes">48x</span>
218
- <span class="cline-any cline-yes">48x</span>
219
- <span class="cline-any cline-yes">48x</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>
220
230
  <span class="cline-any cline-neutral">&nbsp;</span>
221
- <span class="cline-any cline-yes">48x</span>
231
+ <span class="cline-any cline-yes">59x</span>
222
232
  <span class="cline-any cline-neutral">&nbsp;</span>
223
233
  <span class="cline-any cline-neutral">&nbsp;</span>
224
234
  <span class="cline-any cline-neutral">&nbsp;</span>
225
235
  <span class="cline-any cline-neutral">&nbsp;</span>
226
236
  <span class="cline-any cline-neutral">&nbsp;</span>
227
237
  <span class="cline-any cline-neutral">&nbsp;</span>
228
- <span class="cline-any cline-yes">47x</span>
229
- <span class="cline-any cline-yes">47x</span>
230
- <span class="cline-any cline-yes">47x</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>
231
241
  <span class="cline-any cline-neutral">&nbsp;</span>
232
242
  <span class="cline-any cline-neutral">&nbsp;</span>
233
243
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -236,47 +246,46 @@
236
246
  <span class="cline-any cline-neutral">&nbsp;</span>
237
247
  <span class="cline-any cline-neutral">&nbsp;</span>
238
248
  <span class="cline-any cline-neutral">&nbsp;</span>
239
- <span class="cline-any cline-yes">232x</span>
240
- <span class="cline-any cline-yes">232x</span>
249
+ <span class="cline-any cline-yes">272x</span>
250
+ <span class="cline-any cline-yes">272x</span>
241
251
  <span class="cline-any cline-neutral">&nbsp;</span>
242
- <span class="cline-any cline-yes">232x</span>
243
- <span class="cline-any cline-yes">374x</span>
244
- <span class="cline-any cline-yes">374x</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>
245
255
  <span class="cline-any cline-neutral">&nbsp;</span>
246
256
  <span class="cline-any cline-neutral">&nbsp;</span>
247
- <span class="cline-any cline-yes">374x</span>
248
- <span class="cline-any cline-yes">1133x</span>
249
- <span class="cline-any cline-yes">1133x</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>
250
260
  <span class="cline-any cline-neutral">&nbsp;</span>
251
- <span class="cline-any cline-yes">980x</span>
252
- <span class="cline-any cline-yes">153x</span>
253
- <span class="cline-any cline-yes">8x</span>
254
- <span class="cline-any cline-yes">8x</span>
261
+ <span class="cline-any cline-yes">1008x</span>
262
+ <span class="cline-any cline-yes">154x</span>
263
+ <span class="cline-any cline-yes">9x</span>
264
+ <span class="cline-any cline-yes">9x</span>
255
265
  <span class="cline-any cline-neutral">&nbsp;</span>
256
266
  <span class="cline-any cline-neutral">&nbsp;</span>
257
267
  <span class="cline-any cline-neutral">&nbsp;</span>
258
- <span class="cline-any cline-yes">374x</span>
259
- <span class="cline-any cline-yes">8x</span>
260
- <span class="cline-any cline-yes">8x</span>
261
- <span class="cline-any cline-yes">8x</span>
268
+ <span class="cline-any cline-yes">393x</span>
269
+ <span class="cline-any cline-yes">9x</span>
270
+ <span class="cline-any cline-yes">9x</span>
271
+ <span class="cline-any cline-yes">9x</span>
262
272
  <span class="cline-any cline-neutral">&nbsp;</span>
263
273
  <span class="cline-any cline-neutral">&nbsp;</span>
264
274
  <span class="cline-any cline-neutral">&nbsp;</span>
265
- <span class="cline-any cline-yes">8x</span>
266
- <span class="cline-any cline-yes">8x</span>
267
- <span class="cline-any cline-yes">8x</span>
268
- <span class="cline-any cline-yes">366x</span>
269
- <span class="cline-any cline-yes">119x</span>
270
- <span class="cline-any cline-yes">119x</span>
275
+ <span class="cline-any cline-yes">9x</span>
276
+ <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>
271
280
  <span class="cline-any cline-neutral">&nbsp;</span>
272
281
  <span class="cline-any cline-neutral">&nbsp;</span>
273
282
  <span class="cline-any cline-neutral">&nbsp;</span>
274
283
  <span class="cline-any cline-neutral">&nbsp;</span>
275
- <span class="cline-any cline-yes">232x</span>
276
- <span class="cline-any cline-yes">127x</span>
284
+ <span class="cline-any cline-yes">272x</span>
285
+ <span class="cline-any cline-yes">138x</span>
277
286
  <span class="cline-any cline-neutral">&nbsp;</span>
278
287
  <span class="cline-any cline-neutral">&nbsp;</span>
279
- <span class="cline-any cline-yes">232x</span>
288
+ <span class="cline-any cline-yes">272x</span>
280
289
  <span class="cline-any cline-neutral">&nbsp;</span>
281
290
  <span class="cline-any cline-neutral">&nbsp;</span>
282
291
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -284,8 +293,8 @@
284
293
  <span class="cline-any cline-neutral">&nbsp;</span>
285
294
  <span class="cline-any cline-neutral">&nbsp;</span>
286
295
  <span class="cline-any cline-neutral">&nbsp;</span>
287
- <span class="cline-any cline-yes">119x</span>
288
- <span class="cline-any cline-yes">119x</span>
296
+ <span class="cline-any cline-yes">122x</span>
297
+ <span class="cline-any cline-yes">122x</span>
289
298
  <span class="cline-any cline-neutral">&nbsp;</span>
290
299
  <span class="cline-any cline-neutral">&nbsp;</span>
291
300
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -295,9 +304,9 @@
295
304
  <span class="cline-any cline-neutral">&nbsp;</span>
296
305
  <span class="cline-any cline-neutral">&nbsp;</span>
297
306
  <span class="cline-any cline-neutral">&nbsp;</span>
298
- <span class="cline-any cline-yes">120x</span>
299
- <span class="cline-any cline-yes">120x</span>
300
- <span class="cline-any cline-yes">120x</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>
301
310
  <span class="cline-any cline-neutral">&nbsp;</span>
302
311
  <span class="cline-any cline-neutral">&nbsp;</span>
303
312
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -306,16 +315,16 @@
306
315
  <span class="cline-any cline-neutral">&nbsp;</span>
307
316
  <span class="cline-any cline-neutral">&nbsp;</span>
308
317
  <span class="cline-any cline-neutral">&nbsp;</span>
309
- <span class="cline-any cline-yes">66x</span>
318
+ <span class="cline-any cline-yes">81x</span>
310
319
  <span class="cline-any cline-neutral">&nbsp;</span>
311
320
  <span class="cline-any cline-neutral">&nbsp;</span>
312
321
  <span class="cline-any cline-neutral">&nbsp;</span>
313
- <span class="cline-any cline-yes">4x</span>
314
- <span class="cline-any cline-yes">3x</span>
322
+ <span class="cline-any cline-yes">7x</span>
323
+ <span class="cline-any cline-yes">6x</span>
315
324
  <span class="cline-any cline-neutral">&nbsp;</span>
316
325
  <span class="cline-any cline-neutral">&nbsp;</span>
317
326
  <span class="cline-any cline-neutral">&nbsp;</span>
318
- <span class="cline-any cline-yes">3x</span>
327
+ <span class="cline-any cline-yes">6x</span>
319
328
  <span class="cline-any cline-neutral">&nbsp;</span>
320
329
  <span class="cline-any cline-neutral">&nbsp;</span>
321
330
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -323,28 +332,39 @@
323
332
  <span class="cline-any cline-neutral">&nbsp;</span>
324
333
  <span class="cline-any cline-neutral">&nbsp;</span>
325
334
  <span class="cline-any cline-neutral">&nbsp;</span>
326
- <span class="cline-any cline-yes">66x</span>
335
+ <span class="cline-any cline-yes">81x</span>
327
336
  <span class="cline-any cline-neutral">&nbsp;</span>
328
337
  <span class="cline-any cline-neutral">&nbsp;</span>
329
338
  <span class="cline-any cline-neutral">&nbsp;</span>
330
339
  <span class="cline-any cline-neutral">&nbsp;</span>
331
340
  <span class="cline-any cline-neutral">&nbsp;</span>
332
341
  <span class="cline-any cline-neutral">&nbsp;</span>
333
- <span class="cline-any cline-yes">48x</span>
342
+ <span class="cline-any cline-yes">59x</span>
334
343
  <span class="cline-any cline-neutral">&nbsp;</span>
335
344
  <span class="cline-any cline-neutral">&nbsp;</span>
336
345
  <span class="cline-any cline-neutral">&nbsp;</span>
337
346
  <span class="cline-any cline-neutral">&nbsp;</span>
338
347
  <span class="cline-any cline-neutral">&nbsp;</span>
339
348
  <span class="cline-any cline-neutral">&nbsp;</span>
340
- <span class="cline-any cline-yes">92x</span>
349
+ <span class="cline-any cline-yes">121x</span>
341
350
  <span class="cline-any cline-neutral">&nbsp;</span>
342
351
  <span class="cline-any cline-neutral">&nbsp;</span>
343
352
  <span class="cline-any cline-neutral">&nbsp;</span>
344
353
  <span class="cline-any cline-neutral">&nbsp;</span>
345
354
  <span class="cline-any cline-neutral">&nbsp;</span>
346
355
  <span class="cline-any cline-neutral">&nbsp;</span>
347
- <span class="cline-any cline-yes">122x</span>
356
+ <span class="cline-any cline-yes">154x</span>
357
+ <span class="cline-any cline-neutral">&nbsp;</span>
358
+ <span class="cline-any cline-neutral">&nbsp;</span>
359
+ <span class="cline-any cline-neutral">&nbsp;</span>
360
+ <span class="cline-any cline-neutral">&nbsp;</span>
361
+ <span class="cline-any cline-neutral">&nbsp;</span>
362
+ <span class="cline-any cline-neutral">&nbsp;</span>
363
+ <span class="cline-any cline-neutral">&nbsp;</span>
364
+ <span class="cline-any cline-neutral">&nbsp;</span>
365
+ <span class="cline-any cline-yes">12x</span>
366
+ <span class="cline-any cline-yes">12x</span>
367
+ <span class="cline-any cline-yes">12x</span>
348
368
  <span class="cline-any cline-neutral">&nbsp;</span>
349
369
  <span class="cline-any cline-neutral">&nbsp;</span>
350
370
  <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">import { TaskStep } from "./TaskStep.js";
@@ -404,8 +424,7 @@ export class TaskStateManager&lt;TContext&gt; {
404
424
  status: "skipped",
405
425
  message: `Skipped because dependency '${failedDep}' failed${depError}`,
406
426
  };
407
- this.results.set(step.name, result);
408
- this.eventBus.emit("taskSkipped", { step, result });
427
+ this.markSkipped(step, result);
409
428
  toRemove.push(step);
410
429
  } else if (!blocked) {
411
430
  toRun.push(step);
@@ -488,6 +507,17 @@ export class TaskStateManager&lt;TContext&gt; {
488
507
  hasPendingTasks(): boolean {
489
508
  return this.pendingSteps.size &gt; 0;
490
509
  }
510
+ &nbsp;
511
+ /**
512
+ * Marks a task as skipped and emits `taskSkipped`.
513
+ * @param step The task that was skipped.
514
+ * @param result The result object (status: skipped).
515
+ */
516
+ markSkipped(step: TaskStep&lt;TContext&gt;, result: TaskResult): void {
517
+ this.running.delete(step.name);
518
+ this.results.set(step.name, result);
519
+ this.eventBus.emit("taskSkipped", { step, result });
520
+ }
491
521
  }
492
522
  &nbsp;</pre></td></tr></table></pre>
493
523
 
@@ -496,7 +526,7 @@ export class TaskStateManager&lt;TContext&gt; {
496
526
  <div class='footer quiet pad2 space-top1 center small'>
497
527
  Code coverage generated by
498
528
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
499
- at 2026-01-18T20:19:46.886Z
529
+ at 2026-01-18T23:00:28.573Z
500
530
  </div>
501
531
  <script src="../prettify.js"></script>
502
532
  <script>