cdd-cli 3.2.0 → 3.2.2

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 (120) hide show
  1. package/.atl/skill-registry.md +30 -0
  2. package/.editorconfig +12 -0
  3. package/.eslintrc.json +1 -1
  4. package/.prettierignore +4 -0
  5. package/.prettierrc +8 -0
  6. package/CHANGELOG.md +29 -0
  7. package/SECURITY.md +5 -0
  8. package/__mocks__/ink.cjs +17 -0
  9. package/coverage/clover.xml +526 -436
  10. package/coverage/coverage-final.json +19 -15
  11. package/coverage/lcov-report/components/ContainerCreationPrompt.jsx.html +376 -0
  12. package/coverage/lcov-report/components/PromptField.jsx.html +229 -0
  13. package/coverage/lcov-report/components/SuggestionPanel.jsx.html +244 -0
  14. package/coverage/lcov-report/components/index.html +146 -0
  15. package/coverage/lcov-report/helpers/constants.js.html +80 -17
  16. package/coverage/lcov-report/helpers/containerOptionsBuilder.js.html +41 -8
  17. package/coverage/lcov-report/helpers/dockerService/serviceComponents/containerActions.js.html +162 -84
  18. package/coverage/lcov-report/helpers/dockerService/serviceComponents/containerList.js.html +50 -32
  19. package/coverage/lcov-report/helpers/dockerService/serviceComponents/index.html +21 -21
  20. package/coverage/lcov-report/helpers/imageNameUtils.js.html +181 -0
  21. package/coverage/lcov-report/helpers/index.html +27 -12
  22. package/coverage/lcov-report/helpers/logger.js.html +19 -19
  23. package/coverage/lcov-report/helpers/safeCall.js.html +3 -3
  24. package/coverage/lcov-report/helpers/validationHelpers.js.html +28 -76
  25. package/coverage/lcov-report/hooks/creation/index.html +20 -20
  26. package/coverage/lcov-report/hooks/creation/useContainerActions.js.html +38 -17
  27. package/coverage/lcov-report/hooks/creation/useContainerCreation.js.html +416 -89
  28. package/coverage/lcov-report/hooks/creation/useLogsViewer.js.html +7 -7
  29. package/coverage/lcov-report/hooks/debug/index.html +5 -5
  30. package/coverage/lcov-report/hooks/debug/useDebugLogs.js.html +35 -20
  31. package/coverage/lcov-report/hooks/index.html +40 -40
  32. package/coverage/lcov-report/hooks/navigation/index.html +19 -19
  33. package/coverage/lcov-report/hooks/navigation/useContainerSelection.js.html +38 -29
  34. package/coverage/lcov-report/hooks/useContainerCommandRouter.js.html +119 -80
  35. package/coverage/lcov-report/hooks/useControls.js.html +263 -122
  36. package/coverage/lcov-report/hooks/useEraseConfirmation.js.html +8 -8
  37. package/coverage/lcov-report/hooks/useExitHandler.js.html +50 -41
  38. package/coverage/lcov-report/index.html +67 -52
  39. package/coverage/lcov.info +991 -805
  40. package/dist/App.js +11 -11
  41. package/dist/components/ContainerCreationPrompt.js +31 -10
  42. package/dist/components/ContainerList.js +3 -3
  43. package/dist/components/ContainerRow.js +20 -20
  44. package/dist/components/ContainerSection.js +3 -3
  45. package/dist/components/Footer.js +2 -2
  46. package/dist/components/Header.js +7 -7
  47. package/dist/components/LogViewer.js +3 -3
  48. package/dist/components/MessageFeedback.js +2 -2
  49. package/dist/components/PromptField.js +4 -4
  50. package/dist/components/StatsBar.js +5 -5
  51. package/dist/components/SuggestionPanel.js +44 -0
  52. package/dist/components/UsageMenu.js +3 -3
  53. package/dist/helpers/appInfo.js +7 -7
  54. package/dist/helpers/constants.js +114 -0
  55. package/dist/helpers/containerOptionsBuilder.js +3 -3
  56. package/dist/helpers/dockerService/dockerService.js +1 -1
  57. package/dist/helpers/dockerService/serviceComponents/containerActions.js +99 -40
  58. package/dist/helpers/dockerService/serviceComponents/containerList.js +11 -11
  59. package/dist/helpers/dockerService/serviceComponents/containerLogs.js +9 -9
  60. package/dist/helpers/dockerService/serviceComponents/containerStats.js +5 -5
  61. package/dist/helpers/dockerService/serviceComponents/imageUtils.js +1 -1
  62. package/dist/helpers/exitWithMessage.js +10 -10
  63. package/dist/helpers/imageNameUtils.js +32 -0
  64. package/dist/helpers/logger.js +13 -13
  65. package/dist/helpers/safeCall.js +2 -2
  66. package/dist/helpers/validationHelpers.js +76 -21
  67. package/dist/hooks/creation/useContainerActions.js +9 -9
  68. package/dist/hooks/creation/useContainerCreation.js +138 -36
  69. package/dist/hooks/creation/useLogsViewer.js +2 -2
  70. package/dist/hooks/debug/useDebugLogs.js +4 -4
  71. package/dist/hooks/useContainerCommandRouter.js +13 -13
  72. package/dist/hooks/useContainers.js +3 -3
  73. package/dist/hooks/useControls.js +66 -35
  74. package/dist/hooks/useEraseConfirmation.js +3 -3
  75. package/dist/index.js +2 -2
  76. package/jest.config.cjs +7 -0
  77. package/package.json +7 -3
  78. package/src/App.jsx +33 -16
  79. package/src/components/ContainerCreationPrompt.jsx +43 -9
  80. package/src/components/ContainerList.jsx +3 -3
  81. package/src/components/ContainerRow.jsx +19 -16
  82. package/src/components/ContainerSection.jsx +3 -3
  83. package/src/components/Footer.jsx +2 -2
  84. package/src/components/Header.jsx +7 -7
  85. package/src/components/LogViewer.jsx +5 -3
  86. package/src/components/MessageFeedback.jsx +2 -2
  87. package/src/components/PromptField.jsx +4 -4
  88. package/src/components/StatsBar.jsx +11 -7
  89. package/src/components/SuggestionPanel.jsx +53 -0
  90. package/src/components/UsageMenu.jsx +18 -13
  91. package/src/helpers/appInfo.js +7 -7
  92. package/src/helpers/constants.js +30 -9
  93. package/src/helpers/containerOptionsBuilder.js +16 -5
  94. package/src/helpers/dockerService/dockerService.js +1 -1
  95. package/src/helpers/dockerService/serviceComponents/containerActions.js +87 -61
  96. package/src/helpers/dockerService/serviceComponents/containerList.js +31 -25
  97. package/src/helpers/dockerService/serviceComponents/containerLogs.js +41 -26
  98. package/src/helpers/dockerService/serviceComponents/containerStats.js +13 -11
  99. package/src/helpers/dockerService/serviceComponents/imageUtils.js +5 -4
  100. package/src/helpers/exitWithMessage.js +13 -7
  101. package/src/helpers/imageNameUtils.js +32 -0
  102. package/src/helpers/logger.js +15 -15
  103. package/src/helpers/safeCall.js +2 -2
  104. package/src/helpers/validationHelpers.js +13 -29
  105. package/src/hooks/creation/useContainerActions.js +19 -12
  106. package/src/hooks/creation/useContainerCreation.js +150 -41
  107. package/src/hooks/creation/useLogsViewer.js +2 -2
  108. package/src/hooks/debug/useDebugLogs.js +15 -10
  109. package/src/hooks/navigation/useContainerSelection.js +17 -14
  110. package/src/hooks/useContainerCommandRouter.js +71 -58
  111. package/src/hooks/useContainers.js +4 -4
  112. package/src/hooks/useControls.js +115 -68
  113. package/src/hooks/useEraseConfirmation.js +3 -3
  114. package/src/hooks/useExitHandler.js +29 -26
  115. package/src/index.js +4 -4
  116. package/test/ContainerCreationPrompt.dom.test.js +68 -0
  117. package/test/SuggestionPanel.dom.test.js +53 -0
  118. package/test/constants.test.js +34 -0
  119. package/test/useContainerCreation.dom.test.js +123 -0
  120. package/test/useControls.dom.test.js +198 -2
