@calmo/task-runner 1.2.2 → 2.0.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 (44) hide show
  1. package/.gemini/commands/openspec/apply.toml +21 -0
  2. package/.gemini/commands/openspec/archive.toml +25 -0
  3. package/.gemini/commands/openspec/proposal.toml +26 -0
  4. package/.jules/sentinel.md +4 -0
  5. package/AGENTS.md +21 -0
  6. package/CHANGELOG.md +21 -0
  7. package/GEMINI.md +10 -0
  8. package/coverage/coverage-final.json +4 -4
  9. package/coverage/index.html +9 -9
  10. package/coverage/lcov-report/index.html +9 -9
  11. package/coverage/lcov-report/src/EventBus.ts.html +4 -4
  12. package/coverage/lcov-report/src/TaskGraphValidator.ts.html +165 -54
  13. package/coverage/lcov-report/src/TaskRunner.ts.html +7 -109
  14. package/coverage/lcov-report/src/WorkflowExecutor.ts.html +169 -106
  15. package/coverage/lcov-report/src/contracts/RunnerEvents.ts.html +1 -1
  16. package/coverage/lcov-report/src/contracts/index.html +1 -1
  17. package/coverage/lcov-report/src/index.html +13 -13
  18. package/coverage/lcov.info +165 -167
  19. package/coverage/src/EventBus.ts.html +4 -4
  20. package/coverage/src/TaskGraphValidator.ts.html +165 -54
  21. package/coverage/src/TaskRunner.ts.html +7 -109
  22. package/coverage/src/WorkflowExecutor.ts.html +169 -106
  23. package/coverage/src/contracts/RunnerEvents.ts.html +1 -1
  24. package/coverage/src/contracts/index.html +1 -1
  25. package/coverage/src/index.html +13 -13
  26. package/dist/TaskGraphValidator.d.ts +6 -0
  27. package/dist/TaskGraphValidator.js +48 -16
  28. package/dist/TaskGraphValidator.js.map +1 -1
  29. package/dist/TaskRunner.js +1 -32
  30. package/dist/TaskRunner.js.map +1 -1
  31. package/dist/WorkflowExecutor.d.ts +16 -0
  32. package/dist/WorkflowExecutor.js +67 -54
  33. package/dist/WorkflowExecutor.js.map +1 -1
  34. package/dist/contracts/ITaskGraphValidator.d.ts +6 -0
  35. package/openspec/AGENTS.md +456 -0
  36. package/openspec/changes/add-external-task-cancellation/proposal.md +14 -0
  37. package/openspec/changes/add-external-task-cancellation/tasks.md +10 -0
  38. package/openspec/project.md +31 -0
  39. package/package.json +1 -1
  40. package/src/TaskGraphValidator.ts +56 -19
  41. package/src/TaskRunner.ts +1 -35
  42. package/src/WorkflowExecutor.ts +84 -63
  43. package/src/contracts/ITaskGraphValidator.ts +7 -0
  44. package/test-report.xml +51 -39
@@ -39,7 +39,7 @@
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'>11/11</span>
43
43
  </div>
44
44
 
45
45
 
@@ -168,7 +168,28 @@
168
168
  <a name='L103'></a><a href='#L103'>103</a>
169
169
  <a name='L104'></a><a href='#L104'>104</a>
170
170
  <a name='L105'></a><a href='#L105'>105</a>
