Update coverage reports and fix Ollama client abort handling

This commit is contained in:
2026-05-06 23:44:29 +02:00
parent 0920e0959e
commit cec8302dbe
15 changed files with 1945 additions and 1469 deletions
+181 -181
View File
@@ -23,16 +23,16 @@
<div class='clearfix'>
<div class='fl pad1y space-right2'>
<span class="strong">90.36% </span>
<span class="strong">92.55% </span>
<span class="quiet">Statements</span>
<span class='fraction'>197/218</span>
<span class='fraction'>199/215</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">80.28% </span>
<span class="strong">85.71% </span>
<span class="quiet">Branches</span>
<span class='fraction'>57/71</span>
<span class='fraction'>60/70</span>
</div>
@@ -44,9 +44,9 @@
<div class='fl pad1y space-right2'>
<span class="strong">92.15% </span>
<span class="strong">94.52% </span>
<span class="quiet">Lines</span>
<span class='fraction'>188/204</span>
<span class='fraction'>190/201</span>
</div>
@@ -565,22 +565,22 @@
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">31x</span>
<span class="cline-any cline-yes">36x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">31x</span>
<span class="cline-any cline-yes">31x</span>
<span class="cline-any cline-yes">31x</span>
<span class="cline-any cline-yes">31x</span>
<span class="cline-any cline-yes">31x</span>
<span class="cline-any cline-yes">31x</span>
<span class="cline-any cline-yes">31x</span>
<span class="cline-any cline-yes">31x</span>
<span class="cline-any cline-yes">31x</span>
<span class="cline-any cline-yes">31x</span>
<span class="cline-any cline-yes">31x</span>
<span class="cline-any cline-yes">31x</span>
<span class="cline-any cline-yes">36x</span>
<span class="cline-any cline-yes">36x</span>
<span class="cline-any cline-yes">36x</span>
<span class="cline-any cline-yes">36x</span>
<span class="cline-any cline-yes">36x</span>
<span class="cline-any cline-yes">36x</span>
<span class="cline-any cline-yes">36x</span>
<span class="cline-any cline-yes">36x</span>
<span class="cline-any cline-yes">36x</span>
<span class="cline-any cline-yes">36x</span>
<span class="cline-any cline-yes">36x</span>
<span class="cline-any cline-yes">36x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
@@ -596,11 +596,11 @@
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">31x</span>
<span class="cline-any cline-yes">31x</span>
<span class="cline-any cline-yes">31x</span>
<span class="cline-any cline-yes">31x</span>
<span class="cline-any cline-yes">31x</span>
<span class="cline-any cline-yes">36x</span>
<span class="cline-any cline-yes">36x</span>
<span class="cline-any cline-yes">36x</span>
<span class="cline-any cline-yes">36x</span>
<span class="cline-any cline-yes">36x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
@@ -640,8 +640,8 @@
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">136x</span>
<span class="cline-any cline-yes">23x</span>
<span class="cline-any cline-yes">146x</span>
<span class="cline-any cline-yes">28x</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
@@ -649,71 +649,71 @@
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">33x</span>
<span class="cline-any cline-yes">33x</span>
<span class="cline-any cline-yes">43x</span>
<span class="cline-any cline-yes">43x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">33x</span>
<span class="cline-any cline-yes">43x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">33x</span>
<span class="cline-any cline-yes">43x</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">33x</span>
<span class="cline-any cline-yes">43x</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">33x</span>
<span class="cline-any cline-yes">43x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">22x</span>
<span class="cline-any cline-yes">27x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">22x</span>
<span class="cline-any cline-yes">27x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">22x</span>
<span class="cline-any cline-yes">22x</span>
<span class="cline-any cline-yes">27x</span>
<span class="cline-any cline-yes">27x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">33x</span>
<span class="cline-any cline-yes">43x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">282x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">43x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">43x</span>
<span class="cline-any cline-yes">262x</span>
<span class="cline-any cline-yes">262x</span>
<span class="cline-any cline-yes">109x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">153x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">33x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">33x</span>
<span class="cline-any cline-yes">247x</span>
<span class="cline-any cline-yes">247x</span>
<span class="cline-any cline-yes">104x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">143x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">143x</span>
<span class="cline-any cline-yes">143x</span>
<span class="cline-any cline-yes">153x</span>
<span class="cline-any cline-yes">153x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">33x</span>
<span class="cline-any cline-yes">128x</span>
<span class="cline-any cline-yes">3656x</span>
<span class="cline-any cline-yes">43x</span>
<span class="cline-any cline-yes">133x</span>
<span class="cline-any cline-yes">3661x</span>
<span class="cline-any cline-yes">24x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">262x</span>
<span class="cline-any cline-yes">33x</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-yes">282x</span>
<span class="cline-any cline-yes">43x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
@@ -787,59 +787,61 @@
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">138x</span>
<span class="cline-any cline-yes">9x</span>
<span class="cline-any cline-yes">9x</span>
<span class="cline-any cline-yes">292x</span>
<span class="cline-any cline-yes">26x</span>
<span class="cline-any cline-yes">26x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">9x</span>
<span class="cline-any cline-yes">26x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">146x</span>
<span class="cline-any cline-yes">13x</span>
<span class="cline-any cline-yes">8x</span>
<span class="cline-any cline-yes">158x</span>
<span class="cline-any cline-yes">19x</span>
<span class="cline-any cline-yes">12x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">8x</span>
<span class="cline-any cline-yes">12x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">13x</span>
<span class="cline-any cline-yes">13x</span>
<span class="cline-any cline-yes">19x</span>
<span class="cline-any cline-yes">19x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">16x</span>
<span class="cline-any cline-yes">16x</span>
<span class="cline-any cline-yes">21x</span>
<span class="cline-any cline-yes">21x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">16x</span>
<span class="cline-any cline-yes">21x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">16x</span>
<span class="cline-any cline-yes">16x</span>
<span class="cline-any cline-yes">21x</span>
<span class="cline-any cline-yes">21x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">14x</span>
<span class="cline-any cline-yes">14x</span>
<span class="cline-any cline-yes">19x</span>
<span class="cline-any cline-yes">19x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">14x</span>
<span class="cline-any cline-yes">14x</span>
<span class="cline-any cline-yes">19x</span>
<span class="cline-any cline-yes">19x</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">14x</span>
<span class="cline-any cline-yes">19x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">19x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">14x</span>
<span class="cline-any cline-yes">14x</span>
<span class="cline-any cline-yes">19x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">14x</span>
<span class="cline-any cline-yes">19x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
@@ -852,7 +854,7 @@
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">14x</span>
<span class="cline-any cline-yes">19x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
@@ -873,20 +875,20 @@
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">14x</span>
<span class="cline-any cline-yes">19x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">14x</span>
<span class="cline-any cline-yes">14x</span>
<span class="cline-any cline-yes">19x</span>
<span class="cline-any cline-yes">19x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">14x</span>
<span class="cline-any cline-yes">19x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">14x</span>
<span class="cline-any cline-yes">19x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
@@ -895,109 +897,107 @@
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">14x</span>
<span class="cline-any cline-yes">19x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">14x</span>
<span class="cline-any cline-yes">14x</span>
<span class="cline-any cline-yes">19x</span>
<span class="cline-any cline-yes">19x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">14x</span>
<span class="cline-any cline-yes">14x</span>
<span class="cline-any cline-yes">14x</span>
<span class="cline-any cline-yes">14x</span>
<span class="cline-any cline-yes">14x</span>
<span class="cline-any cline-yes">12x</span>
<span class="cline-any cline-yes">12x</span>
<span class="cline-any cline-yes">19x</span>
<span class="cline-any cline-yes">19x</span>
<span class="cline-any cline-yes">19x</span>
<span class="cline-any cline-yes">19x</span>
<span class="cline-any cline-yes">19x</span>
<span class="cline-any cline-yes">17x</span>
<span class="cline-any cline-yes">17x</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">12x</span>
<span class="cline-any cline-yes">12x</span>
<span class="cline-any cline-yes">17x</span>
<span class="cline-any cline-yes">17x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">12x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-yes">17x</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">12x</span>
<span class="cline-any cline-yes">17x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">8x</span>
<span class="cline-any cline-yes">13x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">8x</span>
<span class="cline-any cline-yes">13x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-yes">6x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">8x</span>
<span class="cline-any cline-yes">7x</span>
<span class="cline-any cline-yes">7x</span>
<span class="cline-any cline-yes">7x</span>
<span class="cline-any cline-yes">7x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">8x</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-yes">6x</span>
<span class="cline-any cline-yes">2x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">8x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">14x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">2x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">2x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">2x</span>
<span class="cline-any cline-yes">2x</span>
<span class="cline-any cline-yes">2x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">2x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">2x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">13x</span>
<span class="cline-any cline-yes">9x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">13x</span>
<span class="cline-any cline-yes">2x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">13x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">19x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
@@ -1011,8 +1011,8 @@
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">6x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">16x</span>
<span class="cline-any cline-yes">16x</span>
<span class="cline-any cline-yes">21x</span>
<span class="cline-any cline-yes">21x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
@@ -1185,12 +1185,12 @@ export class ChatView extends ItemView {
&nbsp;
// Re-attach streaming message if it exists
const streamingMessage = messagesSnapshot.find((msg) =&gt; msg.isStreaming);
<span class="missing-if-branch" title="if path not taken" >I</span>if (streamingMessage &amp;&amp; this.lastMessageEl) {
const existingStreamingEl = <span class="cstat-no" title="statement not covered" >container.querySelector(</span>
if (streamingMessage &amp;&amp; this.lastMessageEl) {
const existingStreamingEl = container.querySelector(
`.ollama-message[data-msg-id="${streamingMessage.id}"]`
);
<span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (!existingStreamingEl) {</span>
<span class="cstat-no" title="statement not covered" > container.appendChild(this.lastMessageEl);</span>
if (!existingStreamingEl) {
container.appendChild(this.lastMessageEl);
}
}
}
@@ -1306,14 +1306,16 @@ export class ChatView extends ItemView {
<span class="cstat-no" title="statement not covered" > context = context.substring(0, MAX_CONTEXT_LENGTH) + '\n\n... (truncated)';</span>
}
&nbsp;
const systemContent = context
? <span class="branch-0 cbranch-no" title="branch not covered" >`You are a helpful assistant.\n\nRelevant vault context:\n${context}`</span>
: 'You are a helpful assistant.';
const systemMessage: OllamaMessage = {
role: 'system',
content: 'You are a helpful assistant.',
content: systemContent,
};
const userContent = context ? <span class="branch-0 cbranch-no" title="branch not covered" >`${context}\n\n${userMessage}` </span>: userMessage;
const userMessageWithContext: OllamaMessage = {
role: 'user',
content: userContent,
content: userMessage,
};
&nbsp;
const messages: OllamaMessage[] = [
@@ -1421,9 +1423,9 @@ export class ChatView extends ItemView {
for (const result of settledResults) {
if (result.status === 'fulfilled') {
toolResults.push(result.value);
} else <span class="missing-if-branch" title="else path not taken" >E</span>{
} else {
// Use centralized error handler for tool errors
<span class="cstat-no" title="statement not covered" > ErrorHandler.handleError(result.reason, 'ChatView.handleUserInput');</span>
ErrorHandler.handleError(result.reason, 'ChatView.handleUserInput');
}
}
&nbsp;
@@ -1448,23 +1450,21 @@ export class ChatView extends ItemView {
content: fullResponse,
isStreaming: false,
});
} else <span class="missing-if-branch" title="else path not taken" >E</span>{
} else {
// Even if no tool results were successful, mark streaming as complete
// to prevent the assistant message from disappearing
<span class="cstat-no" title="statement not covered" > this.updateMessageById(assistantMessageId, {</span>
this.updateMessageById(assistantMessageId, {
content: fullResponse,
isStreaming: false,
});
}
}
&nbsp;
// Update last message immutably — only if no tool calls were processed
// Update assistant message immutably — only if no tool calls were processed
if (toolCalls.length === 0) {
const lastMessageIndex = this.messages.length - 1;
if (lastMessageIndex &gt;= 0) {
const lastMessage = { ...this.messages[lastMessageIndex], isStreaming: false };
this.messages = [...this.messages.slice(0, lastMessageIndex), lastMessage];
}
this.updateMessageById(assistantMessageId, {
isStreaming: false,
});
}
&nbsp;
// Limit conversation history to prevent memory issues
@@ -1501,7 +1501,7 @@ export class ChatView extends ItemView {
<div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2026-05-06T20:36:57.831Z
at 2026-05-06T21:42:52.284Z
</div>
<script src="prettify.js"></script>
<script>
+23 -23
View File
@@ -214,30 +214,30 @@
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">2x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">10x</span>
<span class="cline-any cline-yes">10x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">10x</span>
<span class="cline-any cline-yes">9x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">9x</span>
<span class="cline-any cline-yes">9x</span>
<span class="cline-any cline-yes">9x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">16x</span>
<span class="cline-any cline-yes">7x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">9x</span>
<span class="cline-any cline-yes">8x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">8x</span>
<span class="cline-any cline-yes">8x</span>
<span class="cline-any cline-yes">8x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">15x</span>
<span class="cline-any cline-yes">7x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">8x</span>
<span class="cline-any cline-yes">7x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
@@ -272,15 +272,15 @@
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">14x</span>
<span class="cline-any cline-yes">13x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">14x</span>
<span class="cline-any cline-yes">13x</span>
<span class="cline-any cline-yes">2x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">12x</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-yes">11x</span>
<span class="cline-any cline-yes">2x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">9x</span>
@@ -475,7 +475,7 @@ export class ErrorHandler {
<div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2026-05-06T20:36:57.831Z
at 2026-05-06T21:42:52.284Z
</div>
<script src="prettify.js"></script>
<script>
+47 -47
View File
@@ -23,30 +23,30 @@
<div class='clearfix'>
<div class='fl pad1y space-right2'>
<span class="strong">74.47% </span>
<span class="strong">93.41% </span>
<span class="quiet">Statements</span>
<span class='fraction'>499/670</span>
<span class='fraction'>624/668</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">59.06% </span>
<span class="strong">82.09% </span>
<span class="quiet">Branches</span>
<span class='fraction'>176/298</span>
<span class='fraction'>243/296</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">78.21% </span>
<span class="strong">93.06% </span>
<span class="quiet">Functions</span>
<span class='fraction'>79/101</span>
<span class='fraction'>94/101</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">75.31% </span>
<span class="strong">94.51% </span>
<span class="quiet">Lines</span>
<span class='fraction'>482/640</span>
<span class='fraction'>603/638</span>
</div>
@@ -61,7 +61,7 @@
</div>
</template>
</div>
<div class='status-line medium'></div>
<div class='status-line high'></div>
<div class="pad1">
<table class="coverage-summary">
<thead>
@@ -80,17 +80,17 @@
</thead>
<tbody><tr>
<td class="file high" data-value="chat-view.ts"><a href="chat-view.ts.html">chat-view.ts</a></td>
<td data-value="90.36" class="pic high">
<div class="chart"><div class="cover-fill" style="width: 90%"></div><div class="cover-empty" style="width: 10%"></div></div>
<td data-value="92.55" class="pic high">
<div class="chart"><div class="cover-fill" style="width: 92%"></div><div class="cover-empty" style="width: 8%"></div></div>
</td>
<td data-value="90.36" class="pct high">90.36%</td>
<td data-value="218" class="abs high">197/218</td>
<td data-value="80.28" class="pct high">80.28%</td>
<td data-value="71" class="abs high">57/71</td>
<td data-value="92.55" class="pct high">92.55%</td>
<td data-value="215" class="abs high">199/215</td>
<td data-value="85.71" class="pct high">85.71%</td>
<td data-value="70" class="abs high">60/70</td>
<td data-value="82.85" class="pct high">82.85%</td>
<td data-value="35" class="abs high">29/35</td>
<td data-value="92.15" class="pct high">92.15%</td>
<td data-value="204" class="abs high">188/204</td>
<td data-value="94.52" class="pct high">94.52%</td>
<td data-value="201" class="abs high">190/201</td>
</tr>
<tr>
@@ -109,18 +109,18 @@
</tr>
<tr>
<td class="file low" data-value="ollama-client.ts"><a href="ollama-client.ts.html">ollama-client.ts</a></td>
<td data-value="17.7" class="pic low">
<div class="chart"><div class="cover-fill" style="width: 17%"></div><div class="cover-empty" style="width: 83%"></div></div>
<td class="file high" data-value="ollama-client.ts"><a href="ollama-client.ts.html">ollama-client.ts</a></td>
<td data-value="91.91" class="pic high">
<div class="chart"><div class="cover-fill" style="width: 91%"></div><div class="cover-empty" style="width: 9%"></div></div>
</td>
<td data-value="17.7" class="pct low">17.7%</td>
<td data-value="96" class="abs low">17/96</td>
<td data-value="4" class="pct low">4%</td>
<td data-value="50" class="abs low">2/50</td>
<td data-value="36.36" class="pct low">36.36%</td>
<td data-value="11" class="abs low">4/11</td>
<td data-value="18.47" class="pct low">18.47%</td>
<td data-value="92" class="abs low">17/92</td>
<td data-value="91.91" class="pct high">91.91%</td>
<td data-value="99" class="abs high">91/99</td>
<td data-value="72" class="pct medium">72%</td>
<td data-value="50" class="abs medium">36/50</td>
<td data-value="100" class="pct high">100%</td>
<td data-value="11" class="abs high">11/11</td>
<td data-value="91.57" class="pct high">91.57%</td>
<td data-value="95" class="abs high">87/95</td>
</tr>
<tr>
@@ -154,33 +154,33 @@
</tr>
<tr>
<td class="file low" data-value="utils.ts"><a href="utils.ts.html">utils.ts</a></td>
<td data-value="44.32" class="pic low">
<div class="chart"><div class="cover-fill" style="width: 44%"></div><div class="cover-empty" style="width: 56%"></div></div>
<td class="file high" data-value="utils.ts"><a href="utils.ts.html">utils.ts</a></td>
<td data-value="95.87" class="pic high">
<div class="chart"><div class="cover-fill" style="width: 95%"></div><div class="cover-empty" style="width: 5%"></div></div>
</td>
<td data-value="44.32" class="pct low">44.32%</td>
<td data-value="97" class="abs low">43/97</td>
<td data-value="22.91" class="pct low">22.91%</td>
<td data-value="48" class="abs low">11/48</td>
<td data-value="43.75" class="pct low">43.75%</td>
<td data-value="16" class="abs low">7/16</td>
<td data-value="43.01" class="pct low">43.01%</td>
<td data-value="93" class="abs low">40/93</td>
<td data-value="95.87" class="pct high">95.87%</td>
<td data-value="97" class="abs high">93/97</td>
<td data-value="85.41" class="pct high">85.41%</td>
<td data-value="48" class="abs high">41/48</td>
<td data-value="93.75" class="pct high">93.75%</td>
<td data-value="16" class="abs high">15/16</td>
<td data-value="96.77" class="pct high">96.77%</td>
<td data-value="93" class="abs high">90/93</td>
</tr>
<tr>
<td class="file high" data-value="vault-indexer.ts"><a href="vault-indexer.ts.html">vault-indexer.ts</a></td>
<td data-value="92.1" class="pic high">
<td data-value="92.85" class="pic high">
<div class="chart"><div class="cover-fill" style="width: 92%"></div><div class="cover-empty" style="width: 8%"></div></div>
</td>
<td data-value="92.1" class="pct high">92.1%</td>
<td data-value="114" class="abs high">105/114</td>
<td data-value="78.26" class="pct medium">78.26%</td>
<td data-value="46" class="abs medium">36/46</td>
<td data-value="92.85" class="pct high">92.85%</td>
<td data-value="112" class="abs high">104/112</td>
<td data-value="80" class="pct high">80%</td>
<td data-value="45" class="abs high">36/45</td>
<td data-value="100" class="pct high">100%</td>
<td data-value="15" class="abs high">15/15</td>
<td data-value="94.33" class="pct high">94.33%</td>
<td data-value="106" class="abs high">100/106</td>
<td data-value="95.19" class="pct high">95.19%</td>
<td data-value="104" class="abs high">99/104</td>
</tr>
</tbody>
@@ -191,7 +191,7 @@
<div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2026-05-06T20:36:57.831Z
at 2026-05-06T21:42:52.284Z
</div>
<script src="prettify.js"></script>
<script>
+300 -276
View File
@@ -23,30 +23,30 @@
<div class='clearfix'>
<div class='fl pad1y space-right2'>
<span class="strong">17.7% </span>
<span class="strong">91.91% </span>
<span class="quiet">Statements</span>
<span class='fraction'>17/96</span>
<span class='fraction'>91/99</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">4% </span>
<span class="strong">72% </span>
<span class="quiet">Branches</span>
<span class='fraction'>2/50</span>
<span class='fraction'>36/50</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">36.36% </span>
<span class="strong">100% </span>
<span class="quiet">Functions</span>
<span class='fraction'>4/11</span>
<span class='fraction'>11/11</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">18.47% </span>
<span class="strong">91.57% </span>
<span class="quiet">Lines</span>
<span class='fraction'>17/92</span>
<span class='fraction'>87/95</span>
</div>
@@ -61,7 +61,7 @@
</div>
</template>
</div>
<div class='status-line low'></div>
<div class='status-line high'></div>
<pre><table class="coverage">
<tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a>
<a name='L2'></a><a href='#L2'>2</a>
@@ -293,7 +293,15 @@
<a name='L228'></a><a href='#L228'>228</a>
<a name='L229'></a><a href='#L229'>229</a>
<a name='L230'></a><a href='#L230'>230</a>
<a name='L231'></a><a href='#L231'>231</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
<a name='L231'></a><a href='#L231'>231</a>
<a name='L232'></a><a href='#L232'>232</a>
<a name='L233'></a><a href='#L233'>233</a>
<a name='L234'></a><a href='#L234'>234</a>
<a name='L235'></a><a href='#L235'>235</a>
<a name='L236'></a><a href='#L236'>236</a>
<a name='L237'></a><a href='#L237'>237</a>
<a name='L238'></a><a href='#L238'>238</a>
<a name='L239'></a><a href='#L239'>239</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">2x</span>
@@ -306,19 +314,38 @@
<span class="cline-any cline-yes">2x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">31x</span>
<span class="cline-any cline-yes">59x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">59x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">59x</span>
<span class="cline-any cline-yes">59x</span>
<span class="cline-any cline-yes">59x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">28x</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">20x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">31x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">31x</span>
<span class="cline-any cline-yes">31x</span>
<span class="cline-any cline-yes">31x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
@@ -327,29 +354,161 @@
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">25x</span>
<span class="cline-any cline-yes">25x</span>
<span class="cline-any cline-yes">25x</span>
<span class="cline-any cline-yes">5x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">25x</span>
<span class="cline-any cline-yes">25x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">25x</span>
<span class="cline-any cline-yes">8x</span>
<span class="cline-any cline-yes">5x</span>
<span class="cline-any cline-yes">5x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">5x</span>
<span class="cline-any cline-yes">5x</span>
<span class="cline-any cline-yes">2x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">13x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">12x</span>
<span class="cline-any cline-yes">12x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">11x</span>
<span class="cline-any cline-yes">11x</span>
<span class="cline-any cline-yes">11x</span>
<span class="cline-any cline-yes">11x</span>
<span class="cline-any cline-yes">11x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">11x</span>
<span class="cline-any cline-yes">11x</span>
<span class="cline-any cline-yes">19x</span>
<span class="cline-any cline-yes">19x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">10x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">10x</span>
<span class="cline-any cline-yes">10x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">10x</span>
<span class="cline-any cline-yes">68x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">67x</span>
<span class="cline-any cline-yes">67x</span>
<span class="cline-any cline-yes">14x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">13x</span>
<span class="cline-any cline-yes">13x</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">13x</span>
<span class="cline-any cline-yes">13x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">54x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">53x</span>
<span class="cline-any cline-yes">53x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">52x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">9x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">11x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">25x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">5x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">8x</span>
<span class="cline-any cline-yes">8x</span>
<span class="cline-any cline-yes">8x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">8x</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">4x</span>
@@ -357,166 +516,23 @@
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">8x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">15x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">18x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-yes">17x</span>
<span class="cline-any cline-yes">17x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
@@ -560,12 +576,12 @@ export class OllamaClient {
yield* this.streamChatWithRetry(messages, tools, 0);
}
&nbsp;
<span class="fstat-no" title="function not covered" > async </span>streamChatAsPromise(
async streamChatAsPromise(
messages: OllamaMessage[],
tools: OllamaTool[] = <span class="branch-0 cbranch-no" title="branch not covered" >[]</span>
): Promise&lt;OllamaMessage[]&gt; {
const chunks: OllamaMessage[] = <span class="cstat-no" title="statement not covered" >[];</span>
<span class="cstat-no" title="statement not covered" > for await (const chunk of this.streamChat(messages, tools)) {</span>
const chunks: OllamaMessage[] = [];
for await (const chunk of this.streamChat(messages, tools)) {
<span class="cstat-no" title="statement not covered" > chunks.push(chunk);</span>
}
<span class="cstat-no" title="statement not covered" > return chunks;</span>
@@ -578,8 +594,8 @@ export class OllamaClient {
): AsyncGenerator&lt;OllamaMessage, void, unknown&gt; {
const prevController = this.abortController;
this.abortController = new AbortController();
<span class="missing-if-branch" title="if path not taken" >I</span>if (prevController) {
<span class="cstat-no" title="statement not covered" > prevController.abort();</span>
if (prevController) {
prevController.abort();
}
&nbsp;
try {
@@ -597,70 +613,70 @@ export class OllamaClient {
signal: this.abortController.signal,
});
&nbsp;
<span class="missing-if-branch" title="if path not taken" >I</span>if (!response.ok) {
<span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (response.status &gt;= 500 &amp;&amp; attempt &lt; this.maxRetries) {</span>
const retryDelay = <span class="cstat-no" title="statement not covered" >Math.pow(2, attempt) * 100;</span>
<span class="cstat-no" title="statement not covered" > Logger.warn(</span>
if (!response.ok) {
if (response.status &gt;= 500 &amp;&amp; attempt &lt; this.maxRetries) {
const retryDelay = Math.pow(2, attempt) * 100;
Logger.warn(
`Network error (status ${response.status}), retrying in ${retryDelay}ms (attempt ${attempt + 1}/${this.maxRetries})`,
'ollama-client'
);
<span class="cstat-no" title="statement not covered" > await new Promise(<span class="fstat-no" title="function not covered" >(r</span>esolve) =&gt; <span class="cstat-no" title="statement not covered" >setTimeout(resolve, retryDelay))</span>;</span>
<span class="cstat-no" title="statement not covered" > yield* this.streamChatWithRetry(messages, tools, attempt + 1);</span>
<span class="cstat-no" title="statement not covered" > return;</span>
await new Promise((resolve) =&gt; setTimeout(resolve, retryDelay));
yield* this.streamChatWithRetry(messages, tools, attempt + 1);
return;
}
<span class="cstat-no" title="statement not covered" > throw new ApiError(`Ollama API error: ${response.status}`, response.status);</span>
throw new ApiError(`Ollama API error: ${response.status}`, response.status);
}
&nbsp;
<span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (!response.body) {</span>
<span class="cstat-no" title="statement not covered" > throw new Error('No response body');</span>
if (!response.body) {
throw new Error('No response body');
}
&nbsp;
const contentType = <span class="cstat-no" title="statement not covered" >response.headers.get('content-type');</span>
<span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (!contentType || (!contentType.includes('ndjson') &amp;&amp; !contentType.includes('json'))) {</span>
<span class="cstat-no" title="statement not covered" > throw new Error('Invalid response format');</span>
const contentType = response.headers.get('content-type');
if (!contentType || (!contentType.includes('ndjson') &amp;&amp; !contentType.includes('json'))) {
throw new Error('Invalid response format');
}
&nbsp;
const reader = <span class="cstat-no" title="statement not covered" >response.body.getReader();</span>
const decoder = <span class="cstat-no" title="statement not covered" >new TextDecoder();</span>
let buffer = <span class="cstat-no" title="statement not covered" >'';</span>
let malformedCount = <span class="cstat-no" title="statement not covered" >0;</span>
const maxMalformed = <span class="cstat-no" title="statement not covered" >50;</span>
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = '';
let malformedCount = 0;
const maxMalformed = 50;
&nbsp;
<span class="cstat-no" title="statement not covered" > try {</span>
<span class="cstat-no" title="statement not covered" > while (true) {</span>
const { done, value } = <span class="cstat-no" title="statement not covered" >await reader.read();</span>
<span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (done) <span class="cstat-no" title="statement not covered" >break;</span></span>
try {
while (true) {
const { done, value } = await reader.read();
if (done) break;
&nbsp;
<span class="cstat-no" title="statement not covered" > buffer += decoder.decode(value, { stream: true });</span>
buffer += decoder.decode(value, { stream: true });
&nbsp;
const lines = <span class="cstat-no" title="statement not covered" >buffer.split('\n');</span>
<span class="cstat-no" title="statement not covered" > buffer = lines.pop() ?? '';</span>
const lines = buffer.split('\n');
buffer = lines.pop() ?? <span class="branch-1 cbranch-no" title="branch not covered" >'';</span>
&nbsp;
<span class="cstat-no" title="statement not covered" > for (const line of lines) {</span>
<span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (!line.trim()) <span class="cstat-no" title="statement not covered" >continue;</span></span>
for (const line of lines) {
if (!line.trim()) continue;
&nbsp;
<span class="cstat-no" title="statement not covered" > try {</span>
const parsed = <span class="cstat-no" title="statement not covered" >JSON.parse(line) as Record&lt;string, unknown&gt;;</span>
<span class="cstat-no" title="statement not covered" > this.throwIfOllamaError(parsed);</span>
try {
const parsed = JSON.parse(line) as Record&lt;string, unknown&gt;;
this.throwIfOllamaError(parsed);
&nbsp;
const message = <span class="cstat-no" title="statement not covered" >this.toOllamaMessage(parsed.message);</span>
<span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (!message) {</span>
const message = this.toOllamaMessage(parsed.message);
<span class="missing-if-branch" title="if path not taken" >I</span>if (!message) {
<span class="cstat-no" title="statement not covered" > continue;</span>
}
&nbsp;
<span class="cstat-no" title="statement not covered" > malformedCount = 0;</span>
<span class="cstat-no" title="statement not covered" > yield message;</span>
malformedCount = 0;
yield message;
} catch (error) {
<span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (error instanceof Error &amp;&amp; error.message.startsWith('Ollama error:')) {</span>
<span class="cstat-no" title="statement not covered" > throw error;</span>
if (error instanceof Error &amp;&amp; error.message.startsWith('Ollama error:')) {
throw error;
}
&nbsp;
<span class="cstat-no" title="statement not covered" > malformedCount++;</span>
<span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (malformedCount &gt; maxMalformed) {</span>
<span class="cstat-no" title="statement not covered" > throw new Error('Too many malformed chunks in stream');</span>
malformedCount++;
if (malformedCount &gt; maxMalformed) {
throw new Error('Too many malformed chunks in stream');
}
&nbsp;
<span class="cstat-no" title="statement not covered" > Logger.warn(</span>
Logger.warn(
`Skipped malformed chunk: ${line.substring(0, 80)}... - ${(error as Error).message}`,
'ollama-client'
);
@@ -668,14 +684,14 @@ export class OllamaClient {
}
}
&nbsp;
<span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (buffer.trim()) {</span>
<span class="cstat-no" title="statement not covered" > try {</span>
const parsed = <span class="cstat-no" title="statement not covered" >JSON.parse(buffer) as Record&lt;string, unknown&gt;;</span>
<span class="cstat-no" title="statement not covered" > this.throwIfOllamaError(parsed);</span>
if (buffer.trim()) {
try {
const parsed = JSON.parse(buffer) as Record&lt;string, unknown&gt;;
this.throwIfOllamaError(parsed);
&nbsp;
const message = <span class="cstat-no" title="statement not covered" >this.toOllamaMessage(parsed.message);</span>
<span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (message) {</span>
<span class="cstat-no" title="statement not covered" > yield message;</span>
const message = this.toOllamaMessage(parsed.message);
if (message) {
yield message;
}
} catch (error) {
<span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (error instanceof Error &amp;&amp; error.message.startsWith('Ollama error:')) {</span>
@@ -688,67 +704,75 @@ export class OllamaClient {
}
}
} finally {
<span class="cstat-no" title="statement not covered" > reader.releaseLock();</span>
reader.releaseLock();
}
} finally {
this.abortController = null;
}
}
&nbsp;
<span class="fstat-no" title="function not covered" > async </span>chat(messages: OllamaMessage[], tools: OllamaTool[] = <span class="branch-0 cbranch-no" title="branch not covered" >[])</span>: Promise&lt;OllamaMessage&gt; {
<span class="cstat-no" title="statement not covered" > return this.chatWithRetry(messages, tools, 0);</span>
async chat(messages: OllamaMessage[], tools: OllamaTool[] = <span class="branch-0 cbranch-no" title="branch not covered" >[])</span>: Promise&lt;OllamaMessage&gt; {
return this.chatWithRetry(messages, tools, 0);
}
&nbsp;
private <span class="fstat-no" title="function not covered" >async </span>chatWithRetry(
private async chatWithRetry(
messages: OllamaMessage[],
tools: OllamaTool[] = <span class="branch-0 cbranch-no" title="branch not covered" >[],</span>
attempt: number = <span class="branch-0 cbranch-no" title="branch not covered" >0</span>
): Promise&lt;OllamaMessage&gt; {
const response = <span class="cstat-no" title="statement not covered" >await this.fetchFn(`${this.baseURL}/api/chat`, {</span>
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
model: this.model,
messages,
tools,
stream: false,
}),
});
this.abortController = new AbortController();
try {
const response = await this.fetchFn(`${this.baseURL}/api/chat`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
model: this.model,
messages,
tools,
stream: false,
}),
signal: this.abortController.signal,
});
&nbsp;
<span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (!response.ok) {</span>
<span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (response.status &gt;= 500 &amp;&amp; attempt &lt; this.maxRetries) {</span>
const retryDelay = <span class="cstat-no" title="statement not covered" >Math.pow(2, attempt) * 100;</span>
<span class="cstat-no" title="statement not covered" > Logger.warn(</span>
`Network error (status ${response.status}), retrying in ${retryDelay}ms (attempt ${attempt + 1}/${this.maxRetries})`,
'ollama-client'
);
<span class="cstat-no" title="statement not covered" > await new Promise(<span class="fstat-no" title="function not covered" >(r</span>esolve) =&gt; <span class="cstat-no" title="statement not covered" >setTimeout(resolve, retryDelay))</span>;</span>
<span class="cstat-no" title="statement not covered" > return this.chatWithRetry(messages, tools, attempt + 1);</span>
if (!response.ok) {
if (response.status &gt;= 500 &amp;&amp; attempt &lt; this.maxRetries) {
const retryDelay = Math.pow(2, attempt) * 100;
Logger.warn(
`Network error (status ${response.status}), retrying in ${retryDelay}ms (attempt ${attempt + 1}/${this.maxRetries})`,
'ollama-client'
);
await new Promise((resolve) =&gt; setTimeout(resolve, retryDelay));
return this.chatWithRetry(messages, tools, attempt + 1);
}
throw new ApiError(`Ollama API error: ${response.status}`, response.status);
}
<span class="cstat-no" title="statement not covered" > throw new ApiError(`Ollama API error: ${response.status}`, response.status);</span>
}
&nbsp;
const data = (<span class="cstat-no" title="statement not covered" >await response.json())</span> as OllamaChatResponse;
<span class="cstat-no" title="statement not covered" > return this.toOllamaMessage(data.message) ?? { role: 'assistant', content: '', tool_calls: [] };</span>
}
&nbsp;
private <span class="fstat-no" title="function not covered" >throwIfOllamaError(</span>parsed: Record&lt;string, unknown&gt;): void {
<span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (parsed.error) {</span>
<span class="cstat-no" title="statement not covered" > throw new Error(`Ollama error: ${String(parsed.error)}`);</span>
const data = (await response.json()) as OllamaChatResponse;
return (
this.toOllamaMessage(data.message) ?? { role: 'assistant', content: '', tool_calls: [] }
);
} finally {
this.abortController = null;
}
}
&nbsp;
private <span class="fstat-no" title="function not covered" >toOllamaMessage(</span>value: unknown): OllamaMessage | null {
<span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (!value || typeof value !== 'object') {</span>
<span class="cstat-no" title="statement not covered" > return null;</span>
private throwIfOllamaError(parsed: Record&lt;string, unknown&gt;): void {
if (parsed.error) {
throw new Error(`Ollama error: ${String(parsed.error)}`);
}
}
&nbsp;
private toOllamaMessage(value: unknown): OllamaMessage | null {
if (!value || typeof value !== 'object') {
return null;
}
&nbsp;
const record = <span class="cstat-no" title="statement not covered" >value as Partial&lt;OllamaMessage&gt;;</span>
<span class="cstat-no" title="statement not covered" > return {</span>
const record = value as Partial&lt;OllamaMessage&gt;;
return {
role: record.role ?? 'assistant',
content: typeof record.content === 'string' ? record.content : '',
content: typeof record.content === 'string' ? record.content : <span class="branch-1 cbranch-no" title="branch not covered" >'',</span>
tool_calls: record.tool_calls ?? [],
};
}
@@ -760,7 +784,7 @@ export class OllamaClient {
<div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2026-05-06T20:36:57.831Z
at 2026-05-06T21:42:52.284Z
</div>
<script src="prettify.js"></script>
<script>
+3 -3
View File
@@ -210,8 +210,8 @@
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">58x</span>
<span class="cline-any cline-yes">58x</span>
<span class="cline-any cline-yes">63x</span>
<span class="cline-any cline-yes">63x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
@@ -463,7 +463,7 @@ export class ToolExecutor {
<div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2026-05-06T20:36:57.831Z
at 2026-05-06T21:42:52.284Z
</div>
<script src="prettify.js"></script>
<script>
+7 -7
View File
@@ -261,9 +261,9 @@
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">15x</span>
<span class="cline-any cline-yes">15x</span>
<span class="cline-any cline-yes">15x</span>
<span class="cline-any cline-yes">19x</span>
<span class="cline-any cline-yes">19x</span>
<span class="cline-any cline-yes">19x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
@@ -281,9 +281,9 @@
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-yes">5x</span>
<span class="cline-any cline-yes">5x</span>
<span class="cline-any cline-yes">5x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
@@ -604,7 +604,7 @@ export interface VaultIndexEntry {
<div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2026-05-06T20:36:57.831Z
at 2026-05-06T21:42:52.284Z
</div>
<script src="prettify.js"></script>
<script>
+167 -179
View File
@@ -23,30 +23,30 @@
<div class='clearfix'>
<div class='fl pad1y space-right2'>
<span class="strong">44.32% </span>
<span class="strong">95.87% </span>
<span class="quiet">Statements</span>
<span class='fraction'>43/97</span>
<span class='fraction'>93/97</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">22.91% </span>
<span class="strong">85.41% </span>
<span class="quiet">Branches</span>
<span class='fraction'>11/48</span>
<span class='fraction'>41/48</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">43.75% </span>
<span class="strong">93.75% </span>
<span class="quiet">Functions</span>
<span class='fraction'>7/16</span>
<span class='fraction'>15/16</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">43.01% </span>
<span class="strong">96.77% </span>
<span class="quiet">Lines</span>
<span class='fraction'>40/93</span>
<span class='fraction'>90/93</span>
</div>
@@ -61,7 +61,7 @@
</div>
</template>
</div>
<div class='status-line low'></div>
<div class='status-line high'></div>
<pre><table class="coverage">
<tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a>
<a name='L2'></a><a href='#L2'>2</a>
@@ -267,15 +267,7 @@
<a name='L202'></a><a href='#L202'>202</a>
<a name='L203'></a><a href='#L203'>203</a>
<a name='L204'></a><a href='#L204'>204</a>
<a name='L205'></a><a href='#L205'>205</a>
<a name='L206'></a><a href='#L206'>206</a>
<a name='L207'></a><a href='#L207'>207</a>
<a name='L208'></a><a href='#L208'>208</a>
<a name='L209'></a><a href='#L209'>209</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">5x</span>
<a name='L205'></a><a href='#L205'>205</a></td><td class="line-coverage quiet"><span class="cline-any cline-yes">5x</span>
<span class="cline-any cline-yes">5x</span>
<span class="cline-any cline-yes">5x</span>
<span class="cline-any cline-yes">5x</span>
@@ -293,35 +285,35 @@
<span class="cline-any cline-yes">5x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-yes">23x</span>
<span class="cline-any cline-yes">11x</span>
<span class="cline-any cline-yes">11x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-yes">12x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-yes">2x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">64x</span>
<span class="cline-any cline-yes">63x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">2x</span>
<span class="cline-any cline-yes">2x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
@@ -329,71 +321,71 @@
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">5x</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-yes">12x</span>
<span class="cline-any cline-yes">2x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-yes">10x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-yes">10x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-yes">9x</span>
<span class="cline-any cline-yes">9x</span>
<span class="cline-any cline-yes">6x</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-yes">6x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">5x</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-yes">15x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-yes">14x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-yes">14x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-yes">13x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-yes">12x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-yes">11x</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-yes">8x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">5x</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-yes">2x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-yes">2x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
@@ -402,67 +394,67 @@
<span class="cline-any cline-yes">5x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">75x</span>
<span class="cline-any cline-yes">117x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">116x</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">75x</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-yes">116x</span>
<span class="cline-any cline-yes">58x</span>
<span class="cline-any cline-yes">58x</span>
<span class="cline-any cline-yes">83x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">75x</span>
<span class="cline-any cline-yes">26x</span>
<span class="cline-any cline-yes">26x</span>
<span class="cline-any cline-yes">49x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">49x</span>
<span class="cline-any cline-yes">58x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">5x</span>
<span class="cline-any cline-yes">27x</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-yes">41x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">27x</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">27x</span>
<span class="cline-any cline-yes">27x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">40x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">26x</span>
<span class="cline-any cline-yes">75x</span>
<span class="cline-any cline-yes">49x</span>
<span class="cline-any cline-yes">39x</span>
<span class="cline-any cline-yes">39x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">2x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">26x</span>
<span class="cline-any cline-yes">78x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">37x</span>
<span class="cline-any cline-yes">121x</span>
<span class="cline-any cline-yes">59x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">62x</span>
<span class="cline-any cline-yes">183x</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">59x</span>
<span class="cline-any cline-yes">84x</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">26x</span>
<span class="cline-any cline-yes">49x</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-yes">59x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">37x</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">26x</span>
<span class="cline-any cline-yes">34x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">26x</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">26x</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">26x</span>
<span class="cline-any cline-yes">33x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
@@ -470,20 +462,16 @@
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">5x</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-yes">6x</span>
<span class="cline-any cline-yes">6x</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-yes">2x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">// src/utils.ts
&nbsp;
// ==================== Logger ====================
&nbsp;
enum LogLevel {
<span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">export enum LogLevel {
DEBUG = 0,
INFO = 1,
WARN = 2,
@@ -500,24 +488,24 @@ const SEVERITY_ORDER: Record&lt;string, number&gt; = {
export class Logger {
private static minLevel: LogLevel = LogLevel.DEBUG;
&nbsp;
<span class="fstat-no" title="function not covered" > static </span>setLevel(level: string | LogLevel): void {
<span class="cstat-no" title="statement not covered" > if (typeof level === 'string') {</span>
const lowerLevel = <span class="cstat-no" title="statement not covered" >level.toLowerCase();</span>
<span class="cstat-no" title="statement not covered" > Logger.minLevel = SEVERITY_ORDER[lowerLevel] ?? LogLevel.DEBUG;</span>
static setLevel(level: string | LogLevel): void {
if (typeof level === 'string') {
const lowerLevel = level.toLowerCase();
Logger.minLevel = SEVERITY_ORDER[lowerLevel] ?? LogLevel.DEBUG;
} else {
<span class="cstat-no" title="statement not covered" > Logger.minLevel = level;</span>
Logger.minLevel = level;
}
}
&nbsp;
<span class="fstat-no" title="function not covered" > static </span>debug(message: string, category: string = <span class="branch-0 cbranch-no" title="branch not covered" >'general')</span>: void {
<span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (LogLevel.DEBUG &gt;= Logger.minLevel) {</span>
<span class="cstat-no" title="statement not covered" > console.debug(`[${category}] DEBUG: ${message}`);</span>
static debug(message: string, category: string = <span class="branch-0 cbranch-no" title="branch not covered" >'general')</span>: void {
if (LogLevel.DEBUG &gt;= Logger.minLevel) {
console.debug(`[${category}] DEBUG: ${message}`);
}
}
&nbsp;
<span class="fstat-no" title="function not covered" > static </span>info(message: string, category: string = <span class="branch-0 cbranch-no" title="branch not covered" >'general')</span>: void {
<span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (LogLevel.INFO &gt;= Logger.minLevel) {</span>
<span class="cstat-no" title="statement not covered" > console.info(`[${category}] INFO: ${message}`);</span>
static info(message: string, category: string = <span class="branch-0 cbranch-no" title="branch not covered" >'general')</span>: void {
if (LogLevel.INFO &gt;= Logger.minLevel) {
console.info(`[${category}] INFO: ${message}`);
}
}
&nbsp;
@@ -527,81 +515,81 @@ export class Logger {
}
}
&nbsp;
<span class="fstat-no" title="function not covered" > static </span>error(message: string, category: string = <span class="branch-0 cbranch-no" title="branch not covered" >'general')</span>: void {
<span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (LogLevel.ERROR &gt;= Logger.minLevel) {</span>
<span class="cstat-no" title="statement not covered" > console.error(`[${category}] ERROR: ${message}`);</span>
static error(message: string, category: string = <span class="branch-0 cbranch-no" title="branch not covered" >'general')</span>: void {
if (LogLevel.ERROR &gt;= Logger.minLevel) {
console.error(`[${category}] ERROR: ${message}`);
}
}
}
&nbsp;
// ==================== URL &amp; Model Validation ====================
&nbsp;
export function <span class="fstat-no" title="function not covered" >validateOllamaUrl(</span>url: string): { valid: boolean; error?: string } {
<span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (typeof url !== 'string' || !url.trim()) {</span>
<span class="cstat-no" title="statement not covered" > return { valid: false, error: 'URL cannot be empty' };</span>
export function validateOllamaUrl(url: string): { valid: boolean; error?: string } {
if (typeof url !== 'string' || !url.trim()) {
return { valid: false, error: 'URL cannot be empty' };
}
&nbsp;
const trimmedUrl = <span class="cstat-no" title="statement not covered" >url.trim();</span>
const trimmedUrl = url.trim();
&nbsp;
<span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (trimmedUrl.endsWith('/')) {</span>
<span class="cstat-no" title="statement not covered" > return { valid: false, error: 'URL should not end with a slash' };</span>
if (trimmedUrl.endsWith('/')) {
return { valid: false, error: 'URL should not end with a slash' };
}
&nbsp;
<span class="cstat-no" title="statement not covered" > try {</span>
const parsed = <span class="cstat-no" title="statement not covered" >new URL(trimmedUrl);</span>
<span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (parsed.protocol !== 'http:' &amp;&amp; parsed.protocol !== 'https:') {</span>
try {
const parsed = new URL(trimmedUrl);
<span class="missing-if-branch" title="if path not taken" >I</span>if (parsed.protocol !== 'http:' &amp;&amp; parsed.protocol !== 'https:') {
<span class="cstat-no" title="statement not covered" > return { valid: false, error: 'Must be a valid HTTP or HTTPS URL' };</span>
}
<span class="cstat-no" title="statement not covered" > return { valid: true };</span>
return { valid: true };
} catch {
<span class="cstat-no" title="statement not covered" > return { valid: false, error: 'Must be a valid HTTP or HTTPS URL' };</span>
return { valid: false, error: 'Must be a valid HTTP or HTTPS URL' };
}
}
&nbsp;
export function <span class="fstat-no" title="function not covered" >validateModelName(</span>model: string): { valid: boolean; error?: string } {
<span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (typeof model !== 'string') {</span>
<span class="cstat-no" title="statement not covered" > return { valid: false, error: 'Model name must be a string' };</span>
export function validateModelName(model: string): { valid: boolean; error?: string } {
if (typeof model !== 'string') {
return { valid: false, error: 'Model name must be a string' };
}
&nbsp;
const trimmedModel = <span class="cstat-no" title="statement not covered" >model.trim();</span>
const trimmedModel = model.trim();
&nbsp;
// Explicit check for empty string after trimming
<span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (!trimmedModel || trimmedModel.length === 0) {</span>
<span class="cstat-no" title="statement not covered" > return { valid: false, error: 'Model name cannot be empty' };</span>
if (!trimmedModel || trimmedModel.length === 0) {
return { valid: false, error: 'Model name cannot be empty' };
}
&nbsp;
<span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (trimmedModel.length &lt; 2) {</span>
<span class="cstat-no" title="statement not covered" > return { valid: false, error: 'Model name must be at least 2 characters long' };</span>
if (trimmedModel.length &lt; 2) {
return { valid: false, error: 'Model name must be at least 2 characters long' };
}
&nbsp;
<span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (trimmedModel.length &gt; 100) {</span>
<span class="cstat-no" title="statement not covered" > return { valid: false, error: 'Model name must be less than 100 characters long' };</span>
if (trimmedModel.length &gt; 100) {
return { valid: false, error: 'Model name must be less than 100 characters long' };
}
&nbsp;
<span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (!/^[a-zA-Z0-9._:-]+$/.test(trimmedModel)) {</span>
<span class="cstat-no" title="statement not covered" > return {</span>
if (!/^[a-zA-Z0-9._:-]+$/.test(trimmedModel)) {
return {
valid: false,
error: 'Model name can only contain letters, numbers, dots, dashes, underscores, and colons',
};
}
&nbsp;
<span class="cstat-no" title="statement not covered" > return { valid: true };</span>
return { valid: true };
}
&nbsp;
export function <span class="fstat-no" title="function not covered" >validatePluginSettings(</span>settings: { ollamaUrl: string; model: string }): string[] {
const errors: string[] = <span class="cstat-no" title="statement not covered" >[];</span>
export function validatePluginSettings(settings: { ollamaUrl: string; model: string }): string[] {
const errors: string[] = [];
&nbsp;
const urlValidation = <span class="cstat-no" title="statement not covered" >validateOllamaUrl(settings.ollamaUrl);</span>
<span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (!urlValidation.valid) {</span>
<span class="cstat-no" title="statement not covered" > errors.push(`Invalid Ollama URL: ${urlValidation.error}`);</span>
const urlValidation = validateOllamaUrl(settings.ollamaUrl);
if (!urlValidation.valid) {
errors.push(`Invalid Ollama URL: ${urlValidation.error}`);
}
&nbsp;
const modelValidation = <span class="cstat-no" title="statement not covered" >validateModelName(settings.model);</span>
<span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (!modelValidation.valid) {</span>
<span class="cstat-no" title="statement not covered" > errors.push(`Invalid Model Name: ${modelValidation.error}`);</span>
const modelValidation = validateModelName(settings.model);
if (!modelValidation.valid) {
errors.push(`Invalid Model Name: ${modelValidation.error}`);
}
&nbsp;
<span class="cstat-no" title="statement not covered" > return errors;</span>
return errors;
}
&nbsp;
// ==================== Safe JSON Parsing ====================
@@ -610,8 +598,8 @@ const MAX_JSON_SIZE = 1_000_000;
const MAX_JSON_NESTING = 24;
&nbsp;
function countNestingDepth(value: unknown, depth: number = 0): number {
<span class="missing-if-branch" title="if path not taken" >I</span>if (depth &gt; MAX_JSON_NESTING) {
<span class="cstat-no" title="statement not covered" > return depth;</span>
if (depth &gt; MAX_JSON_NESTING) {
return depth;
}
<span class="missing-if-branch" title="if path not taken" >I</span>if (Array.isArray(value)) {
<span class="cstat-no" title="statement not covered" > return Math.max(...value.map(<span class="fstat-no" title="function not covered" >(i</span>tem) =&gt; <span class="cstat-no" title="statement not covered" >countNestingDepth(item, depth + 1))</span>, depth);</span>
@@ -625,12 +613,12 @@ function countNestingDepth(value: unknown, depth: number = 0): number {
}
&nbsp;
export function safeParseJson(jsonString: string): unknown {
<span class="missing-if-branch" title="if path not taken" >I</span>if (typeof jsonString !== 'string') {
<span class="cstat-no" title="statement not covered" > throw new Error('Input must be a string');</span>
if (typeof jsonString !== 'string') {
throw new Error('Input must be a string');
}
&nbsp;
<span class="missing-if-branch" title="if path not taken" >I</span>if (jsonString.length &gt; MAX_JSON_SIZE) {
<span class="cstat-no" title="statement not covered" > throw new Error('JSON input too large');</span>
if (jsonString.length &gt; MAX_JSON_SIZE) {
throw new Error('JSON input too large');
}
&nbsp;
let parsed: unknown;
@@ -647,8 +635,8 @@ export function safeParseJson(jsonString: string): unknown {
}
&nbsp;
const dangerousKeys = ['constructor', 'prototype', '__proto__'];
<span class="missing-if-branch" title="if path not taken" >I</span>if (dangerousKeys.some((key) =&gt; Object.keys(obj).includes(key))) {
<span class="cstat-no" title="statement not covered" > return true;</span>
if (dangerousKeys.some((key) =&gt; Object.keys(obj).includes(key))) {
return true;
}
&nbsp;
// Recursively check nested objects
@@ -661,13 +649,13 @@ export function safeParseJson(jsonString: string): unknown {
return false;
};
&nbsp;
<span class="missing-if-branch" title="if path not taken" >I</span>if (checkDangerousPatterns(parsed)) {
<span class="cstat-no" title="statement not covered" > throw new Error('dangerous code pattern detected');</span>
if (checkDangerousPatterns(parsed)) {
throw new Error('dangerous code pattern detected');
}
&nbsp;
// Check nesting depth
<span class="missing-if-branch" title="if path not taken" >I</span>if (countNestingDepth(parsed) &gt; MAX_JSON_NESTING) {
<span class="cstat-no" title="statement not covered" > throw new Error('JSON nesting too deep');</span>
if (countNestingDepth(parsed) &gt; MAX_JSON_NESTING) {
throw new Error('JSON nesting too deep');
}
&nbsp;
return parsed;
@@ -677,12 +665,12 @@ export function safeParseJson(jsonString: string): unknown {
&nbsp;
// ==================== HTTP Helpers ====================
&nbsp;
export function <span class="fstat-no" title="function not covered" >isValidHttpUrl(</span>url: string): boolean {
<span class="cstat-no" title="statement not covered" > try {</span>
const parsed = <span class="cstat-no" title="statement not covered" >new URL(url);</span>
<span class="cstat-no" title="statement not covered" > return parsed.protocol === 'http:' || parsed.protocol === 'https:';</span>
export function isValidHttpUrl(url: string): boolean {
try {
const parsed = new URL(url);
return parsed.protocol === 'http:' || parsed.protocol === 'https:';
} catch {
<span class="cstat-no" title="statement not covered" > return false;</span>
return false;
}
}
&nbsp;
@@ -694,7 +682,7 @@ export function <span class="fstat-no" title="function not covered" >isValidHttp
<div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2026-05-06T20:36:57.831Z
at 2026-05-06T21:42:52.284Z
</div>
<script src="prettify.js"></script>
<script>
+26 -38
View File
@@ -23,16 +23,16 @@
<div class='clearfix'>
<div class='fl pad1y space-right2'>
<span class="strong">92.1% </span>
<span class="strong">92.85% </span>
<span class="quiet">Statements</span>
<span class='fraction'>105/114</span>
<span class='fraction'>104/112</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">78.26% </span>
<span class="strong">80% </span>
<span class="quiet">Branches</span>
<span class='fraction'>36/46</span>
<span class='fraction'>36/45</span>
</div>
@@ -44,9 +44,9 @@
<div class='fl pad1y space-right2'>
<span class="strong">94.33% </span>
<span class="strong">95.19% </span>
<span class="quiet">Lines</span>
<span class='fraction'>100/106</span>
<span class='fraction'>99/104</span>
</div>
@@ -333,11 +333,7 @@
<a name='L268'></a><a href='#L268'>268</a>
<a name='L269'></a><a href='#L269'>269</a>
<a name='L270'></a><a href='#L270'>270</a>
<a name='L271'></a><a href='#L271'>271</a>
<a name='L272'></a><a href='#L272'>272</a>
<a name='L273'></a><a href='#L273'>273</a>
<a name='L274'></a><a href='#L274'>274</a>
<a name='L275'></a><a href='#L275'>275</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
<a name='L271'></a><a href='#L271'>271</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">2x</span>
@@ -370,27 +366,27 @@
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">62x</span>
<span class="cline-any cline-yes">67x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">62x</span>
<span class="cline-any cline-yes">67x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">28x</span>
<span class="cline-any cline-yes">33x</span>
<span class="cline-any cline-yes">2x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">26x</span>
<span class="cline-any cline-yes">31x</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">26x</span>
<span class="cline-any cline-yes">26x</span>
<span class="cline-any cline-yes">26x</span>
<span class="cline-any cline-yes">26x</span>
<span class="cline-any cline-yes">31x</span>
<span class="cline-any cline-yes">31x</span>
<span class="cline-any cline-yes">31x</span>
<span class="cline-any cline-yes">31x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">26x</span>
<span class="cline-any cline-yes">31x</span>
<span class="cline-any cline-yes">50x</span>
<span class="cline-any cline-yes">38x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
@@ -401,11 +397,11 @@
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">26x</span>
<span class="cline-any cline-yes">26x</span>
<span class="cline-any cline-yes">26x</span>
<span class="cline-any cline-yes">31x</span>
<span class="cline-any cline-yes">31x</span>
<span class="cline-any cline-yes">31x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">26x</span>
<span class="cline-any cline-yes">31x</span>
<span class="cline-any cline-yes">15x</span>
<span class="cline-any cline-yes">15x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
@@ -442,16 +438,12 @@
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">15x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">15x</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">31x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">26x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">95x</span>
<span class="cline-any cline-yes">100x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
@@ -478,10 +470,10 @@
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">95x</span>
<span class="cline-any cline-yes">100x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">362x</span>
<span class="cline-any cline-yes">367x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
@@ -715,10 +707,6 @@ class VaultIndexer {
(result): result is NonNullable&lt;typeof result&gt; =&gt; result !== null
);
results.push(...validResults);
&nbsp;
<span class="missing-if-branch" title="if path not taken" >I</span>if (results.length &gt;= 50) {
<span class="cstat-no" title="statement not covered" > break;</span>
}
}
&nbsp;
return results;
@@ -892,7 +880,7 @@ export { VaultIndexer };
<div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2026-05-06T20:36:57.831Z
at 2026-05-06T21:42:52.284Z
</div>
<script src="prettify.js"></script>
<script>