@@ -23,30 +23,30 @@
23
23
  <div class='clearfix'>
24
24
 
25
25
  <div class='fl pad1y space-right2'>
26
- <span class="strong">73.01% </span>
26
+ <span class="strong">86.4% </span>
27
27
  <span class="quiet">Statements</span>
28
- <span class='fraction'>46/63</span>
28
+ <span class='fraction'>89/103</span>
29
29
  </div>
30
30
 
31
31
 
32
32
  <div class='fl pad1y space-right2'>
33
- <span class="strong">88% </span>
33
+ <span class="strong">88.63% </span>
34
34
  <span class="quiet">Branches</span>
35
- <span class='fraction'>22/25</span>
35
+ <span class='fraction'>39/44</span>
36
36
  </div>
37
37
 
38
38
 
39
39
  <div class='fl pad1y space-right2'>
40
- <span class="strong">60% </span>
40
+ <span class="strong">90.9% </span>
41
41
  <span class="quiet">Functions</span>
42
- <span class='fraction'>3/5</span>
42
+ <span class='fraction'>10/11</span>
43
43
  </div>
44
44
 
45
45
 
46
46
  <div class='fl pad1y space-right2'>
47
- <span class="strong">72.58% </span>
47
+ <span class="strong">87% </span>
48
48
  <span class="quiet">Lines</span>
49
- <span class='fraction'>45/62</span>
49
+ <span class='fraction'>87/100</span>
50
50
  </div>
51
51
 
52
52
 
@@ -61,7 +61,7 @@
61
61
  </div>
