@aiready/cli 0.12.20 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/.turbo/turbo-build.log +10 -10
  2. package/.turbo/turbo-lint.log +24 -5
  3. package/.turbo/turbo-test.log +66 -85
  4. package/coverage/base.css +224 -0
  5. package/coverage/block-navigation.js +87 -0
  6. package/coverage/clover.xml +865 -0
  7. package/coverage/coverage-final.json +15 -0
  8. package/coverage/favicon.png +0 -0
  9. package/coverage/index.html +146 -0
  10. package/coverage/prettify.css +1 -0
  11. package/coverage/prettify.js +2 -0
  12. package/coverage/sort-arrow-sprite.png +0 -0
  13. package/coverage/sorter.js +210 -0
  14. package/coverage/src/commands/agent-grounding.ts.html +271 -0
  15. package/coverage/src/commands/ai-signal-clarity.ts.html +253 -0
  16. package/coverage/src/commands/change-amplification.ts.html +94 -0
  17. package/coverage/src/commands/consistency.ts.html +781 -0
  18. package/coverage/src/commands/context.ts.html +871 -0
  19. package/coverage/src/commands/deps-health.ts.html +280 -0
  20. package/coverage/src/commands/doc-drift.ts.html +271 -0
  21. package/coverage/src/commands/index.html +281 -0
  22. package/coverage/src/commands/patterns.ts.html +745 -0
  23. package/coverage/src/commands/scan.ts.html +1393 -0
  24. package/coverage/src/commands/testability.ts.html +304 -0
  25. package/coverage/src/commands/upload.ts.html +466 -0
  26. package/coverage/src/commands/visualize.ts.html +1027 -0
  27. package/coverage/src/index.html +116 -0
  28. package/coverage/src/index.ts.html +1372 -0
  29. package/coverage/src/utils/helpers.ts.html +559 -0
  30. package/coverage/src/utils/index.html +116 -0
  31. package/dist/cli.js +259 -16
  32. package/dist/cli.mjs +259 -15
  33. package/package.json +13 -12
  34. package/src/.aiready/aiready-report-20260308-174006.json +29526 -0
  35. package/src/.aiready/aiready-report-20260310-153526.json +34441 -0
  36. package/src/.aiready/aiready-report-20260310-155555.json +34441 -0
  37. package/src/.aiready/aiready-report-20260310-162403.json +34441 -0
  38. package/src/.aiready/aiready-report-20260310-183821.json +34448 -0
  39. package/src/__tests__/unified.test.ts +95 -0
  40. package/src/cli.ts +86 -0
  41. package/src/commands/__tests__/agent-grounding.test.ts +24 -0
  42. package/src/commands/__tests__/ai-signal-clarity.test.ts +32 -0
  43. package/src/commands/__tests__/consistency.test.ts +97 -0
  44. package/src/commands/__tests__/deps-health.test.ts +26 -0
  45. package/src/commands/__tests__/doc-drift.test.ts +26 -0
  46. package/src/commands/__tests__/extra-commands.test.ts +177 -0
  47. package/src/commands/__tests__/scan.test.ts +151 -0
  48. package/src/commands/__tests__/testability.test.ts +36 -0
  49. package/src/commands/__tests__/upload.test.ts +51 -0
  50. package/src/commands/__tests__/visualize.test.ts +82 -0
  51. package/src/commands/clawmart.ts +162 -0
  52. package/src/commands/index.ts +8 -0
  53. package/src/commands/scan.ts +45 -13
  54. package/src/utils/__tests__/helpers.test.ts +35 -0
  55. package/vitest.config.ts +20 -0