171
- <a name='L106'></a><a href='#L106'>106</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
171
+ <a name='L106'></a><a href='#L106'>106</a>
172
+ <a name='L107'></a><a href='#L107'>107</a>
173
+ <a name='L108'></a><a href='#L108'>108</a>
174
+ <a name='L109'></a><a href='#L109'>109</a>
175
+ <a name='L110'></a><a href='#L110'>110</a>
176
+ <a name='L111'></a><a href='#L111'>111</a>
177
+ <a name='L112'></a><a href='#L112'>112</a>
178
+ <a name='L113'></a><a href='#L113'>113</a>
179
+ <a name='L114'></a><a href='#L114'>114</a>
180
+ <a name='L115'></a><a href='#L115'>115</a>
181
+ <a name='L116'></a><a href='#L116'>116</a>
182
+ <a name='L117'></a><a href='#L117'>117</a>
183
+ <a name='L118'></a><a href='#L118'>118</a>
184
+ <a name='L119'></a><a href='#L119'>119</a>
185
+ <a name='L120'></a><a href='#L120'>120</a>
186
+ <a name='L121'></a><a href='#L121'>121</a>
187
+ <a name='L122'></a><a href='#L122'>122</a>
188
+ <a name='L123'></a><a href='#L123'>123</a>
189
+ <a name='L124'></a><a href='#L124'>124</a>
190
+ <a name='L125'></a><a href='#L125'>125</a>
191
+ <a name='L126'></a><a href='#L126'>126</a>
192
+ <a name='L127'></a><a href='#L127'>127</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
172
193
  <span class="cline-any cline-neutral">&nbsp;</span>
173
194
  <span class="cline-any cline-neutral">&nbsp;</span>
174
195
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -177,15 +198,15 @@
177
198
  <span class="cline-any cline-neutral">&nbsp;</span>
178
199
  <span class="cline-any cline-neutral">&nbsp;</span>
179
200
  <span class="cline-any cline-neutral">&nbsp;</span>
180
- <span class="cline-any cline-yes">15x</span>
201
+ <span class="cline-any cline-yes">18x</span>
181
202
  <span class="cline-any cline-neutral">&nbsp;</span>
182
203
  <span class="cline-any cline-neutral">&nbsp;</span>
183
204
  <span class="cline-any cline-neutral">&nbsp;</span>
184
205
  <span class="cline-any cline-neutral">&nbsp;</span>
185
206
  <span class="cline-any cline-neutral">&nbsp;</span>
186
207
  <span class="cline-any cline-neutral">&nbsp;</span>
187
- <span class="cline-any cline-yes">15x</span>
188
- <span class="cline-any cline-yes">15x</span>
208
+ <span class="cline-any cline-yes">18x</span>
209
+ <span class="cline-any cline-yes">18x</span>
189
210
  <span class="cline-any cline-neutral">&nbsp;</span>
190
211
  <span class="cline-any cline-neutral">&nbsp;</span>
191
212
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -194,83 +215,104 @@
194
215
  <span class="cline-any cline-neutral">&nbsp;</span>
195
216
  <span class="cline-any cline-neutral">&nbsp;</span>
196
217
  <span class="cline-any cline-neutral">&nbsp;</span>
197
- <span class="cline-any cline-yes">15x</span>
218
+ <span class="cline-any cline-yes">18x</span>
198
219
  <span class="cline-any cline-neutral">&nbsp;</span>
199
- <span class="cline-any cline-yes">15x</span>
200
- <span class="cline-any cline-yes">15x</span>
220
+ <span class="cline-any cline-yes">18x</span>
221
+ <span class="cline-any cline-yes">18x</span>
201
222
  <span class="cline-any cline-neutral">&nbsp;</span>
202
223
  <span class="cline-any cline-neutral">&nbsp;</span>
203
- <span class="cline-any cline-yes">15x</span>
204
- <span class="cline-any cline-yes">35x</span>
205
- <span class="cline-any cline-yes">98x</span>
224
+ <span class="cline-any cline-yes">18x</span>
206
225
  <span class="cline-any cline-neutral">&nbsp;</span>