62
62
  </template>
63
63
  </div>
64
- <div class='status-line medium'></div>
64
+ <div class='status-line high'></div>
65
65
  <pre><table class="coverage">
66
66
  <tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a>
67
67
  <a name='L2'></a><a href='#L2'>2</a>
@@ -194,7 +194,116 @@
194
194
  <a name='L129'></a><a href='#L129'>129</a>
195
195
  <a name='L130'></a><a href='#L130'>130</a>
196
196
  <a name='L131'></a><a href='#L131'>131</a>
197
- <a name='L132'></a><a href='#L132'>132</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
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></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
198
307
  <span class="cline-any cline-neutral">&nbsp;</span>
199
308
  <span class="cline-any cline-neutral">&nbsp;</span>
200
309
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -202,67 +311,164 @@
202
311
  <span class="cline-any cline-neutral">&nbsp;</span>
203
312
  <span class="cline-any cline-neutral">&nbsp;</span>
204
313
  <span class="cline-any cline-neutral">&nbsp;</span>
314
+ <span class="cline-any cline-yes">2x</span>
315
+ <span class="cline-any cline-neutral">&nbsp;</span>
316
+ <span class="cline-any cline-neutral">&nbsp;</span>
317
+ <span class="cline-any cline-neutral">&nbsp;</span>
318
+ <span class="cline-any cline-neutral">&nbsp;</span>
319
+ <span class="cline-any cline-neutral">&nbsp;</span>
320
+ <span class="cline-any cline-neutral">&nbsp;</span>
321
+ <span class="cline-any cline-neutral">&nbsp;</span>
322
+ <span class="cline-any cline-neutral">&nbsp;</span>
323
+ <span class="cline-any cline-neutral">&nbsp;</span>
324
+ <span class="cline-any cline-neutral">&nbsp;</span>
325
+ <span class="cline-any cline-neutral">&nbsp;</span>
326
+ <span class="cline-any cline-neutral">&nbsp;</span>
327
+ <span class="cline-any cline-neutral">&nbsp;</span>
328
+ <span class="cline-any cline-neutral">&nbsp;</span>
329
+ <span class="cline-any cline-neutral">&nbsp;</span>
330
+ <span class="cline-any cline-neutral">&nbsp;</span>
331
+ <span class="cline-any cline-neutral">&nbsp;</span>
332
+ <span class="cline-any cline-neutral">&nbsp;</span>
333
+ <span class="cline-any cline-yes">165x</span>
334
+ <span class="cline-any cline-yes">165x</span>
335
+ <span class="cline-any cline-yes">165x</span>
336
+ <span class="cline-any cline-yes">165x</span>
337
+ <span class="cline-any cline-yes">165x</span>
338
+ <span class="cline-any cline-yes">165x</span>
339
+ <span class="cline-any cline-yes">165x</span>
340
+ <span class="cline-any cline-neutral">&nbsp;</span>
341
+ <span class="cline-any cline-neutral">&nbsp;</span>
342
+ <span class="cline-any cline-yes">165x</span>
343
+ <span class="cline-any cline-yes">165x</span>
344
+ <span class="cline-any cline-yes">165x</span>
345
+ <span class="cline-any cline-neutral">&nbsp;</span>
346
+ <span class="cline-any cline-neutral">&nbsp;</span>
347
+ <span class="cline-any cline-neutral">&nbsp;</span>
348
+ <span class="cline-any cline-neutral">&nbsp;</span>
349
+ <span class="cline-any cline-neutral">&nbsp;</span>
350
+ <span class="cline-any cline-neutral">&nbsp;</span>
351
+ <span class="cline-any cline-neutral">&nbsp;</span>
352
+ <span class="cline-any cline-neutral">&nbsp;</span>
353
+ <span class="cline-any cline-yes">22x</span>
354
+ <span class="cline-any cline-yes">22x</span>
355
+ <span class="cline-any cline-yes">22x</span>
356
+ <span class="cline-any cline-yes">22x</span>
357
+ <span class="cline-any cline-yes">1x</span>
358
+ <span class="cline-any cline-yes">1x</span>
359
+ <span class="cline-any cline-neutral">&nbsp;</span>
360
+ <span class="cline-any cline-yes">21x</span>
361
+ <span class="cline-any cline-yes">21x</span>
362
+ <span class="cline-any cline-yes">420x</span>
363
+ <span class="cline-any cline-neutral">&nbsp;</span>
364
+ <span class="cline-any cline-yes">21x</span>
365
+ <span class="cline-any cline-neutral">&nbsp;</span>
366
+ <span class="cline-any cline-neutral">&nbsp;</span>
367
+ <span class="cline-any cline-neutral">&nbsp;</span>
368
+ <span class="cline-any cline-neutral">&nbsp;</span>
369
+ <span class="cline-any cline-neutral">&nbsp;</span>
205
370
  <span class="cline-any cline-neutral">&nbsp;</span>
206
371
  <span class="cline-any cline-neutral">&nbsp;</span>