@@ -0,0 +1,1027 @@
1
+
2
+ <!doctype html>
3
+ <html lang="en">
4
+
5
+ <head>
6
+ <title>Code coverage report for src/commands/visualize.ts</title>
7
+ <meta charset="utf-8" />
8
+ <link rel="stylesheet" href="../../prettify.css" />
9
+ <link rel="stylesheet" href="../../base.css" />
10
+ <link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
11
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
12
+ <style type='text/css'>
13
+ .coverage-summary .sorter {
14
+ background-image: url(../../sort-arrow-sprite.png);
15
+ }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <div class='wrapper'>
21
+ <div class='pad1'>
22
+ <h1><a href="../../index.html">All files</a> / <a href="index.html">src/commands</a> visualize.ts</h1>
23
+ <div class='clearfix'>
24
+
25
+ <div class='fl pad1y space-right2'>
26
+ <span class="strong">30.53% </span>
27
+ <span class="quiet">Statements</span>
28
+ <span class='fraction'>40/131</span>
29
+ </div>
30
+
31
+
32
+ <div class='fl pad1y space-right2'>
33
+ <span class="strong">35.93% </span>
34
+ <span class="quiet">Branches</span>
35
+ <span class='fraction'>23/64</span>
36
+ </div>
37
+
38
+
39
+ <div class='fl pad1y space-right2'>
40
+ <span class="strong">14.28% </span>
41
+ <span class="quiet">Functions</span>
42
+ <span class='fraction'>1/7</span>
43
+ </div>
44
+
45
+
46
+ <div class='fl pad1y space-right2'>
47
+ <span class="strong">31% </span>
48
+ <span class="quiet">Lines</span>
49
+ <span class='fraction'>40/129</span>
50
+ </div>
51
+
52
+
53
+ </div>
54
+ <p class="quiet">
55
+ Press <em>n</em> or <em>j</em> to go to the next uncovered block, <em>b</em>, <em>p</em> or <em>k</em> for the previous block.
56
+ </p>
57
+ <template id="filterTemplate">
58
+ <div class="quiet">
59
+ Filter:
60
+ <input type="search" id="fileSearch">
61
+ </div>
62
+ </template>
63
+ </div>
64
+ <div class='status-line low'></div>
65
+ <pre><table class="coverage">
66
+ <tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a>
67
+ <a name='L2'></a><a href='#L2'>2</a>
68
+ <a name='L3'></a><a href='#L3'>3</a>
69
+ <a name='L4'></a><a href='#L4'>4</a>
70
+ <a name='L5'></a><a href='#L5'>5</a>
71
+ <a name='L6'></a><a href='#L6'>6</a>
72
+ <a name='L7'></a><a href='#L7'>7</a>
73
+ <a name='L8'></a><a href='#L8'>8</a>
74
+ <a name='L9'></a><a href='#L9'>9</a>
75
+ <a name='L10'></a><a href='#L10'>10</a>
76
+ <a name='L11'></a><a href='#L11'>11</a>
77
+ <a name='L12'></a><a href='#L12'>12</a>
78
+ <a name='L13'></a><a href='#L13'>13</a>
79
+ <a name='L14'></a><a href='#L14'>14</a>
80
+ <a name='L15'></a><a href='#L15'>15</a>
81
+ <a name='L16'></a><a href='#L16'>16</a>
82
+ <a name='L17'></a><a href='#L17'>17</a>
83
+ <a name='L18'></a><a href='#L18'>18</a>
84
+ <a name='L19'></a><a href='#L19'>19</a>
85
+ <a name='L20'></a><a href='#L20'>20</a>
86
+ <a name='L21'></a><a href='#L21'>21</a>
87
+ <a name='L22'></a><a href='#L22'>22</a>
88
+ <a name='L23'></a><a href='#L23'>23</a>
89
+ <a name='L24'></a><a href='#L24'>24</a>
90
+ <a name='L25'></a><a href='#L25'>25</a>
91
+ <a name='L26'></a><a href='#L26'>26</a>
92
+ <a name='L27'></a><a href='#L27'>27</a>
93
+ <a name='L28'></a><a href='#L28'>28</a>
94
+ <a name='L29'></a><a href='#L29'>29</a>
95
+ <a name='L30'></a><a href='#L30'>30</a>
96
+ <a name='L31'></a><a href='#L31'>31</a>
97
+ <a name='L32'></a><a href='#L32'>32</a>
98
+ <a name='L33'></a><a href='#L33'>33</a>
99
+ <a name='L34'></a><a href='#L34'>34</a>
100
+ <a name='L35'></a><a href='#L35'>35</a>
101
+ <a name='L36'></a><a href='#L36'>36</a>
102
+ <a name='L37'></a><a href='#L37'>37</a>
103
+ <a name='L38'></a><a href='#L38'>38</a>
104
+ <a name='L39'></a><a href='#L39'>39</a>
105
+ <a name='L40'></a><a href='#L40'>40</a>
106
+ <a name='L41'></a><a href='#L41'>41</a>
107
+ <a name='L42'></a><a href='#L42'>42</a>
108
+ <a name='L43'></a><a href='#L43'>43</a>
109
+ <a name='L44'></a><a href='#L44'>44</a>
110
+ <a name='L45'></a><a href='#L45'>45</a>
111
+ <a name='L46'></a><a href='#L46'>46</a>
112
+ <a name='L47'></a><a href='#L47'>47</a>
113
+ <a name='L48'></a><a href='#L48'>48</a>
114
+ <a name='L49'></a><a href='#L49'>49</a>
115
+ <a name='L50'></a><a href='#L50'>50</a>
116
+ <a name='L51'></a><a href='#L51'>51</a>
117
+ <a name='L52'></a><a href='#L52'>52</a>
118
+ <a name='L53'></a><a href='#L53'>53</a>
119
+ <a name='L54'></a><a href='#L54'>54</a>
120
+ <a name='L55'></a><a href='#L55'>55</a>
121
+ <a name='L56'></a><a href='#L56'>56</a>
122
+ <a name='L57'></a><a href='#L57'>57</a>
123
+ <a name='L58'></a><a href='#L58'>58</a>
124
+ <a name='L59'></a><a href='#L59'>59</a>
125
+ <a name='L60'></a><a href='#L60'>60</a>
126
+ <a name='L61'></a><a href='#L61'>61</a>
127
+ <a name='L62'></a><a href='#L62'>62</a>
128
+ <a name='L63'></a><a href='#L63'>63</a>
129
+ <a name='L64'></a><a href='#L64'>64</a>
130
+ <a name='L65'></a><a href='#L65'>65</a>
131
+ <a name='L66'></a><a href='#L66'>66</a>
132
+ <a name='L67'></a><a href='#L67'>67</a>
133
+ <a name='L68'></a><a href='#L68'>68</a>
134
+ <a name='L69'></a><a href='#L69'>69</a>
135
+ <a name='L70'></a><a href='#L70'>70</a>
136
+ <a name='L71'></a><a href='#L71'>71</a>
137
+ <a name='L72'></a><a href='#L72'>72</a>
138
+ <a name='L73'></a><a href='#L73'>73</a>
139
+ <a name='L74'></a><a href='#L74'>74</a>
140
+ <a name='L75'></a><a href='#L75'>75</a>
141
+ <a name='L76'></a><a href='#L76'>76</a>
142
+ <a name='L77'></a><a href='#L77'>77</a>
143
+ <a name='L78'></a><a href='#L78'>78</a>
144
+ <a name='L79'></a><a href='#L79'>79</a>
145
+ <a name='L80'></a><a href='#L80'>80</a>
146
+ <a name='L81'></a><a href='#L81'>81</a>
147
+ <a name='L82'></a><a href='#L82'>82</a>
148
+ <a name='L83'></a><a href='#L83'>83</a>
149
+ <a name='L84'></a><a href='#L84'>84</a>
150
+ <a name='L85'></a><a href='#L85'>85</a>
151
+ <a name='L86'></a><a href='#L86'>86</a>
152
+ <a name='L87'></a><a href='#L87'>87</a>
153
+ <a name='L88'></a><a href='#L88'>88</a>
154
+ <a name='L89'></a><a href='#L89'>89</a>
155
+ <a name='L90'></a><a href='#L90'>90</a>
156
+ <a name='L91'></a><a href='#L91'>91</a>
157
+ <a name='L92'></a><a href='#L92'>92</a>
158
+ <a name='L93'></a><a href='#L93'>93</a>
159
+ <a name='L94'></a><a href='#L94'>94</a>
160
+ <a name='L95'></a><a href='#L95'>95</a>
161
+ <a name='L96'></a><a href='#L96'>96</a>
162
+ <a name='L97'></a><a href='#L97'>97</a>
163
+ <a name='L98'></a><a href='#L98'>98</a>
164
+ <a name='L99'></a><a href='#L99'>99</a>
165
+ <a name='L100'></a><a href='#L100'>100</a>
166
+ <a name='L101'></a><a href='#L101'>101</a>
167
+ <a name='L102'></a><a href='#L102'>102</a>
168
+ <a name='L103'></a><a href='#L103'>103</a>
169
+ <a name='L104'></a><a href='#L104'>104</a>
170
+ <a name='L105'></a><a href='#L105'>105</a>
171
+ <a name='L106'></a><a href='#L106'>106</a>
172
+ <a name='L107'></a><a href='#L107'>107</a>
173
+ <a name='L108'></a><a href='#L108'>108</a>
174
+ <a name='L109'></a><a href='#L109'>109</a>
175
+ <a name='L110'></a><a href='#L110'>110</a>
176
+ <a name='L111'></a><a href='#L111'>111</a>
177
+ <a name='L112'></a><a href='#L112'>112</a>
178
+ <a name='L113'></a><a href='#L113'>113</a>
179
+ <a name='L114'></a><a href='#L114'>114</a>
180
+ <a name='L115'></a><a href='#L115'>115</a>
181
+ <a name='L116'></a><a href='#L116'>116</a>
182
+ <a name='L117'></a><a href='#L117'>117</a>
183
+ <a name='L118'></a><a href='#L118'>118</a>
184
+ <a name='L119'></a><a href='#L119'>119</a>
185
+ <a name='L120'></a><a href='#L120'>120</a>
186
+ <a name='L121'></a><a href='#L121'>121</a>
187
+ <a name='L122'></a><a href='#L122'>122</a>
188
+ <a name='L123'></a><a href='#L123'>123</a>
189
+ <a name='L124'></a><a href='#L124'>124</a>
190
+ <a name='L125'></a><a href='#L125'>125</a>
191
+ <a name='L126'></a><a href='#L126'>126</a>
192
+ <a name='L127'></a><a href='#L127'>127</a>
193
+ <a name='L128'></a><a href='#L128'>128</a>
194
+ <a name='L129'></a><a href='#L129'>129</a>
195
+ <a name='L130'></a><a href='#L130'>130</a>
196
+ <a name='L131'></a><a href='#L131'>131</a>
197
+ <a name='L132'></a><a href='#L132'>132</a>
198
+ <a name='L133'></a><a href='#L133'>133</a>
199
+ <a name='L134'></a><a href='#L134'>134</a>
200
+ <a name='L135'></a><a href='#L135'>135</a>
201
+ <a name='L136'></a><a href='#L136'>136</a>
202
+ <a name='L137'></a><a href='#L137'>137</a>
203
+ <a name='L138'></a><a href='#L138'>138</a>
204
+ <a name='L139'></a><a href='#L139'>139</a>
205
+ <a name='L140'></a><a href='#L140'>140</a>
206
+ <a name='L141'></a><a href='#L141'>141</a>
207
+ <a name='L142'></a><a href='#L142'>142</a>
208
+ <a name='L143'></a><a href='#L143'>143</a>
209
+ <a name='L144'></a><a href='#L144'>144</a>
210
+ <a name='L145'></a><a href='#L145'>145</a>
211
+ <a name='L146'></a><a href='#L146'>146</a>
212
+ <a name='L147'></a><a href='#L147'>147</a>
213
+ <a name='L148'></a><a href='#L148'>148</a>
214
+ <a name='L149'></a><a href='#L149'>149</a>
215
+ <a name='L150'></a><a href='#L150'>150</a>
216
+ <a name='L151'></a><a href='#L151'>151</a>
217
+ <a name='L152'></a><a href='#L152'>152</a>
218
+ <a name='L153'></a><a href='#L153'>153</a>
219
+ <a name='L154'></a><a href='#L154'>154</a>
220
+ <a name='L155'></a><a href='#L155'>155</a>
221
+ <a name='L156'></a><a href='#L156'>156</a>
222
+ <a name='L157'></a><a href='#L157'>157</a>
223
+ <a name='L158'></a><a href='#L158'>158</a>
224
+ <a name='L159'></a><a href='#L159'>159</a>
225
+ <a name='L160'></a><a href='#L160'>160</a>
226
+ <a name='L161'></a><a href='#L161'>161</a>
227
+ <a name='L162'></a><a href='#L162'>162</a>
228
+ <a name='L163'></a><a href='#L163'>163</a>
229
+ <a name='L164'></a><a href='#L164'>164</a>
230
+ <a name='L165'></a><a href='#L165'>165</a>
231
+ <a name='L166'></a><a href='#L166'>166</a>
232
+ <a name='L167'></a><a href='#L167'>167</a>
233
+ <a name='L168'></a><a href='#L168'>168</a>
234
+ <a name='L169'></a><a href='#L169'>169</a>
235
+ <a name='L170'></a><a href='#L170'>170</a>
236
+ <a name='L171'></a><a href='#L171'>171</a>
237
+ <a name='L172'></a><a href='#L172'>172</a>
238
+ <a name='L173'></a><a href='#L173'>173</a>
239
+ <a name='L174'></a><a href='#L174'>174</a>
240
+ <a name='L175'></a><a href='#L175'>175</a>
241
+ <a name='L176'></a><a href='#L176'>176</a>
242
+ <a name='L177'></a><a href='#L177'>177</a>
243
+ <a name='L178'></a><a href='#L178'>178</a>
244
+ <a name='L179'></a><a href='#L179'>179</a>
245
+ <a name='L180'></a><a href='#L180'>180</a>
246
+ <a name='L181'></a><a href='#L181'>181</a>
247
+ <a name='L182'></a><a href='#L182'>182</a>
248
+ <a name='L183'></a><a href='#L183'>183</a>
249
+ <a name='L184'></a><a href='#L184'>184</a>
250
+ <a name='L185'></a><a href='#L185'>185</a>
251
+ <a name='L186'></a><a href='#L186'>186</a>
252
+ <a name='L187'></a><a href='#L187'>187</a>
253
+ <a name='L188'></a><a href='#L188'>188</a>
254
+ <a name='L189'></a><a href='#L189'>189</a>
255
+ <a name='L190'></a><a href='#L190'>190</a>
256
+ <a name='L191'></a><a href='#L191'>191</a>
257
+ <a name='L192'></a><a href='#L192'>192</a>
258
+ <a name='L193'></a><a href='#L193'>193</a>
259
+ <a name='L194'></a><a href='#L194'>194</a>
260
+ <a name='L195'></a><a href='#L195'>195</a>
261
+ <a name='L196'></a><a href='#L196'>196</a>
262
+ <a name='L197'></a><a href='#L197'>197</a>
263
+ <a name='L198'></a><a href='#L198'>198</a>
264
+ <a name='L199'></a><a href='#L199'>199</a>
265
+ <a name='L200'></a><a href='#L200'>200</a>
266
+ <a name='L201'></a><a href='#L201'>201</a>
267
+ <a name='L202'></a><a href='#L202'>202</a>
268
+ <a name='L203'></a><a href='#L203'>203</a>
269
+ <a name='L204'></a><a href='#L204'>204</a>
270
+ <a name='L205'></a><a href='#L205'>205</a>
271
+ <a name='L206'></a><a href='#L206'>206</a>
272
+ <a name='L207'></a><a href='#L207'>207</a>
273
+ <a name='L208'></a><a href='#L208'>208</a>
274
+ <a name='L209'></a><a href='#L209'>209</a>
275
+ <a name='L210'></a><a href='#L210'>210</a>
276
+ <a name='L211'></a><a href='#L211'>211</a>
277
+ <a name='L212'></a><a href='#L212'>212</a>
278
+ <a name='L213'></a><a href='#L213'>213</a>
279
+ <a name='L214'></a><a href='#L214'>214</a>
280
+ <a name='L215'></a><a href='#L215'>215</a>
281
+ <a name='L216'></a><a href='#L216'>216</a>
282
+ <a name='L217'></a><a href='#L217'>217</a>
283
+ <a name='L218'></a><a href='#L218'>218</a>
284
+ <a name='L219'></a><a href='#L219'>219</a>
285
+ <a name='L220'></a><a href='#L220'>220</a>
286
+ <a name='L221'></a><a href='#L221'>221</a>
287
+ <a name='L222'></a><a href='#L222'>222</a>
288
+ <a name='L223'></a><a href='#L223'>223</a>
289
+ <a name='L224'></a><a href='#L224'>224</a>
290
+ <a name='L225'></a><a href='#L225'>225</a>
291
+ <a name='L226'></a><a href='#L226'>226</a>
292
+ <a name='L227'></a><a href='#L227'>227</a>
293
+ <a name='L228'></a><a href='#L228'>228</a>
294
+ <a name='L229'></a><a href='#L229'>229</a>
295
+ <a name='L230'></a><a href='#L230'>230</a>
296
+ <a name='L231'></a><a href='#L231'>231</a>
297
+ <a name='L232'></a><a href='#L232'>232</a>
298
+ <a name='L233'></a><a href='#L233'>233</a>
299
+ <a name='L234'></a><a href='#L234'>234</a>
300
+ <a name='L235'></a><a href='#L235'>235</a>
301
+ <a name='L236'></a><a href='#L236'>236</a>
302
+ <a name='L237'></a><a href='#L237'>237</a>
303
+ <a name='L238'></a><a href='#L238'>238</a>
304
+ <a name='L239'></a><a href='#L239'>239</a>
305
+ <a name='L240'></a><a href='#L240'>240</a>
306
+ <a name='L241'></a><a href='#L241'>241</a>
307
+ <a name='L242'></a><a href='#L242'>242</a>
308
+ <a name='L243'></a><a href='#L243'>243</a>
309
+ <a name='L244'></a><a href='#L244'>244</a>
310
+ <a name='L245'></a><a href='#L245'>245</a>
311
+ <a name='L246'></a><a href='#L246'>246</a>
312
+ <a name='L247'></a><a href='#L247'>247</a>
313
+ <a name='L248'></a><a href='#L248'>248</a>
314
+ <a name='L249'></a><a href='#L249'>249</a>
315
+ <a name='L250'></a><a href='#L250'>250</a>
316
+ <a name='L251'></a><a href='#L251'>251</a>
317
+ <a name='L252'></a><a href='#L252'>252</a>
318
+ <a name='L253'></a><a href='#L253'>253</a>
319
+ <a name='L254'></a><a href='#L254'>254</a>
320
+ <a name='L255'></a><a href='#L255'>255</a>
321
+ <a name='L256'></a><a href='#L256'>256</a>
322
+ <a name='L257'></a><a href='#L257'>257</a>
323
+ <a name='L258'></a><a href='#L258'>258</a>
324
+ <a name='L259'></a><a href='#L259'>259</a>
325
+ <a name='L260'></a><a href='#L260'>260</a>
326
+ <a name='L261'></a><a href='#L261'>261</a>
327
+ <a name='L262'></a><a href='#L262'>262</a>
328
+ <a name='L263'></a><a href='#L263'>263</a>
329
+ <a name='L264'></a><a href='#L264'>264</a>
330
+ <a name='L265'></a><a href='#L265'>265</a>
331
+ <a name='L266'></a><a href='#L266'>266</a>
332
+ <a name='L267'></a><a href='#L267'>267</a>
333
+ <a name='L268'></a><a href='#L268'>268</a>
334
+ <a name='L269'></a><a href='#L269'>269</a>
335
+ <a name='L270'></a><a href='#L270'>270</a>
336
+ <a name='L271'></a><a href='#L271'>271</a>
337
+ <a name='L272'></a><a href='#L272'>272</a>
338
+ <a name='L273'></a><a href='#L273'>273</a>
339
+ <a name='L274'></a><a href='#L274'>274</a>
340
+ <a name='L275'></a><a href='#L275'>275</a>
341
+ <a name='L276'></a><a href='#L276'>276</a>
342
+ <a name='L277'></a><a href='#L277'>277</a>
343
+ <a name='L278'></a><a href='#L278'>278</a>
344
+ <a name='L279'></a><a href='#L279'>279</a>
345
+ <a name='L280'></a><a href='#L280'>280</a>
346
+ <a name='L281'></a><a href='#L281'>281</a>
347
+ <a name='L282'></a><a href='#L282'>282</a>
348
+ <a name='L283'></a><a href='#L283'>283</a>
349
+ <a name='L284'></a><a href='#L284'>284</a>
350
+ <a name='L285'></a><a href='#L285'>285</a>
351
+ <a name='L286'></a><a href='#L286'>286</a>
352
+ <a name='L287'></a><a href='#L287'>287</a>
353
+ <a name='L288'></a><a href='#L288'>288</a>
354
+ <a name='L289'></a><a href='#L289'>289</a>
355
+ <a name='L290'></a><a href='#L290'>290</a>
356
+ <a name='L291'></a><a href='#L291'>291</a>
357
+ <a name='L292'></a><a href='#L292'>292</a>
358
+ <a name='L293'></a><a href='#L293'>293</a>
359
+ <a name='L294'></a><a href='#L294'>294</a>
360
+ <a name='L295'></a><a href='#L295'>295</a>
361
+ <a name='L296'></a><a href='#L296'>296</a>
362
+ <a name='L297'></a><a href='#L297'>297</a>
363
+ <a name='L298'></a><a href='#L298'>298</a>
364
+ <a name='L299'></a><a href='#L299'>299</a>
365
+ <a name='L300'></a><a href='#L300'>300</a>
366
+ <a name='L301'></a><a href='#L301'>301</a>
367
+ <a name='L302'></a><a href='#L302'>302</a>
368
+ <a name='L303'></a><a href='#L303'>303</a>
369
+ <a name='L304'></a><a href='#L304'>304</a>
370
+ <a name='L305'></a><a href='#L305'>305</a>
371
+ <a name='L306'></a><a href='#L306'>306</a>
372
+ <a name='L307'></a><a href='#L307'>307</a>
373
+ <a name='L308'></a><a href='#L308'>308</a>
374
+ <a name='L309'></a><a href='#L309'>309</a>
375
+ <a name='L310'></a><a href='#L310'>310</a>
376
+ <a name='L311'></a><a href='#L311'>311</a>
377
+ <a name='L312'></a><a href='#L312'>312</a>
378
+ <a name='L313'></a><a href='#L313'>313</a>
379
+ <a name='L314'></a><a href='#L314'>314</a>
380
+ <a name='L315'></a><a href='#L315'>315</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
381
+ <span class="cline-any cline-neutral">&nbsp;</span>
382
+ <span class="cline-any cline-neutral">&nbsp;</span>
383
+ <span class="cline-any cline-neutral">&nbsp;</span>
384
+ <span class="cline-any cline-neutral">&nbsp;</span>
385
+ <span class="cline-any cline-neutral">&nbsp;</span>
386
+ <span class="cline-any cline-neutral">&nbsp;</span>
387
+ <span class="cline-any cline-neutral">&nbsp;</span>
388
+ <span class="cline-any cline-neutral">&nbsp;</span>
389
+ <span class="cline-any cline-neutral">&nbsp;</span>
390
+ <span class="cline-any cline-neutral">&nbsp;</span>
391
+ <span class="cline-any cline-neutral">&nbsp;</span>
392
+ <span class="cline-any cline-neutral">&nbsp;</span>
393
+ <span class="cline-any cline-neutral">&nbsp;</span>
394
+ <span class="cline-any cline-neutral">&nbsp;</span>
395
+ <span class="cline-any cline-neutral">&nbsp;</span>
396
+ <span class="cline-any cline-neutral">&nbsp;</span>
397
+ <span class="cline-any cline-neutral">&nbsp;</span>
398
+ <span class="cline-any cline-neutral">&nbsp;</span>
399
+ <span class="cline-any cline-neutral">&nbsp;</span>
400
+ <span class="cline-any cline-neutral">&nbsp;</span>
401
+ <span class="cline-any cline-neutral">&nbsp;</span>
402
+ <span class="cline-any cline-neutral">&nbsp;</span>
403
+ <span class="cline-any cline-neutral">&nbsp;</span>
404
+ <span class="cline-any cline-yes">4x</span>
405
+ <span class="cline-any cline-yes">4x</span>
406
+ <span class="cline-any cline-yes">4x</span>
407
+ <span class="cline-any cline-neutral">&nbsp;</span>
408
+ <span class="cline-any cline-neutral">&nbsp;</span>
409
+ <span class="cline-any cline-neutral">&nbsp;</span>
410
+ <span class="cline-any cline-neutral">&nbsp;</span>
411
+ <span class="cline-any cline-yes">4x</span>
412
+ <span class="cline-any cline-yes">2x</span>
413
+ <span class="cline-any cline-yes">2x</span>
414
+ <span class="cline-any cline-yes">1x</span>
415
+ <span class="cline-any cline-yes">1x</span>
416
+ <span class="cline-any cline-neutral">&nbsp;</span>
417
+ <span class="cline-any cline-neutral">&nbsp;</span>
418
+ <span class="cline-any cline-neutral">&nbsp;</span>
419
+ <span class="cline-any cline-yes">1x</span>
420
+ <span class="cline-any cline-yes">1x</span>
421
+ <span class="cline-any cline-neutral">&nbsp;</span>
422
+ <span class="cline-any cline-neutral">&nbsp;</span>
423
+ <span class="cline-any cline-neutral">&nbsp;</span>
424
+ <span class="cline-any cline-neutral">&nbsp;</span>
425
+ <span class="cline-any cline-yes">1x</span>
426
+ <span class="cline-any cline-neutral">&nbsp;</span>
427
+ <span class="cline-any cline-neutral">&nbsp;</span>
428
+ <span class="cline-any cline-neutral">&nbsp;</span>
429
+ <span class="cline-any cline-yes">3x</span>
430
+ <span class="cline-any cline-yes">3x</span>
431
+ <span class="cline-any cline-neutral">&nbsp;</span>
432
+ <span class="cline-any cline-neutral">&nbsp;</span>
433
+ <span class="cline-any cline-yes">3x</span>
434
+ <span class="cline-any cline-yes">3x</span>
435
+ <span class="cline-any cline-neutral">&nbsp;</span>
436
+ <span class="cline-any cline-yes">3x</span>
437
+ <span class="cline-any cline-yes">3x</span>
438
+ <span class="cline-any cline-yes">3x</span>
439
+ <span class="cline-any cline-yes">3x</span>
440
+ <span class="cline-any cline-no">&nbsp;</span>
441
+ <span class="cline-any cline-neutral">&nbsp;</span>
442
+ <span class="cline-any cline-neutral">&nbsp;</span>
443
+ <span class="cline-any cline-neutral">&nbsp;</span>
444
+ <span class="cline-any cline-neutral">&nbsp;</span>
445
+ <span class="cline-any cline-neutral">&nbsp;</span>
446
+ <span class="cline-any cline-neutral">&nbsp;</span>
447
+ <span class="cline-any cline-neutral">&nbsp;</span>
448
+ <span class="cline-any cline-no">&nbsp;</span>
449
+ <span class="cline-any cline-neutral">&nbsp;</span>
450
+ <span class="cline-any cline-neutral">&nbsp;</span>
451
+ <span class="cline-any cline-neutral">&nbsp;</span>
452
+ <span class="cline-any cline-neutral">&nbsp;</span>
453
+ <span class="cline-any cline-neutral">&nbsp;</span>
454
+ <span class="cline-any cline-yes">3x</span>
455
+ <span class="cline-any cline-yes">3x</span>
456
+ <span class="cline-any cline-neutral">&nbsp;</span>
457
+ <span class="cline-any cline-yes">3x</span>
458
+ <span class="cline-any cline-yes">3x</span>
459
+ <span class="cline-any cline-yes">3x</span>
460
+ <span class="cline-any cline-neutral">&nbsp;</span>
461
+ <span class="cline-any cline-neutral">&nbsp;</span>
462
+ <span class="cline-any cline-yes">3x</span>
463
+ <span class="cline-any cline-yes">4x</span>
464
+ <span class="cline-any cline-neutral">&nbsp;</span>
465
+ <span class="cline-any cline-yes">4x</span>
466
+ <span class="cline-any cline-no">&nbsp;</span>
467
+ <span class="cline-any cline-no">&nbsp;</span>
468
+ <span class="cline-any cline-no">&nbsp;</span>
469
+ <span class="cline-any cline-no">&nbsp;</span>
470
+ <span class="cline-any cline-neutral">&nbsp;</span>
471
+ <span class="cline-any cline-no">&nbsp;</span>
472
+ <span class="cline-any cline-no">&nbsp;</span>
473
+ <span class="cline-any cline-no">&nbsp;</span>
474
+ <span class="cline-any cline-neutral">&nbsp;</span>
475
+ <span class="cline-any cline-neutral">&nbsp;</span>
476
+ <span class="cline-any cline-no">&nbsp;</span>
477
+ <span class="cline-any cline-neutral">&nbsp;</span>
478
+ <span class="cline-any cline-neutral">&nbsp;</span>
479
+ <span class="cline-any cline-neutral">&nbsp;</span>
480
+ <span class="cline-any cline-neutral">&nbsp;</span>
481
+ <span class="cline-any cline-neutral">&nbsp;</span>
482
+ <span class="cline-any cline-neutral">&nbsp;</span>
483
+ <span class="cline-any cline-neutral">&nbsp;</span>
484
+ <span class="cline-any cline-neutral">&nbsp;</span>
485
+ <span class="cline-any cline-neutral">&nbsp;</span>
486
+ <span class="cline-any cline-neutral">&nbsp;</span>
487
+ <span class="cline-any cline-no">&nbsp;</span>
488
+ <span class="cline-any cline-no">&nbsp;</span>
489
+ <span class="cline-any cline-no">&nbsp;</span>
490
+ <span class="cline-any cline-neutral">&nbsp;</span>
491
+ <span class="cline-any cline-neutral">&nbsp;</span>
492
+ <span class="cline-any cline-no">&nbsp;</span>
493
+ <span class="cline-any cline-no">&nbsp;</span>
494
+ <span class="cline-any cline-no">&nbsp;</span>
495
+ <span class="cline-any cline-neutral">&nbsp;</span>
496
+ <span class="cline-any cline-neutral">&nbsp;</span>
497
+ <span class="cline-any cline-no">&nbsp;</span>
498
+ <span class="cline-any cline-no">&nbsp;</span>
499
+ <span class="cline-any cline-neutral">&nbsp;</span>
500
+ <span class="cline-any cline-neutral">&nbsp;</span>
501
+ <span class="cline-any cline-neutral">&nbsp;</span>
502
+ <span class="cline-any cline-no">&nbsp;</span>
503
+ <span class="cline-any cline-no">&nbsp;</span>
504
+ <span class="cline-any cline-no">&nbsp;</span>
505
+ <span class="cline-any cline-neutral">&nbsp;</span>
506
+ <span class="cline-any cline-neutral">&nbsp;</span>
507
+ <span class="cline-any cline-neutral">&nbsp;</span>
508
+ <span class="cline-any cline-neutral">&nbsp;</span>
509
+ <span class="cline-any cline-no">&nbsp;</span>
510
+ <span class="cline-any cline-no">&nbsp;</span>
511
+ <span class="cline-any cline-neutral">&nbsp;</span>
512
+ <span class="cline-any cline-no">&nbsp;</span>
513
+ <span class="cline-any cline-no">&nbsp;</span>
514
+ <span class="cline-any cline-no">&nbsp;</span>
515
+ <span class="cline-any cline-neutral">&nbsp;</span>
516
+ <span class="cline-any cline-no">&nbsp;</span>
517
+ <span class="cline-any cline-neutral">&nbsp;</span>
518
+ <span class="cline-any cline-neutral">&nbsp;</span>
519
+ <span class="cline-any cline-neutral">&nbsp;</span>
520
+ <span class="cline-any cline-neutral">&nbsp;</span>
521
+ <span class="cline-any cline-neutral">&nbsp;</span>
522
+ <span class="cline-any cline-neutral">&nbsp;</span>
523
+ <span class="cline-any cline-neutral">&nbsp;</span>
524
+ <span class="cline-any cline-no">&nbsp;</span>
525
+ <span class="cline-any cline-neutral">&nbsp;</span>
526
+ <span class="cline-any cline-no">&nbsp;</span>
527
+ <span class="cline-any cline-neutral">&nbsp;</span>
528
+ <span class="cline-any cline-no">&nbsp;</span>
529
+ <span class="cline-any cline-neutral">&nbsp;</span>
530
+ <span class="cline-any cline-neutral">&nbsp;</span>
531
+ <span class="cline-any cline-no">&nbsp;</span>
532
+ <span class="cline-any cline-no">&nbsp;</span>
533
+ <span class="cline-any cline-no">&nbsp;</span>
534
+ <span class="cline-any cline-no">&nbsp;</span>
535
+ <span class="cline-any cline-no">&nbsp;</span>
536
+ <span class="cline-any cline-no">&nbsp;</span>
537
+ <span class="cline-any cline-neutral">&nbsp;</span>
538
+ <span class="cline-any cline-no">&nbsp;</span>
539
+ <span class="cline-any cline-neutral">&nbsp;</span>
540
+ <span class="cline-any cline-neutral">&nbsp;</span>
541
+ <span class="cline-any cline-neutral">&nbsp;</span>
542
+ <span class="cline-any cline-neutral">&nbsp;</span>
543
+ <span class="cline-any cline-no">&nbsp;</span>
544
+ <span class="cline-any cline-neutral">&nbsp;</span>
545
+ <span class="cline-any cline-neutral">&nbsp;</span>
546
+ <span class="cline-any cline-no">&nbsp;</span>
547
+ <span class="cline-any cline-no">&nbsp;</span>
548
+ <span class="cline-any cline-no">&nbsp;</span>
549
+ <span class="cline-any cline-no">&nbsp;</span>
550
+ <span class="cline-any cline-neutral">&nbsp;</span>
551
+ <span class="cline-any cline-neutral">&nbsp;</span>
552
+ <span class="cline-any cline-no">&nbsp;</span>
553
+ <span class="cline-any cline-neutral">&nbsp;</span>
554
+ <span class="cline-any cline-neutral">&nbsp;</span>
555
+ <span class="cline-any cline-neutral">&nbsp;</span>
556
+ <span class="cline-any cline-neutral">&nbsp;</span>
557
+ <span class="cline-any cline-no">&nbsp;</span>
558
+ <span class="cline-any cline-neutral">&nbsp;</span>
559
+ <span class="cline-any cline-neutral">&nbsp;</span>
560
+ <span class="cline-any cline-neutral">&nbsp;</span>
561
+ <span class="cline-any cline-neutral">&nbsp;</span>
562
+ <span class="cline-any cline-neutral">&nbsp;</span>
563
+ <span class="cline-any cline-no">&nbsp;</span>
564
+ <span class="cline-any cline-no">&nbsp;</span>
565
+ <span class="cline-any cline-no">&nbsp;</span>
566
+ <span class="cline-any cline-neutral">&nbsp;</span>
567
+ <span class="cline-any cline-no">&nbsp;</span>
568
+ <span class="cline-any cline-neutral">&nbsp;</span>
569
+ <span class="cline-any cline-no">&nbsp;</span>
570
+ <span class="cline-any cline-no">&nbsp;</span>
571
+ <span class="cline-any cline-neutral">&nbsp;</span>
572
+ <span class="cline-any cline-no">&nbsp;</span>
573
+ <span class="cline-any cline-neutral">&nbsp;</span>
574
+ <span class="cline-any cline-no">&nbsp;</span>
575
+ <span class="cline-any cline-neutral">&nbsp;</span>
576
+ <span class="cline-any cline-no">&nbsp;</span>
577
+ <span class="cline-any cline-no">&nbsp;</span>
578
+ <span class="cline-any cline-no">&nbsp;</span>
579
+ <span class="cline-any cline-no">&nbsp;</span>
580
+ <span class="cline-any cline-no">&nbsp;</span>
581
+ <span class="cline-any cline-neutral">&nbsp;</span>
582
+ <span class="cline-any cline-no">&nbsp;</span>
583
+ <span class="cline-any cline-neutral">&nbsp;</span>
584
+ <span class="cline-any cline-neutral">&nbsp;</span>
585
+ <span class="cline-any cline-neutral">&nbsp;</span>
586
+ <span class="cline-any cline-neutral">&nbsp;</span>
587
+ <span class="cline-any cline-no">&nbsp;</span>
588
+ <span class="cline-any cline-neutral">&nbsp;</span>
589
+ <span class="cline-any cline-neutral">&nbsp;</span>
590
+ <span class="cline-any cline-no">&nbsp;</span>
591
+ <span class="cline-any cline-neutral">&nbsp;</span>
592
+ <span class="cline-any cline-neutral">&nbsp;</span>
593
+ <span class="cline-any cline-no">&nbsp;</span>
594
+ <span class="cline-any cline-no">&nbsp;</span>
595
+ <span class="cline-any cline-neutral">&nbsp;</span>
596
+ <span class="cline-any cline-neutral">&nbsp;</span>
597
+ <span class="cline-any cline-no">&nbsp;</span>
598
+ <span class="cline-any cline-neutral">&nbsp;</span>
599
+ <span class="cline-any cline-neutral">&nbsp;</span>
600
+ <span class="cline-any cline-neutral">&nbsp;</span>
601
+ <span class="cline-any cline-neutral">&nbsp;</span>
602
+ <span class="cline-any cline-yes">3x</span>
603
+ <span class="cline-any cline-yes">3x</span>
604
+ <span class="cline-any cline-yes">3x</span>
605
+ <span class="cline-any cline-yes">3x</span>
606
+ <span class="cline-any cline-yes">4x</span>
607
+ <span class="cline-any cline-yes">4x</span>
608
+ <span class="cline-any cline-neutral">&nbsp;</span>
609
+ <span class="cline-any cline-yes">4x</span>
610
+ <span class="cline-any cline-neutral">&nbsp;</span>
611
+ <span class="cline-any cline-yes">1x</span>
612
+ <span class="cline-any cline-neutral">&nbsp;</span>
613
+ <span class="cline-any cline-neutral">&nbsp;</span>
614
+ <span class="cline-any cline-neutral">&nbsp;</span>
615
+ <span class="cline-any cline-neutral">&nbsp;</span>
616
+ <span class="cline-any cline-neutral">&nbsp;</span>
617
+ <span class="cline-any cline-yes">1x</span>
618
+ <span class="cline-any cline-no">&nbsp;</span>
619
+ <span class="cline-any cline-no">&nbsp;</span>
620
+ <span class="cline-any cline-no">&nbsp;</span>
621
+ <span class="cline-any cline-no">&nbsp;</span>
622
+ <span class="cline-any cline-neutral">&nbsp;</span>
623
+ <span class="cline-any cline-no">&nbsp;</span>
624
+ <span class="cline-any cline-no">&nbsp;</span>
625
+ <span class="cline-any cline-no">&nbsp;</span>
626
+ <span class="cline-any cline-no">&nbsp;</span>
627
+ <span class="cline-any cline-no">&nbsp;</span>
628
+ <span class="cline-any cline-no">&nbsp;</span>
629
+ <span class="cline-any cline-neutral">&nbsp;</span>
630
+ <span class="cline-any cline-neutral">&nbsp;</span>
631
+ <span class="cline-any cline-no">&nbsp;</span>
632
+ <span class="cline-any cline-no">&nbsp;</span>
633
+ <span class="cline-any cline-neutral">&nbsp;</span>
634
+ <span class="cline-any cline-no">&nbsp;</span>
635
+ <span class="cline-any cline-no">&nbsp;</span>
636
+ <span class="cline-any cline-neutral">&nbsp;</span>
637
+ <span class="cline-any cline-no">&nbsp;</span>
638
+ <span class="cline-any cline-no">&nbsp;</span>
639
+ <span class="cline-any cline-no">&nbsp;</span>
640
+ <span class="cline-any cline-neutral">&nbsp;</span>
641
+ <span class="cline-any cline-neutral">&nbsp;</span>
642
+ <span class="cline-any cline-neutral">&nbsp;</span>
643
+ <span class="cline-any cline-no">&nbsp;</span>
644
+ <span class="cline-any cline-no">&nbsp;</span>
645
+ <span class="cline-any cline-no">&nbsp;</span>
646
+ <span class="cline-any cline-neutral">&nbsp;</span>
647
+ <span class="cline-any cline-neutral">&nbsp;</span>
648
+ <span class="cline-any cline-no">&nbsp;</span>
649
+ <span class="cline-any cline-neutral">&nbsp;</span>
650
+ <span class="cline-any cline-neutral">&nbsp;</span>
651
+ <span class="cline-any cline-no">&nbsp;</span>
652
+ <span class="cline-any cline-no">&nbsp;</span>
653
+ <span class="cline-any cline-no">&nbsp;</span>
654
+ <span class="cline-any cline-neutral">&nbsp;</span>
655
+ <span class="cline-any cline-neutral">&nbsp;</span>
656
+ <span class="cline-any cline-no">&nbsp;</span>
657
+ <span class="cline-any cline-neutral">&nbsp;</span>
658
+ <span class="cline-any cline-yes">1x</span>
659
+ <span class="cline-any cline-yes">1x</span>
660
+ <span class="cline-any cline-neutral">&nbsp;</span>
661
+ <span class="cline-any cline-neutral">&nbsp;</span>
662
+ <span class="cline-any cline-neutral">&nbsp;</span>
663
+ <span class="cline-any cline-no">&nbsp;</span>
664
+ <span class="cline-any cline-neutral">&nbsp;</span>
665
+ <span class="cline-any cline-neutral">&nbsp;</span>
666
+ <span class="cline-any cline-neutral">&nbsp;</span>
667
+ <span class="cline-any cline-yes">1x</span>
668
+ <span class="cline-any cline-neutral">&nbsp;</span>
669
+ <span class="cline-any cline-neutral">&nbsp;</span>
670
+ <span class="cline-any cline-neutral">&nbsp;</span>
671
+ <span class="cline-any cline-neutral">&nbsp;</span>
672
+ <span class="cline-any cline-neutral">&nbsp;</span>
673
+ <span class="cline-any cline-neutral">&nbsp;</span>
674
+ <span class="cline-any cline-neutral">&nbsp;</span>
675
+ <span class="cline-any cline-neutral">&nbsp;</span>
676
+ <span class="cline-any cline-neutral">&nbsp;</span>
677
+ <span class="cline-any cline-neutral">&nbsp;</span>
678
+ <span class="cline-any cline-neutral">&nbsp;</span>
679
+ <span class="cline-any cline-neutral">&nbsp;</span>
680
+ <span class="cline-any cline-neutral">&nbsp;</span>
681
+ <span class="cline-any cline-neutral">&nbsp;</span>
682
+ <span class="cline-any cline-neutral">&nbsp;</span>
683
+ <span class="cline-any cline-neutral">&nbsp;</span>
684
+ <span class="cline-any cline-neutral">&nbsp;</span>
685
+ <span class="cline-any cline-yes">1x</span>
686
+ <span class="cline-any cline-neutral">&nbsp;</span>
687
+ <span class="cline-any cline-neutral">&nbsp;</span>
688
+ <span class="cline-any cline-neutral">&nbsp;</span>
689
+ <span class="cline-any cline-neutral">&nbsp;</span>
690
+ <span class="cline-any cline-neutral">&nbsp;</span>
691
+ <span class="cline-any cline-neutral">&nbsp;</span>
692
+ <span class="cline-any cline-neutral">&nbsp;</span>
693
+ <span class="cline-any cline-neutral">&nbsp;</span>
694
+ <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">/**
695
+ * Visualize command - Generate interactive visualization from an AIReady report
696
+ */
697
+ &nbsp;
698
+ import chalk from 'chalk';
699
+ import { writeFileSync, readFileSync, existsSync, copyFileSync } from 'fs';
700
+ import { resolve as resolvePath } from 'path';
701
+ import { spawn } from 'child_process';
702
+ import { handleCLIError } from '@aiready/core';
703
+ import { generateHTML } from '@aiready/core';
704
+ import { findLatestScanReport } from '../utils/helpers';
705
+ &nbsp;
706
+ interface VisualizeOptions {
707
+ report?: string;
708
+ output?: string;
709
+ open?: boolean;
710
+ serve?: boolean | number;
711
+ dev?: boolean;
712
+ }
713
+ &nbsp;
714
+ export async function visualizeAction(
715
+ directory: string,
716
+ options: VisualizeOptions
717
+ ) {
718
+ try {
719
+ const dirPath = resolvePath(process.cwd(), directory || <span class="branch-1 cbranch-no" title="branch not covered" >'.')</span>;
720
+ let reportPath = options.report
721
+ ? resolvePath(dirPath, options.report)
722
+ : null;
723
+ &nbsp;
724
+ // If report not provided or not found, try to find latest scan report
725
+ if (!reportPath || !existsSync(reportPath)) {
726
+ const latestScan = findLatestScanReport(dirPath);
727
+ if (latestScan) {
728
+ reportPath = latestScan;
729
+ console.log(
730
+ chalk.dim(`Found latest report: ${latestScan.split('/').pop()}`)
731
+ );
732
+ } else {
733
+ console.error(chalk.red('❌ No AI readiness report found'));
734
+ console.log(
735
+ chalk.dim(
736
+ `\nGenerate a report with:\n aiready scan --output json\n\nOr specify a custom report:\n aiready visualise --report &lt;path-to-report.json&gt;`
737
+ )
738
+ );
739
+ return;
740
+ }
741
+ }
742
+ &nbsp;
743
+ const raw = readFileSync(reportPath, 'utf8');
744
+ const report = JSON.parse(raw);
745
+ &nbsp;
746
+ // Load config to extract graph caps
747
+ const configPath = resolvePath(dirPath, 'aiready.json');
748
+ let graphConfig = { maxNodes: 400, maxEdges: 600 };
749
+ &nbsp;
750
+ <span class="missing-if-branch" title="else path not taken" >E</span>if (existsSync(configPath)) {
751
+ try {
752
+ const rawConfig = JSON.parse(readFileSync(configPath, 'utf8'));
753
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (rawConfig.visualizer?.graph) {
754
+ <span class="cstat-no" title="statement not covered" > graphConfig = {</span>
755
+ maxNodes:
756
+ rawConfig.visualizer.graph.maxNodes ?? graphConfig.maxNodes,
757
+ maxEdges:
758
+ rawConfig.visualizer.graph.maxEdges ?? graphConfig.maxEdges,
759
+ };
760
+ }
761
+ } catch (e) {
762
+ <span class="cstat-no" title="statement not covered" > void e;</span>
763
+ // Silently ignore parse errors and use defaults
764
+ }
765
+ }
766
+ &nbsp;
767
+ // Store config in env for vite middleware to pass to client
768
+ const envVisualizerConfig = JSON.stringify(graphConfig);
769
+ process.env.AIREADY_VISUALIZER_CONFIG = envVisualizerConfig;
770
+ &nbsp;
771
+ console.log('Building graph from report...');
772
+ const { GraphBuilder } = await import('@aiready/visualizer/graph');
773
+ const graph = GraphBuilder.buildFromReport(report, dirPath);
774
+ &nbsp;
775
+ // Check if --dev mode is requested and available
776
+ let useDevMode = options.dev || false;
777
+ let devServerStarted = false;
778
+ &nbsp;
779
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (useDevMode) {
780
+ <span class="cstat-no" title="statement not covered" > try {</span>
781
+ const <span class="cstat-no" title="statement not covered" >localWebDir = resolvePath(dirPath, 'packages/visualizer');</span>
782
+ let webDir = <span class="cstat-no" title="statement not covered" >'';</span>
783
+ let visualizerAvailable = <span class="cstat-no" title="statement not covered" >false;</span>
784
+ &nbsp;
785
+ <span class="cstat-no" title="statement not covered" > if (existsSync(localWebDir)) {</span>
786
+ <span class="cstat-no" title="statement not covered" > webDir = localWebDir;</span>
787
+ <span class="cstat-no" title="statement not covered" > visualizerAvailable = true;</span>
788
+ } else {
789
+ // Try to resolve installed @aiready/visualizer package from node_modules
790
+ const nodemodulesLocations: string[] = <span class="cstat-no" title="statement not covered" >[</span>
791
+ resolvePath(dirPath, 'node_modules', '@aiready', 'visualizer'),
792
+ resolvePath(
793
+ process.cwd(),
794
+ 'node_modules',
795
+ '@aiready',
796
+ 'visualizer'
797
+ ),
798
+ ];
799
+ &nbsp;
800
+ // Walk up directory tree to find node_modules in parent directories
801
+ let currentDir = <span class="cstat-no" title="statement not covered" >dirPath;</span>
802
+ <span class="cstat-no" title="statement not covered" > while (currentDir !== '/' &amp;&amp; currentDir !== '.') {</span>
803
+ <span class="cstat-no" title="statement not covered" > nodemodulesLocations.push(</span>
804
+ resolvePath(currentDir, 'node_modules', '@aiready', 'visualizer')
805
+ );
806
+ const <span class="cstat-no" title="statement not covered" >parent = resolvePath(currentDir, '..');</span>
807
+ <span class="cstat-no" title="statement not covered" > if (parent === currentDir) <span class="cstat-no" title="statement not covered" >break;</span></span>
808
+ <span class="cstat-no" title="statement not covered" > currentDir = parent;</span>
809
+ }
810
+ &nbsp;
811
+ <span class="cstat-no" title="statement not covered" > for (const location of nodemodulesLocations) {</span>
812
+ <span class="cstat-no" title="statement not covered" > if (</span>
813
+ existsSync(location) &amp;&amp;
814
+ existsSync(resolvePath(location, 'package.json'))
815
+ ) {
816
+ <span class="cstat-no" title="statement not covered" > webDir = location;</span>
817
+ <span class="cstat-no" title="statement not covered" > visualizerAvailable = true;</span>
818
+ <span class="cstat-no" title="statement not covered" > break;</span>
819
+ }
820
+ }
821
+ &nbsp;
822
+ // Fallback: try require.resolve
823
+ <span class="cstat-no" title="statement not covered" > if (!visualizerAvailable) {</span>
824
+ <span class="cstat-no" title="statement not covered" > try {</span>
825
+ const vizPkgPath =
826
+ <span class="cstat-no" title="statement not covered" > require.resolve('@aiready/visualizer/package.json');</span>
827
+ <span class="cstat-no" title="statement not covered" > webDir = resolvePath(vizPkgPath, '..');</span>
828
+ <span class="cstat-no" title="statement not covered" > visualizerAvailable = true;</span>
829
+ } catch (err) {
830
+ <span class="cstat-no" title="statement not covered" > void err;</span>
831
+ // Visualizer not found
832
+ }
833
+ }
834
+ }
835
+ &nbsp;
836
+ // Check if web directory with vite config exists (required for dev mode)
837
+ const webViteConfigExists =
838
+ <span class="cstat-no" title="statement not covered" > webDir &amp;&amp; existsSync(resolvePath(webDir, 'web', 'vite.config.ts'));</span>
839
+ &nbsp;
840
+ <span class="cstat-no" title="statement not covered" > if (visualizerAvailable &amp;&amp; webViteConfigExists) {</span>
841
+ // Dev mode is available - start Vite dev server
842
+ const spawnCwd = <span class="cstat-no" title="statement not covered" >webDir!;</span>
843
+ &nbsp;
844
+ // Inline report watcher: copy report to web/report-data.json and watch for changes
845
+ const { watch } = <span class="cstat-no" title="statement not covered" >await import('fs');</span>
846
+ const copyReportToViz = <span class="cstat-no" title="statement not covered" ><span class="fstat-no" title="function not covered" >() =&gt; {</span></span>
847
+ <span class="cstat-no" title="statement not covered" > try {</span>
848
+ const <span class="cstat-no" title="statement not covered" >destPath = resolvePath(spawnCwd, 'web', 'report-data.json');</span>
849
+ <span class="cstat-no" title="statement not covered" > copyFileSync(reportPath!, destPath);</span>
850
+ <span class="cstat-no" title="statement not covered" > console.log(`📋 Report synced to ${destPath}`);</span>
851
+ } catch (e) {
852
+ <span class="cstat-no" title="statement not covered" > console.error('Failed to sync report:', e);</span>
853
+ }
854
+ };
855
+ &nbsp;
856
+ // Initial copy
857
+ <span class="cstat-no" title="statement not covered" > copyReportToViz();</span>
858
+ &nbsp;
859
+ // Watch source report for changes
860
+ let watchTimeout: NodeJS.Timeout | null = <span class="cstat-no" title="statement not covered" >null;</span>
861
+ const reportWatcher = <span class="cstat-no" title="statement not covered" >watch(reportPath, <span class="fstat-no" title="function not covered" >() =&gt; {</span></span>
862
+ <span class="cstat-no" title="statement not covered" > if (watchTimeout) <span class="cstat-no" title="statement not covered" >clearTimeout(watchTimeout);</span></span>
863
+ <span class="cstat-no" title="statement not covered" > watchTimeout = setTimeout(copyReportToViz, 100);</span>
864
+ });
865
+ &nbsp;
866
+ const envForSpawn = <span class="cstat-no" title="statement not covered" >{</span>
867
+ ...process.env,
868
+ AIREADY_REPORT_PATH: reportPath,
869
+ AIREADY_VISUALIZER_CONFIG: envVisualizerConfig,
870
+ };
871
+ const <span class="cstat-no" title="statement not covered" >vite = spawn('pnpm', ['run', 'dev:web'], {</span>
872
+ cwd: spawnCwd,
873
+ stdio: 'inherit',
874
+ shell: true,
875
+ env: envForSpawn,
876
+ });
877
+ const onExit = <span class="cstat-no" title="statement not covered" ><span class="fstat-no" title="function not covered" >() =&gt; {</span></span>
878
+ <span class="cstat-no" title="statement not covered" > try {</span>
879
+ <span class="cstat-no" title="statement not covered" > reportWatcher.close();</span>
880
+ } catch (err) {
881
+ <span class="cstat-no" title="statement not covered" > void err;</span>
882
+ }
883
+ <span class="cstat-no" title="statement not covered" > try {</span>
884
+ <span class="cstat-no" title="statement not covered" > vite.kill();</span>
885
+ } catch (err) {
886
+ <span class="cstat-no" title="statement not covered" > void err;</span>
887
+ }
888
+ <span class="cstat-no" title="statement not covered" > process.exit(0);</span>
889
+ };
890
+ <span class="cstat-no" title="statement not covered" > process.on('SIGINT', onExit);</span>
891
+ <span class="cstat-no" title="statement not covered" > process.on('SIGTERM', onExit);</span>
892
+ <span class="cstat-no" title="statement not covered" > devServerStarted = true;</span>
893
+ <span class="cstat-no" title="statement not covered" > void devServerStarted;</span>
894
+ <span class="cstat-no" title="statement not covered" > return;</span>
895
+ } else {
896
+ <span class="cstat-no" title="statement not covered" > console.log(</span>
897
+ chalk.yellow(
898
+ '⚠️ Dev server not available (requires local @aiready/visualizer with web assets).'
899
+ )
900
+ );
901
+ <span class="cstat-no" title="statement not covered" > console.log(</span>
902
+ chalk.cyan(' Falling back to static HTML generation...\n')
903
+ );
904
+ <span class="cstat-no" title="statement not covered" > useDevMode = false;</span>
905
+ }
906
+ } catch (err) {
907
+ <span class="cstat-no" title="statement not covered" > console.error('Failed to start dev server:', err);</span>
908
+ <span class="cstat-no" title="statement not covered" > console.log(</span>
909
+ chalk.cyan(' Falling back to static HTML generation...\n')
910
+ );
911
+ <span class="cstat-no" title="statement not covered" > useDevMode = false;</span>
912
+ }
913
+ }
914
+ &nbsp;
915
+ // Generate static HTML (default behavior or fallback from failed --dev)
916
+ console.log('Generating HTML...');
917
+ const html = generateHTML(graph);
918
+ const defaultOutput = 'visualization.html';
919
+ const outPath = resolvePath(dirPath, options.output || defaultOutput);
920
+ writeFileSync(outPath, html, 'utf8');
921
+ console.log(chalk.green(`✅ Visualization written to: ${outPath}`));
922
+ &nbsp;
923
+ if (options.open || options.serve) {
924
+ const opener =
925
+ process.platform === 'darwin'
926
+ ? 'open'
927
+ : <span class="branch-1 cbranch-no" title="branch not covered" >process.platform === 'win32'</span>
928
+ ? 'start'
929
+ : 'xdg-open';
930
+ &nbsp;
931
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (options.serve) {
932
+ <span class="cstat-no" title="statement not covered" > try {</span>
933
+ const port = <span class="cstat-no" title="statement not covered" >typeof options.serve === 'number' ? options.serve : 5173;</span>
934
+ const http = <span class="cstat-no" title="statement not covered" >await import('http');</span>
935
+ const fsp = <span class="cstat-no" title="statement not covered" >await import('fs/promises');</span>
936
+ &nbsp;
937
+ const server = <span class="cstat-no" title="statement not covered" >http.createServer(<span class="fstat-no" title="function not covered" >async (r</span>eq, res) =&gt; {</span>
938
+ <span class="cstat-no" title="statement not covered" > try {</span>
939
+ const urlPath = <span class="cstat-no" title="statement not covered" >req.url || '/';</span>
940
+ <span class="cstat-no" title="statement not covered" > if (urlPath === '/' || urlPath === '/index.html') {</span>
941
+ const content = <span class="cstat-no" title="statement not covered" >await fsp.readFile(outPath, 'utf8');</span>
942
+ <span class="cstat-no" title="statement not covered" > res.writeHead(200, {</span>
943
+ 'Content-Type': 'text/html; charset=utf-8',
944
+ });
945
+ <span class="cstat-no" title="statement not covered" > res.end(content);</span>
946
+ <span class="cstat-no" title="statement not covered" > return;</span>
947
+ }
948
+ <span class="cstat-no" title="statement not covered" > res.writeHead(404, { 'Content-Type': 'text/plain' });</span>
949
+ <span class="cstat-no" title="statement not covered" > res.end('Not found');</span>
950
+ } catch (e: any) {
951
+ <span class="cstat-no" title="statement not covered" > void e;</span>
952
+ <span class="cstat-no" title="statement not covered" > res.writeHead(500, { 'Content-Type': 'text/plain' });</span>
953
+ <span class="cstat-no" title="statement not covered" > res.end('Server error');</span>
954
+ }
955
+ });
956
+ &nbsp;
957
+ <span class="cstat-no" title="statement not covered" > server.listen(port, <span class="fstat-no" title="function not covered" >() =&gt; {</span></span>
958
+ const addr = <span class="cstat-no" title="statement not covered" >`http://localhost:${port}/`;</span>
959
+ <span class="cstat-no" title="statement not covered" > console.log(</span>
960
+ chalk.cyan(`🌐 Local visualization server running at ${addr}`)
961
+ );
962
+ <span class="cstat-no" title="statement not covered" > spawn(opener, [`"${addr}"`], { shell: true });</span>
963
+ });
964
+ &nbsp;
965
+ <span class="cstat-no" title="statement not covered" > process.on('SIGINT', <span class="fstat-no" title="function not covered" >() =&gt; {</span></span>
966
+ <span class="cstat-no" title="statement not covered" > server.close();</span>
967
+ <span class="cstat-no" title="statement not covered" > process.exit(0);</span>
968
+ });
969
+ } catch (err) {
970
+ <span class="cstat-no" title="statement not covered" > console.error('Failed to start local server:', err);</span>
971
+ }
972
+ <span class="missing-if-branch" title="else path not taken" >E</span>} else if (options.open) {
973
+ spawn(opener, [`"${outPath}"`], { shell: true });
974
+ }
975
+ }
976
+ } catch (err: any) {
977
+ <span class="cstat-no" title="statement not covered" > handleCLIError(err, 'Visualization');</span>
978
+ }
979
+ }
980
+ &nbsp;
981
+ export const visualizeHelpText = `
982
+ EXAMPLES:
983
+ $ aiready visualize . # Auto-detects latest report, generates HTML
984
+ $ aiready visualize . --report .aiready/aiready-report-20260217-143022.json
985
+ $ aiready visualize . --report report.json -o out/visualization.html --open
986
+ $ aiready visualize . --report report.json --serve
987
+ $ aiready visualize . --report report.json --serve 8080
988
+ $ aiready visualize . --report report.json --dev
989
+ &nbsp;
990
+ NOTES:
991
+ - The value passed to --report is interpreted relative to the directory argument (first positional).
992
+ If the report is not found, the CLI will suggest running 'aiready scan' to generate it.
993
+ - Default output path: visualization.html (in the current directory).
994
+ - --serve starts a tiny single-file HTTP server (default port: 5173) and opens your browser.
995
+ - --dev starts a Vite dev server with live reload (requires local @aiready/visualizer installation).
996
+ When --dev is not available, it falls back to static HTML generation.
997
+ `;
998
+ &nbsp;
999
+ export const visualiseHelpText = `
1000
+ EXAMPLES:
1001
+ $ aiready visualise . # Auto-detects latest report
1002
+ $ aiready visualise . --report .aiready/aiready-report-20260217-143022.json
1003
+ $ aiready visualise . --report report.json --serve 8080
1004
+ &nbsp;
1005
+ NOTES:
1006
+ - Same options as 'visualize'. Use --serve to host the static HTML, or --dev for live reload.
1007
+ `;
1008
+ &nbsp;</pre></td></tr></table></pre>
1009
+
1010
+ <div class='push'></div><!-- for sticky footer -->
1011
+ </div><!-- /wrapper -->
1012
+ <div class='footer quiet pad2 space-top1 center small'>
1013
+ Code coverage generated by
1014
+ <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
1015
+ at 2026-03-09T03:44:16.153Z
1016
+ </div>
1017
+ <script src="../../prettify.js"></script>
1018
+ <script>
1019
+ window.onload = function () {
1020
+ prettyPrint();
1021
+ };
1022
+ </script>
1023
+ <script src="../../sorter.js"></script>
1024
+ <script src="../../block-navigation.js"></script>
1025
+ </body>
1026
+ </html>
1027
+