226
+ <span class="cline-any cline-yes">18x</span>
227
+ <span class="cline-any cline-neutral">&nbsp;</span>
228
+ <span class="cline-any cline-yes">25x</span>
229
+ <span class="cline-any cline-neutral">&nbsp;</span>
230
+ <span class="cline-any cline-yes">25x</span>
231
+ <span class="cline-any cline-neutral">&nbsp;</span>
232
+ <span class="cline-any cline-neutral">&nbsp;</span>
233
+ <span class="cline-any cline-yes">18x</span>
234
+ <span class="cline-any cline-yes">18x</span>
207
235
  <span class="cline-any cline-neutral">&nbsp;</span>
208
236
  <span class="cline-any cline-neutral">&nbsp;</span>
209
- <span class="cline-any cline-yes">35x</span>
210
- <span class="cline-any cline-yes">49x</span>
211
- <span class="cline-any cline-yes">49x</span>
212
- <span class="cline-any cline-yes">39x</span>
213
237
  <span class="cline-any cline-neutral">&nbsp;</span>
214
- <span class="cline-any cline-yes">49x</span>
215
- <span class="cline-any cline-yes">6x</span>
216
238
  <span class="cline-any cline-neutral">&nbsp;</span>
217
239
  <span class="cline-any cline-neutral">&nbsp;</span>
218
240
  <span class="cline-any cline-neutral">&nbsp;</span>
219
- <span class="cline-any cline-yes">6x</span>
220
- <span class="cline-any cline-yes">6x</span>
221
241
  <span class="cline-any cline-neutral">&nbsp;</span>
222
242
  <span class="cline-any cline-neutral">&nbsp;</span>
223
243
  <span class="cline-any cline-neutral">&nbsp;</span>
224
244
  <span class="cline-any cline-neutral">&nbsp;</span>
225
- <span class="cline-any cline-yes">35x</span>
226
- <span class="cline-any cline-yes">98x</span>
227
245
  <span class="cline-any cline-yes">43x</span>
228
- <span class="cline-any cline-yes">98x</span>
229
- <span class="cline-any cline-yes">29x</span>
230
246
  <span class="cline-any cline-neutral">&nbsp;</span>
247
+ <span class="cline-any cline-yes">43x</span>
248
+ <span class="cline-any cline-neutral">&nbsp;</span>
249
+ <span class="cline-any cline-yes">43x</span>
250
+ <span class="cline-any cline-yes">31x</span>
251
+ <span class="cline-any cline-yes">31x</span>
231
252
  <span class="cline-any cline-neutral">&nbsp;</span>
253
+ <span class="cline-any cline-yes">31x</span>
232
254
  <span class="cline-any cline-neutral">&nbsp;</span>
233
255
  <span class="cline-any cline-neutral">&nbsp;</span>
234
- <span class="cline-any cline-yes">35x</span>
235
- <span class="cline-any cline-yes">26x</span>
236
- <span class="cline-any cline-yes">26x</span>
237
256
  <span class="cline-any cline-neutral">&nbsp;</span>
238
- <span class="cline-any cline-yes">26x</span>
239
- <span class="cline-any cline-yes">26x</span>
240
- <span class="cline-any cline-yes">26x</span>
241
- <span class="cline-any cline-yes">24x</span>
242
257
  <span class="cline-any cline-neutral">&nbsp;</span>
243
- <span class="cline-any cline-yes">2x</span>
244
258
  <span class="cline-any cline-neutral">&nbsp;</span>
245
259
  <span class="cline-any cline-neutral">&nbsp;</span>
246
260
  <span class="cline-any cline-neutral">&nbsp;</span>
261
+ <span class="cline-any cline-yes">43x</span>
262
+ <span class="cline-any cline-yes">114x</span>
263
+ <span class="cline-any cline-neutral">&nbsp;</span>
264
+ <span class="cline-any cline-neutral">&nbsp;</span>
265
+ <span class="cline-any cline-yes">43x</span>
266
+ <span class="cline-any cline-yes">57x</span>
267
+ <span class="cline-any cline-yes">57x</span>
268
+ <span class="cline-any cline-yes">43x</span>
247
269
  <span class="cline-any cline-neutral">&nbsp;</span>