207
372
  <span class="cline-any cline-neutral">&nbsp;</span>
208
373
  <span class="cline-any cline-neutral">&nbsp;</span>
209
374
  <span class="cline-any cline-neutral">&nbsp;</span>
375
+ <span class="cline-any cline-yes">23x</span>
376
+ <span class="cline-any cline-yes">23x</span>
377
+ <span class="cline-any cline-neutral">&nbsp;</span>
378
+ <span class="cline-any cline-yes">23x</span>
379
+ <span class="cline-any cline-yes">23x</span>
380
+ <span class="cline-any cline-yes">22x</span>
381
+ <span class="cline-any cline-yes">21x</span>
382
+ <span class="cline-any cline-neutral">&nbsp;</span>
383
+ <span class="cline-any cline-yes">23x</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-yes">7x</span>
393
+ <span class="cline-any cline-yes">7x</span>
394
+ <span class="cline-any cline-yes">7x</span>
395
+ <span class="cline-any cline-yes">7x</span>
396
+ <span class="cline-any cline-yes">7x</span>
397
+ <span class="cline-any cline-yes">7x</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>
210
401
  <span class="cline-any cline-neutral">&nbsp;</span>
211
402
  <span class="cline-any cline-neutral">&nbsp;</span>
212
403
  <span class="cline-any cline-neutral">&nbsp;</span>
404
+ <span class="cline-any cline-yes">39x</span>
405
+ <span class="cline-any cline-yes">14x</span>
406
+ <span class="cline-any cline-yes">1x</span>
407
+ <span class="cline-any cline-yes">1x</span>
408
+ <span class="cline-any cline-yes">1x</span>
213
409
  <span class="cline-any cline-neutral">&nbsp;</span>
214
- <span class="cline-any cline-yes">51x</span>
215
- <span class="cline-any cline-yes">51x</span>
216
- <span class="cline-any cline-yes">51x</span>
217
- <span class="cline-any cline-yes">51x</span>
218
- <span class="cline-any cline-yes">51x</span>
219
- <span class="cline-any cline-yes">51x</span>
220
- <span class="cline-any cline-yes">51x</span>
410
+ <span class="cline-any cline-yes">13x</span>
411
+ <span class="cline-any cline-yes">13x</span>
221
412
  <span class="cline-any cline-neutral">&nbsp;</span>
222
413
  <span class="cline-any cline-neutral">&nbsp;</span>
414
+ <span class="cline-any cline-yes">13x</span>
415
+ <span class="cline-any cline-yes">13x</span>
223
416
  <span class="cline-any cline-neutral">&nbsp;</span>
417
+ <span class="cline-any cline-yes">25x</span>
418
+ <span class="cline-any cline-yes">9x</span>
419
+ <span class="cline-any cline-yes">9x</span>
224
420
  <span class="cline-any cline-neutral">&nbsp;</span>
225
421
  <span class="cline-any cline-neutral">&nbsp;</span>
226
- <span class="cline-any cline-yes">32x</span>
422
+ <span class="cline-any cline-yes">9x</span>
423
+ <span class="cline-any cline-yes">9x</span>
424
+ <span class="cline-any cline-neutral">&nbsp;</span>
425
+ <span class="cline-any cline-yes">16x</span>
426
+ <span class="cline-any cline-neutral">&nbsp;</span>
227
427
  <span class="cline-any cline-yes">9x</span>
228
428
  <span class="cline-any cline-yes">1x</span>
429
+ <span class="cline-any cline-neutral">&nbsp;</span>
430
+ <span class="cline-any cline-neutral">&nbsp;</span>
229
431
  <span class="cline-any cline-yes">1x</span>
230
432
  <span class="cline-any cline-yes">1x</span>
231
433
  <span class="cline-any cline-neutral">&nbsp;</span>
232
434
  <span class="cline-any cline-yes">8x</span>
233
435
  <span class="cline-any cline-yes">8x</span>
234
- <span class="cline-any cline-yes">8x</span>
235
- <span class="cline-any cline-yes">8x</span>
436
+ <span class="cline-any cline-yes">24x</span>
437
+ <span class="cline-any cline-neutral">&nbsp;</span>
236
438
  <span class="cline-any cline-neutral">&nbsp;</span>
237
- <span class="cline-any cline-yes">23x</span>
238
- <span class="cline-any cline-yes">8x</span>
239
439
  <span class="cline-any cline-yes">8x</span>
440
+ <span class="cline-any cline-neutral">&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>
240
445
  <span class="cline-any cline-yes">8x</span>
241
446
  <span class="cline-any cline-yes">8x</span>
242
447
  <span class="cline-any cline-neutral">&nbsp;</span>
243
- <span class="cline-any cline-yes">15x</span>
448
+ <span class="cline-any cline-yes">3x</span>
244
449
  <span class="cline-any cline-neutral">&nbsp;</span>
245
- <span class="cline-any cline-yes">8x</span>
246
- <span class="cline-any cline-yes">1x</span>
247
- <span class="cline-any cline-yes">1x</span>
248
- <span class="cline-any cline-yes">1x</span>
249
450
  <span class="cline-any cline-neutral">&nbsp;</span>
250
- <span class="cline-any cline-yes">7x</span>
251
- <span class="cline-any cline-yes">24x</span>
451
+ <span class="cline-any cline-yes">3x</span>
252
452
  <span class="cline-any cline-neutral">&nbsp;</span>
253
- <span class="cline-any cline-yes">7x</span>
254
- <span class="cline-any cline-yes">7x</span>
255
- <span class="cline-any cline-yes">7x</span>
256
- <span class="cline-any cline-yes">2x</span>
257
- <span class="cline-any cline-yes">2x</span>
453
+ <span class="cline-any cline-neutral">&nbsp;</span>
454
+ <span class="cline-any cline-yes">3x</span>
258
455
  <span class="cline-any cline-yes">5x</span>
456
+ <span class="cline-any cline-yes">1x</span>
457
+ <span class="cline-any cline-neutral">&nbsp;</span>
458
+ <span class="cline-any cline-neutral">&nbsp;</span>
459
+ <span class="cline-any cline-yes">1x</span>
460
+ <span class="cline-any cline-yes">4x</span>
259
461
  <span class="cline-any cline-no">&nbsp;</span>
462
+ <span class="cline-any cline-neutral">&nbsp;</span>
463
+ <span class="cline-any cline-neutral">&nbsp;</span>
260
464
  <span class="cline-any cline-no">&nbsp;</span>
261
465
  <span class="cline-any cline-neutral">&nbsp;</span>
262
- <span class="cline-any cline-yes">5x</span>
263
- <span class="cline-any cline-yes">5x</span>
466
+ <span class="cline-any cline-yes">4x</span>
264
467
  <span class="cline-any cline-neutral">&nbsp;</span>
265
- <span class="cline-any cline-yes">7x</span>
468
+ <span class="cline-any cline-neutral">&nbsp;</span>
469
+ <span class="cline-any cline-yes">4x</span>
470
+ <span class="cline-any cline-neutral">&nbsp;</span>
471
+ <span class="cline-any cline-yes">8x</span>
266
472
  <span class="cline-any cline-neutral">&nbsp;</span>
267
473
  <span class="cline-any cline-yes">7x</span>
268
474
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -289,6 +495,9 @@
289
495
  <span class="cline-any cline-no">&nbsp;</span>
290
496
  <span class="cline-any cline-no">&nbsp;</span>
291
497
  <span class="cline-any cline-no">&nbsp;</span>
498
+ <span class="cline-any cline-no">&nbsp;</span>
499
+ <span class="cline-any cline-no">&nbsp;</span>
500
+ <span class="cline-any cline-no">&nbsp;</span>
292
501
  <span class="cline-any cline-neutral">&nbsp;</span>
293
502
  <span class="cline-any cline-neutral">&nbsp;</span>
294
503
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -296,16 +505,24 @@
296
505
  <span class="cline-any cline-neutral">&nbsp;</span>
297
506
  <span class="cline-any cline-neutral">&nbsp;</span>
298
507
  <span class="cline-any cline-neutral">&nbsp;</span>
299
- <span class="cline-any cline-no">&nbsp;</span>
300
- <span class="cline-any cline-no">&nbsp;</span>
301
- <span class="cline-any cline-no">&nbsp;</span>
302
- <span class="cline-any cline-no">&nbsp;</span>
303
- <span class="cline-any cline-no">&nbsp;</span>
304
- <span class="cline-any cline-no">&nbsp;</span>
305
- <span class="cline-any cline-no">&nbsp;</span>
508
+ <span class="cline-any cline-yes">8x</span>
509
+ <span class="cline-any cline-yes">8x</span>
510
+ <span class="cline-any cline-yes">8x</span>
511
+ <span class="cline-any cline-yes">8x</span>
512
+ <span class="cline-any cline-yes">8x</span>
513
+ <span class="cline-any cline-yes">8x</span>
514
+ <span class="cline-any cline-yes">8x</span>
515
+ <span class="cline-any cline-yes">8x</span>
516
+ <span class="cline-any cline-yes">8x</span>
517
+ <span class="cline-any cline-yes">8x</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-yes">165x</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>
306
524
  <span class="cline-any cline-neutral">&nbsp;</span>
307
525
  <span class="cline-any cline-neutral">&nbsp;</span>
308
- <span class="cline-any cline-yes">51x</span>
309
526
  <span class="cline-any cline-neutral">&nbsp;</span>
310
527
  <span class="cline-any cline-neutral">&nbsp;</span>
311
528
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -325,10 +542,16 @@
325
542
  <span class="cline-any cline-neutral">&nbsp;</span>
326
543
  <span class="cline-any cline-neutral">&nbsp;</span>
327
544
  <span class="cline-any cline-neutral">&nbsp;</span>