248
- <span class="cline-any cline-yes">26x</span>
249
- <span class="cline-any cline-yes">26x</span>
250
- <span class="cline-any cline-yes">26x</span>
251
270
  <span class="cline-any cline-neutral">&nbsp;</span>
271
+ <span class="cline-any cline-yes">57x</span>
272
+ <span class="cline-any cline-yes">7x</span>
252
273
  <span class="cline-any cline-neutral">&nbsp;</span>
253
274
  <span class="cline-any cline-neutral">&nbsp;</span>
254
275
  <span class="cline-any cline-neutral">&nbsp;</span>
255
- <span class="cline-any cline-yes">26x</span>
256
- <span class="cline-any cline-yes">26x</span>
276
+ <span class="cline-any cline-yes">7x</span>
277
+ <span class="cline-any cline-yes">7x</span>
257
278
  <span class="cline-any cline-neutral">&nbsp;</span>
258
- <span class="cline-any cline-yes">26x</span>
259
279
  <span class="cline-any cline-neutral">&nbsp;</span>
260
280
  <span class="cline-any cline-neutral">&nbsp;</span>
261
281
  <span class="cline-any cline-neutral">&nbsp;</span>
262
282
  <span class="cline-any cline-neutral">&nbsp;</span>
263
- <span class="cline-any cline-yes">15x</span>
264
283
  <span class="cline-any cline-neutral">&nbsp;</span>
265
- <span class="cline-any cline-yes">15x</span>
266
284
  <span class="cline-any cline-neutral">&nbsp;</span>
267
- <span class="cline-any cline-yes">20x</span>
268
285
  <span class="cline-any cline-neutral">&nbsp;</span>
269
- <span class="cline-any cline-yes">20x</span>
286
+ <span class="cline-any cline-yes">43x</span>
287
+ <span class="cline-any cline-yes">114x</span>
288
+ <span class="cline-any cline-neutral">&nbsp;</span>
289
+ <span class="cline-any cline-yes">50x</span>
290
+ <span class="cline-any cline-yes">114x</span>
291
+ <span class="cline-any cline-yes">32x</span>
292
+ <span class="cline-any cline-neutral">&nbsp;</span>
293
+ <span class="cline-any cline-neutral">&nbsp;</span>
270
294
  <span class="cline-any cline-neutral">&nbsp;</span>
271
295
  <span class="cline-any cline-neutral">&nbsp;</span>
272
- <span class="cline-any cline-yes">15x</span>
273
- <span class="cline-any cline-yes">15x</span>
296
+ <span class="cline-any cline-neutral">&nbsp;</span>
297
+ <span class="cline-any cline-neutral">&nbsp;</span>
298
+ <span class="cline-any cline-neutral">&nbsp;</span>
299
+ <span class="cline-any cline-neutral">&nbsp;</span>
300
+ <span class="cline-any cline-yes">31x</span>
301
+ <span class="cline-any cline-yes">31x</span>
302
+ <span class="cline-any cline-neutral">&nbsp;</span>
303
+ <span class="cline-any cline-yes">31x</span>
304
+ <span class="cline-any cline-yes">31x</span>
305
+ <span class="cline-any cline-yes">29x</span>
306
+ <span class="cline-any cline-neutral">&nbsp;</span>
307
+ <span class="cline-any cline-yes">2x</span>
308
+ <span class="cline-any cline-neutral">&nbsp;</span>
309
+ <span class="cline-any cline-neutral">&nbsp;</span>
310
+ <span class="cline-any cline-neutral">&nbsp;</span>
311
+ <span class="cline-any cline-neutral">&nbsp;</span>
312
+ <span class="cline-any cline-yes">31x</span>
313
+ <span class="cline-any cline-yes">31x</span>
314
+ <span class="cline-any cline-yes">31x</span>
315
+ <span class="cline-any cline-neutral">&nbsp;</span>
274
316
  <span class="cline-any cline-neutral">&nbsp;</span>