328
- <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">import { useState } from "react";
329
- import { validatePorts, validateEnvVars } from "../../helpers/validationHelpers.js";
330
- import { IMAGE_PROFILES } from "../../helpers/constants.js";
331
- import { safeCall } from "../../helpers/safeCall.js";
545
+ <span class="cline-any cline-neutral">&nbsp;</span>
546
+ <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">import { useState } from 'react';
547
+ import {
548
+ validatePorts,
549
+ validateEnvVars,
550
+ } from '../../helpers/validationHelpers.js';
551
+ import { IMAGE_PROFILES } from '../../helpers/constants.js';
552
+ import { safeCall } from '../../helpers/safeCall.js';
553
+ &nbsp;
554
+ const MAX_VISIBLE = 6;
332
555
  &nbsp;
333
556
  /**
334
557
  * Custom hook to manage the container creation flow, step by step.
@@ -341,14 +564,78 @@ import { safeCall } from "../../helpers/safeCall.js";
341
564
  * @param {Object} [params.imageProfiles] - Image profiles map for contextual validation
342
565
  * @returns {Object} Creation state, setters, and helpers
343
566
  */
344
- export function useContainerCreation({ onCreate, onCancel, dbImages = <span class="branch-0 cbranch-no" title="branch not covered" >[],</span> imageProfiles = IMAGE_PROFILES }) {
567
+ export function useContainerCreation({
568
+ onCreate,
569
+ onCancel,
570
+ dbImages = <span class="branch-0 cbranch-no" title="branch not covered" >[],</span>
571
+ imageProfiles = IMAGE_PROFILES,
572
+ }) {
345
573
  const [step, setStep] = useState(0); // 0: image, 1: name, 2: ports, 3: env
346
- const [imageName, setImageName] = useState("");
347
- const [containerName, setContainerName] = useState("");
348
- const [portInput, setPortInput] = useState("");
349
- const [envInput, setEnvInput] = useState("");
350
- const [message, setMessage] = useState("");
351
- const [messageColor, setMessageColor] = useState("yellow");
574
+ const [imageName, setImageName] = useState('');
575
+ const [containerName, setContainerName] = useState('');
576
+ const [portInput, setPortInput] = useState('');
577
+ const [envInput, setEnvInput] = useState('');
578
+ const [message, setMessage] = useState('');
579
+ const [messageColor, setMessageColor] = useState('yellow');
580
+ &nbsp;
581
+ // Autocomplete state
582
+ const [suggestions, setSuggestions] = useState([]);
583
+ const [selectedSuggestionIndex, setSelectedSuggestionIndex] = useState(-1);
584
+ const [visibleOffset, setVisibleOffset] = useState(0);
585
+ &nbsp;
586
+ /**
587
+ * Updates the image name input and recalculates autocomplete suggestions.
588
+ * Resets selectedSuggestionIndex to -1 on every keystroke.
589
+ *
590
+ * @param {string} value - New raw image name typed by user
591
+ */
592
+ function updateImageInput(value) {
593
+ setImageName(value);
594
+ setSelectedSuggestionIndex(-1);
595
+ setVisibleOffset(0);
596
+ if (!value.trim()) {
597
+ setSuggestions([]);
598
+ return;
599
+ }
600
+ const lower = value.toLowerCase();
601
+ const matches = Object.keys(imageProfiles).filter((key) =&gt;
602
+ key.includes(lower)
603
+ );
604
+ setSuggestions(matches);
605
+ }
606
+ &nbsp;
607
+ /**
608
+ * Moves the suggestion selection up (-1) or down (+1).
609
+ * Clamps index to [-1, suggestions.length - 1].
610
+ * Adjusts visibleOffset to keep selected item in the visible window.
611
+ *
612
+ * @param {number} direction - -1 (up) or 1 (down)
613
+ */
614
+ function moveSuggestionSelection(direction) {
615
+ setSelectedSuggestionIndex((prev) =&gt; {
616
+ const next = Math.max(-1, Math.min(suggestions.length - 1, prev + direction));
617
+ // Adjust visibleOffset to keep selected in view
618
+ setVisibleOffset((offset) =&gt; {
619
+ if (next &lt; offset) return Math.max(0, next);
620
+ if (next &gt;= offset + MAX_VISIBLE) return next - MAX_VISIBLE + 1;
621
+ return offset;
622
+ });
623
+ return next;
624
+ });
625
+ }
626
+ &nbsp;
627
+ /**
628
+ * Applies the currently focused suggestion to imageName.
629
+ * Does NOT advance the step. Clears suggestions after applying.
630
+ */
631
+ function applyFocusedSuggestion() {
632
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (selectedSuggestionIndex &lt; 0 || selectedSuggestionIndex &gt;= suggestions.length) <span class="cstat-no" title="statement not covered" >return;</span>
633
+ const chosen = suggestions[selectedSuggestionIndex];
634
+ setImageName(chosen);
635
+ setSuggestions([]);
636
+ setSelectedSuggestionIndex(-1);
637
+ setVisibleOffset(0);
638
+ }
352
639
  &nbsp;
353
640
  /**
354
641
  * Advances to the next step, with validation and feedback.
@@ -356,42 +643,70 @@ export function useContainerCreation({ onCreate, onCancel, dbImages = <span clas
356
643
  function nextStep() {
357
644
  if (step === 0) {
358
645
  if (!imageName.trim()) {
359
- setMessage("Image name cannot be empty.");
360
- setMessageColor("red");
646
+ setMessage('Image name cannot be empty.');
647
+ setMessageColor('red');
361
648
  return;
362
649
  }
363
650
  setStep(1);
364
- setMessage("Optional: Enter container name or leave empty and press Enter");
365
- setMessageColor("yellow");
651
+ setMessage(
652
+ 'Optional: Enter container name or leave empty and press Enter'
653
+ );
654
+ setMessageColor('yellow');
366
655
  return;
367
656
  }
368
657
  if (step === 1) {
369
658
  setStep(2);
370
- setMessage("Optional: Enter ports (format 8080:80,443:443) or leave empty and press Enter");
371
- setMessageColor("yellow");
659
+ setMessage(
660
+ 'Optional: Enter ports (format 8080:80,443:443) or leave empty and press Enter'
661
+ );
662
+ setMessageColor('yellow');
372
663
  return;
373
664
  }
374
665
  if (step === 2) {
375
666
  // Ports are now optional - only validate if provided
376
667
  if (portInput.trim() &amp;&amp; !validatePorts(portInput)) {
377
- setMessage("Port format must be host:container and both must be numbers (e.g. 8080:80)");
378
- setMessageColor("red");
668
+ setMessage(
669
+ 'Port format must be host:container and both must be numbers (e.g. 8080:80)'
670
+ );
671
+ setMessageColor('red');
379
672
  return;
380
673
  }
381
674
  setStep(3);
382
- const isDb = dbImages.some(db =&gt; imageName.trim().toLowerCase().includes(db));
675
+ const isDb = dbImages.some((db) =&gt;
676
+ imageName.trim().toLowerCase().includes(db)
677
+ );
383
678
  // Check if the image has a profile with required env vars
384
- const baseName = imageName.trim().toLowerCase().split(":")[0].split("/").pop();
679
+ const baseName = imageName
680
+ .trim()
681
+ .toLowerCase()
682
+ .split(':')[0]
683
+ .split('/')
684
+ .pop();
385
685
  const profile = imageProfiles[baseName];
386
686
  if (profile &amp;&amp; profile.requiredEnv &amp;&amp; profile.requiredEnv.length) {
387
- setMessage(`Required env vars for ${baseName}: ${profile.requiredEnv.join(", ")}. Enter as VAR=val,VAR2=val2`);
388
- setMessageColor("yellow");
687
+ const suggestedPart =
688
+ profile.suggestedEnv &amp;&amp; profile.suggestedEnv.length
689
+ ? ` | Suggested: ${profile.suggestedEnv.join(', ')}`
690
+ : <span class="branch-1 cbranch-no" title="branch not covered" >'';</span>
691
+ setMessage(
692
+ `Required env vars for ${baseName}: ${profile.requiredEnv.join(', ')}. Enter as VAR=val,VAR2=val2${suggestedPart}`
693
+ );
694
+ setMessageColor('yellow');
695
+ } else if (profile &amp;&amp; profile.suggestedEnv &amp;&amp; profile.suggestedEnv.length) {
696
+ setMessage(
697
+ `Suggested env vars for ${baseName}: ${profile.suggestedEnv.join(', ')}. Enter as VAR=val,VAR2=val2 or leave empty.`
698
+ );
699
+ setMessageColor('yellow');
389
700
  } else <span class="missing-if-branch" title="if path not taken" >I</span>if (isDb) {
390
- <span class="cstat-no" title="statement not covered" > setMessage("Warning: This image usually requires environment variables (e.g. MYSQL_ROOT_PASSWORD=my-secret-pw for MySQL, POSTGRES_PASSWORD=yourpassword for Postgres). Enter them as VAR=val,VAR2=val2 or leave empty and press Enter.");</span>
391
- <span class="cstat-no" title="statement not covered" > setMessageColor("yellow");</span>
701
+ <span class="cstat-no" title="statement not covered" > setMessage(</span>
702
+ 'Warning: This image usually requires environment variables (e.g. MYSQL_ROOT_PASSWORD=my-secret-pw for MySQL, POSTGRES_PASSWORD=yourpassword for Postgres). Enter them as VAR=val,VAR2=val2 or leave empty and press Enter.'
703
+ );
704
+ <span class="cstat-no" title="statement not covered" > setMessageColor('yellow');</span>
392
705
  } else {
393
- setMessage("Optional: Enter environment variables (format VAR1=val1,VAR2=val2) or leave empty and press Enter");
394
- setMessageColor("yellow");
706
+ setMessage(
707
+ 'Optional: Enter environment variables (format VAR1=val1,VAR2=val2) or leave empty and press Enter'
708
+ );
709
+ setMessageColor('yellow');
395
710
  }
396
711
  return;
397
712
  }
@@ -399,8 +714,8 @@ export function useContainerCreation({ onCreate, onCancel, dbImages = <span clas
399
714
  // Contextual env validation using image profiles
400
715
  const result = validateEnvVars(envInput, imageName, imageProfiles);
401
716
  if (!result.valid) {
402
- setMessage(result.errors.join(" | "));
403
- setMessageColor("red");
717
+ setMessage(result.errors.join(' | '));
718
+ setMessageColor('red');
404
719
  return;
405
720
  }
406
721
  // Final step: call onCreate with all data (safely)
@@ -413,12 +728,15 @@ export function useContainerCreation({ onCreate, onCancel, dbImages = <span clas
413
728
  */
414
729
  function <span class="fstat-no" title="function not covered" >cancelCreation(</span>) {
415
730
  <span class="cstat-no" title="statement not covered" > setStep(0);</span>
416
- <span class="cstat-no" title="statement not covered" > setImageName("");</span>
417
- <span class="cstat-no" title="statement not covered" > setContainerName("");</span>
418
- <span class="cstat-no" title="statement not covered" > setPortInput("");</span>
419
- <span class="cstat-no" title="statement not covered" > setEnvInput("");</span>
420
- <span class="cstat-no" title="statement not covered" > setMessage("");</span>
421
- <span class="cstat-no" title="statement not covered" > setMessageColor("yellow");</span>
731
+ <span class="cstat-no" title="statement not covered" > setImageName('');</span>
732
+ <span class="cstat-no" title="statement not covered" > setContainerName('');</span>
733
+ <span class="cstat-no" title="statement not covered" > setPortInput('');</span>
734
+ <span class="cstat-no" title="statement not covered" > setEnvInput('');</span>
735
+ <span class="cstat-no" title="statement not covered" > setMessage('');</span>
736
+ <span class="cstat-no" title="statement not covered" > setMessageColor('yellow');</span>
737
+ <span class="cstat-no" title="statement not covered" > setSuggestions([]);</span>
738
+ <span class="cstat-no" title="statement not covered" > setSelectedSuggestionIndex(-1);</span>
739
+ <span class="cstat-no" title="statement not covered" > setVisibleOffset(0);</span>
422
740
  <span class="cstat-no" title="statement not covered" > safeCall(onCancel);</span>
423
741
  }
424
742
  &nbsp;
@@ -426,14 +744,17 @@ export function useContainerCreation({ onCreate, onCancel, dbImages = <span clas
426
744
  * Resets all creation state to initial values without triggering onCancel.
427
745
  * Used by the command router when the user presses 'c' to open the creation wizard.
428
746
  */
429
- function <span class="fstat-no" title="function not covered" >resetCreation(</span>) {
430
- <span class="cstat-no" title="statement not covered" > setStep(0);</span>
431
- <span class="cstat-no" title="statement not covered" > setImageName("");</span>
432
- <span class="cstat-no" title="statement not covered" > setContainerName("");</span>
433
- <span class="cstat-no" title="statement not covered" > setPortInput("");</span>
434
- <span class="cstat-no" title="statement not covered" > setEnvInput("");</span>
435
- <span class="cstat-no" title="statement not covered" > setMessage("Insert the name of the image to create: ");</span>
436
- <span class="cstat-no" title="statement not covered" > setMessageColor("yellow");</span>
747
+ function resetCreation() {
748
+ setStep(0);
749
+ setImageName('');
750
+ setContainerName('');
751
+ setPortInput('');
752
+ setEnvInput('');
753
+ setMessage('Insert the name of the image to create: ');
754
+ setMessageColor('yellow');
755
+ setSuggestions([]);
756
+ setSelectedSuggestionIndex(-1);
757
+ setVisibleOffset(0);
437
758
  }
438
759
  &nbsp;
439
760
  return {
@@ -451,6 +772,12 @@ export function useContainerCreation({ onCreate, onCancel, dbImages = <span clas
451
772
  setMessage,
452
773
  messageColor,
453
774
  setMessageColor,
775
+ suggestions,
776
+ selectedSuggestionIndex,
777
+ visibleOffset,
778
+ updateImageInput,
779
+ moveSuggestionSelection,
780
+ applyFocusedSuggestion,
454
781
  nextStep,
455
782
  cancelCreation,
456
783
  resetCreation,
@@ -463,7 +790,7 @@ export function useContainerCreation({ onCreate, onCancel, dbImages = <span clas
463
790
  <div class='footer quiet pad2 space-top1 center small'>
464
791
  Code coverage generated by
465
792
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
466
- at 2026-04-25T17:40:28.828Z
793
+ at 2026-04-27T20:17:25.625Z
467
794
  </div>
468
795
  <script src="../../prettify.js"></script>
469
796
  <script>