275
317
  <span class="cline-any cline-neutral">&nbsp;</span>
276
318
  <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">import { TaskStep } from "./TaskStep.js";
@@ -304,78 +346,99 @@ export class WorkflowExecutor&lt;TContext&gt; {
304
346
  const results = new Map&lt;string, TaskResult&gt;();
305
347
  const executingPromises = new Set&lt;Promise&lt;void&gt;&gt;();
306
348
  &nbsp;
307
- // Helper to process pending steps and launch ready ones
308
- const processPendingSteps = () =&gt; {
309
- const pendingSteps = steps.filter(
310
- (step) =&gt; !results.has(step.name) &amp;&amp; !this.running.has(step.name)
311
- );
349
+ // Initial pass
350
+ this.processQueue(steps, results, executingPromises);
312
351
  &nbsp;
313
- // 1. Identify and mark skipped tasks
314
- for (const step of pendingSteps) {
315
- const deps = step.dependencies ?? [];
316
- const failedDep = deps.find(
317
- (dep) =&gt; results.has(dep) &amp;&amp; results.get(dep)?.status !== "success"
318
- );
319
- if (failedDep) {
320
- const result: TaskResult = {
321
- status: "skipped",
322
- message: `Skipped due to failed dependency: ${failedDep}`,
323
- };
324
- results.set(step.name, result);
325
- this.eventBus.emit("taskSkipped", { step, result });
326
- }
327
- }
352
+ while (results.size &lt; steps.length &amp;&amp; executingPromises.size &gt; 0) {
353
+ // Wait for the next task to finish
354
+ await Promise.race(executingPromises);
355
+ // After a task finishes, check for new work
356
+ this.processQueue(steps, results, executingPromises);
357
+ }
358
+ &nbsp;
359
+ this.eventBus.emit("workflowEnd", { context: this.context, results });
360
+ return results;
361
+ }
362
+ &nbsp;
363
+ /**
364
+ * Logic to identify tasks that can be started or must be skipped.
365
+ */
366
+ private processQueue(
367
+ steps: TaskStep&lt;TContext&gt;[],
368
+ results: Map&lt;string, TaskResult&gt;,
369
+ executingPromises: Set&lt;Promise&lt;void&gt;&gt;
370
+ ): void {
371
+ this.handleSkippedTasks(steps, results);
372
+ &nbsp;
373
+ const readySteps = this.getReadySteps(steps, results);
328
374
  &nbsp;
329
- // Re-filter pending steps as some might have been skipped above
330
- const readySteps = steps.filter((step) =&gt; {
331
- if (results.has(step.name) || this.running.has(step.name)) return false;
332
- const deps = step.dependencies ?? [];
333
- return deps.every(
334
- (dep) =&gt; results.has(dep) &amp;&amp; results.get(dep)?.status === "success"
335
- );
375
+ for (const step of readySteps) {
376
+ const taskPromise = this.runStep(step, results).then(() =&gt; {
377
+ executingPromises.delete(taskPromise);
336
378
  });
379
+ executingPromises.add(taskPromise);
380
+ }
381
+ }
337
382
  &nbsp;
338
- // 2. Launch ready tasks
339
- for (const step of readySteps) {
340
- this.running.add(step.name);
341
- this.eventBus.emit("taskStart", { step });
383
+ /**
384
+ * Identifies steps that cannot run because a dependency failed.
385
+ */
386
+ private handleSkippedTasks(steps: TaskStep&lt;TContext&gt;[], results: Map&lt;string, TaskResult&gt;): void {
387
+ const pendingSteps = steps.filter(
388
+ (step) =&gt; !results.has(step.name) &amp;&amp; !this.running.has(step.name)
389
+ );
342
390
  &nbsp;
343
- const taskPromise = (async () =&gt; {
344
- try {
345
- const result = await step.run(this.context);
346
- results.set(step.name, result);
347
- } catch (e) {
348
- results.set(step.name, {
349
- status: "failure",
350
- error: e instanceof Error ? e.message : String(e),
351
- });
352
- } finally {
353
- this.running.delete(step.name);
354
- const result = results.get(step.name)!;
355
- this.eventBus.emit("taskEnd", { step, result });
356
- }
357
- })();
391
+ for (const step of pendingSteps) {
392
+ const deps = step.dependencies ?? [];
393
+ const failedDep = deps.find(
394
+ (dep) =&gt; results.has(dep) &amp;&amp; results.get(dep)?.status !== "success"
395
+ );
358
396
  &nbsp;
359
- // Wrap the task promise to ensure we can track it in the Set
360
- const trackedPromise = taskPromise.then(() =&gt; {
361
- executingPromises.delete(trackedPromise);
362
- });
363
- executingPromises.add(trackedPromise);
397
+ if (failedDep) {
398
+ const result: TaskResult = {
399
+ status: "skipped",
400
+ message: `Skipped due to failed dependency: ${failedDep}`,
401
+ };
402
+ results.set(step.name, result);
403
+ this.eventBus.emit("taskSkipped", { step, result });
364
404
  }
365
- };
405
+ }
406
+ }
366
407
  &nbsp;
367
- // Initial check to start independent tasks
368
- processPendingSteps();
408
+ /**
409
+ * Returns steps where all dependencies have finished successfully.
410
+ */
411
+ private getReadySteps(steps: TaskStep&lt;TContext&gt;[], results: Map&lt;string, TaskResult&gt;): TaskStep&lt;TContext&gt;[] {
412
+ return steps.filter((step) =&gt; {
413
+ if (results.has(step.name) || this.running.has(step.name)) return false;
369
414
  &nbsp;
370
- while (results.size &lt; steps.length &amp;&amp; executingPromises.size &gt; 0) {
371
- // Wait for the next task to finish
372
- await Promise.race(executingPromises);
373
- // After a task finishes, check for new work
374
- processPendingSteps();
375
- }
415
+ const deps = step.dependencies ?? [];
416
+ return deps.every(
417
+ (dep) =&gt; results.has(dep) &amp;&amp; results.get(dep)?.status === "success"
418
+ );
419
+ });
420
+ }
376
421
  &nbsp;
377
- this.eventBus.emit("workflowEnd", { context: this.context, results });
378
- return results;
422
+ /**
423
+ * Handles the lifecycle of a single task execution.
424
+ */
425
+ private async runStep(step: TaskStep&lt;TContext&gt;, results: Map&lt;string, TaskResult&gt;): Promise&lt;void&gt; {
426
+ this.running.add(step.name);
427
+ this.eventBus.emit("taskStart", { step });
428
+ &nbsp;
429
+ try {
430
+ const result = await step.run(this.context);
431
+ results.set(step.name, result);
432
+ } catch (e) {
433
+ results.set(step.name, {
434
+ status: "failure",
435
+ error: e instanceof Error ? e.message : String(e),
436
+ });
437
+ } finally {
438
+ this.running.delete(step.name);
439
+ const result = results.get(step.name)!;
440
+ this.eventBus.emit("taskEnd", { step, result });
441
+ }
379
442
  }
380
443
  }
381
444
  &nbsp;</pre></td></tr></table></pre>
@@ -385,7 +448,7 @@ export class WorkflowExecutor&lt;TContext&gt; {
385
448
  <div class='footer quiet pad2 space-top1 center small'>
386
449
  Code coverage generated by
387
450
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
388
- at 2026-01-18T05:44:30.766Z
451
+ at 2026-01-18T15:13:46.748Z
389
452
  </div>
390
453
  <script src="../prettify.js"></script>
391
454
  <script>
@@ -202,7 +202,7 @@ export type ListenerMap&lt;TContext&gt; = {
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-18T05:44:30.766Z
205
+ at 2026-01-18T15:13:46.748Z
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-18T05:44:30.766Z
104
+ at 2026-01-18T15:13:46.748Z
105
105
  </div>
106
106
  <script src="../../prettify.js"></script>
107
107
  <script>
@@ -25,28 +25,28 @@
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'>131/131</span>
28
+ <span class='fraction'>126/126</span>
29
29
  </div>
30
30
 
31
31
 
32
32
  <div class='fl pad1y space-right2'>
33
33
  <span class="strong">100% </span>
34
34
  <span class="quiet">Branches</span>
35
- <span class='fraction'>51/51</span>
35
+ <span class='fraction'>48/48</span>
36
36
  </div>
37
37
 
38
38
 
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'>22/22</span>
42
+ <span class='fraction'>25/25</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'>128/128</span>
49
+ <span class='fraction'>123/123</span>
50
50
  </div>
51
51
 
52
52
 
@@ -99,13 +99,13 @@
99
99
  <div class="chart"><div class="cover-fill cover-full" style="width: 100%"></div><div class="cover-empty" style="width: 0%"></div></div>
100
100
  </td>
101
101
  <td data-value="100" class="pct high">100%</td>
102
- <td data-value="43" class="abs high">43/43</td>
102
+ <td data-value="56" class="abs high">56/56</td>
103
103
  <td data-value="100" class="pct high">100%</td>
104
104
  <td data-value="16" class="abs high">16/16</td>
105
105
  <td data-value="100" class="pct high">100%</td>
106
- <td data-value="3" class="abs high">3/3</td>
106
+ <td data-value="5" class="abs high">5/5</td>
107
107
  <td data-value="100" class="pct high">100%</td>
108
- <td data-value="42" class="abs high">42/42</td>
108
+ <td data-value="54" class="abs high">54/54</td>
109
109
  </tr>
110
110
 
111
111
  <tr>
@@ -114,13 +114,13 @@
114
114
  <div class="chart"><div class="cover-fill cover-full" style="width: 100%"></div><div class="cover-empty" style="width: 0%"></div></div>
115
115
  </td>
116
116
  <td data-value="100" class="pct high">100%</td>
117
- <td data-value="30" class="abs high">30/30</td>
117
+ <td data-value="12" class="abs high">12/12</td>
118
118
  <td data-value="100" class="pct high">100%</td>
119
- <td data-value="7" class="abs high">7/7</td>
119
+ <td data-value="4" class="abs high">4/4</td>
120
120
  <td data-value="100" class="pct high">100%</td>
121
- <td data-value="6" class="abs high">6/6</td>
121
+ <td data-value="5" class="abs high">5/5</td>
122
122
  <td data-value="100" class="pct high">100%</td>
123
- <td data-value="29" class="abs high">29/29</td>
123
+ <td data-value="12" class="abs high">12/12</td>
124
124
  </tr>
125
125
 
126
126
  <tr>
@@ -133,7 +133,7 @@
133
133
  <td data-value="100" class="pct high">100%</td>
134
134
  <td data-value="20" class="abs high">20/20</td>
135
135
  <td data-value="100" class="pct high">100%</td>
136
- <td data-value="9" class="abs high">9/9</td>
136
+ <td data-value="11" class="abs high">11/11</td>
137
137
  <td data-value="100" class="pct high">100%</td>
138
138
  <td data-value="42" class="abs high">42/42</td>
139
139
  </tr>
@@ -146,7 +146,7 @@
146
146
  <div class='footer quiet pad2 space-top1 center small'>
147
147
  Code coverage generated by
148
148
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
149
- at 2026-01-18T05:44:30.766Z
149
+ at 2026-01-18T15:13:46.748Z
150
150
  </div>
151
151
  <script src="../prettify.js"></script>
152
152
  <script>