cdd-cli 3.1.4 → 3.1.6

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 (140) hide show
  1. package/.eslintrc.json +30 -0
  2. package/.github/workflows/docs.yml +35 -0
  3. package/CHANGELOG.md +37 -4
  4. package/README.md +26 -0
  5. package/_config.yml +13 -0
  6. package/dist/App.js +20 -3
  7. package/dist/components/ContainerCreationPrompt.js +27 -1
  8. package/dist/components/ContainerList.js +11 -15
  9. package/dist/components/ContainerRow.js +73 -14
  10. package/dist/components/ContainerSection.js +16 -2
  11. package/dist/components/Footer.js +7 -1
  12. package/dist/components/Header.js +27 -3
  13. package/dist/components/LogViewer.js +21 -3
  14. package/dist/components/MessageFeedback.js +15 -1
  15. package/dist/components/PromptField.js +31 -1
  16. package/dist/components/StatsBar.js +47 -8
  17. package/dist/components/UsageMenu.js +30 -1
  18. package/dist/helpers/actionHelpers.js +17 -6
  19. package/dist/helpers/appInfo.js +21 -0
  20. package/dist/helpers/constants.js +30 -0
  21. package/dist/helpers/dockerService/dockerService.js +19 -0
  22. package/dist/helpers/dockerService/serviceComponents/containerActions.js +194 -35
  23. package/dist/helpers/dockerService/serviceComponents/containerList.js +45 -8
  24. package/dist/helpers/dockerService/serviceComponents/containerLogs.js +16 -6
  25. package/dist/helpers/dockerService/serviceComponents/containerStats.js +28 -9
  26. package/dist/helpers/exitWithMessage.js +2 -1
  27. package/dist/helpers/logger.js +126 -0
  28. package/dist/helpers/safeCall.js +21 -0
  29. package/dist/helpers/validationHelpers.js +20 -1
  30. package/dist/hooks/creation/useContainerActions.js +2 -1
  31. package/dist/hooks/creation/useContainerCreation.js +5 -4
  32. package/dist/hooks/creation/useLogsViewer.js +3 -2
  33. package/dist/hooks/useContainers.js +6 -3
  34. package/dist/hooks/useControls.js +253 -122
  35. package/dist/hooks/useLogsStream.js +3 -2
  36. package/dist/index.js +1 -0
  37. package/docs/_config.yml +13 -0
  38. package/docs/components_ContainerCreationPrompt.jsx.html +114 -0
  39. package/docs/components_ContainerRow.jsx.html +151 -0
  40. package/docs/components_ContainerSection.jsx.html +75 -0
  41. package/docs/components_Footer.jsx.html +66 -0
  42. package/docs/components_Header.jsx.html +84 -0
  43. package/docs/components_LogViewer.jsx.html +91 -0
  44. package/docs/components_MessageFeedback.jsx.html +76 -0
  45. package/docs/components_PromptField.jsx.html +99 -0
  46. package/docs/components_StatsBar.jsx.html +105 -0
  47. package/docs/components_UsageMenu.jsx.html +73 -0
  48. package/docs/fonts/OpenSans-Bold-webfont.eot +0 -0
  49. package/docs/fonts/OpenSans-Bold-webfont.svg +1830 -0
  50. package/docs/fonts/OpenSans-Bold-webfont.woff +0 -0
  51. package/docs/fonts/OpenSans-BoldItalic-webfont.eot +0 -0
  52. package/docs/fonts/OpenSans-BoldItalic-webfont.svg +1830 -0
  53. package/docs/fonts/OpenSans-BoldItalic-webfont.woff +0 -0
  54. package/docs/fonts/OpenSans-Italic-webfont.eot +0 -0
  55. package/docs/fonts/OpenSans-Italic-webfont.svg +1830 -0
  56. package/docs/fonts/OpenSans-Italic-webfont.woff +0 -0
  57. package/docs/fonts/OpenSans-Light-webfont.eot +0 -0
  58. package/docs/fonts/OpenSans-Light-webfont.svg +1831 -0
  59. package/docs/fonts/OpenSans-Light-webfont.woff +0 -0
  60. package/docs/fonts/OpenSans-LightItalic-webfont.eot +0 -0
  61. package/docs/fonts/OpenSans-LightItalic-webfont.svg +1835 -0
  62. package/docs/fonts/OpenSans-LightItalic-webfont.woff +0 -0
  63. package/docs/fonts/OpenSans-Regular-webfont.eot +0 -0
  64. package/docs/fonts/OpenSans-Regular-webfont.svg +1831 -0
  65. package/docs/fonts/OpenSans-Regular-webfont.woff +0 -0
  66. package/docs/global.html +6145 -0
  67. package/docs/helpers_actionHelpers.js.html +94 -0
  68. package/docs/helpers_constants.js.html +81 -0
  69. package/docs/helpers_dockerService_dockerService.js.html +79 -0
  70. package/docs/helpers_dockerService_serviceComponents_containerActions.js.html +153 -0
  71. package/docs/helpers_dockerService_serviceComponents_containerList.js.html +81 -0
  72. package/docs/helpers_dockerService_serviceComponents_containerLogs.js.html +85 -0
  73. package/docs/helpers_dockerService_serviceComponents_containerStats.js.html +107 -0
  74. package/docs/helpers_dockerService_serviceComponents_imageUtils.js.html +82 -0
  75. package/docs/helpers_exitWithMessage.js.html +77 -0
  76. package/docs/helpers_safeCall.js.html +68 -0
  77. package/docs/helpers_validationHelpers.js.html +96 -0
  78. package/docs/hooks_creation_useContainerActions.js.html +120 -0
  79. package/docs/hooks_creation_useContainerCreation.js.html +152 -0
  80. package/docs/hooks_creation_useLogsViewer.js.html +102 -0
  81. package/docs/hooks_useControls.js.html +298 -0
  82. package/docs/hooks_useLogsStream.js.html +82 -0
  83. package/docs/index.html +65 -0
  84. package/docs/index.js.html +65 -0
  85. package/docs/module-index.html +171 -0
  86. package/docs/scripts/linenumber.js +25 -0
  87. package/docs/scripts/prettify/Apache-License-2.0.txt +202 -0
  88. package/docs/scripts/prettify/lang-css.js +2 -0
  89. package/docs/scripts/prettify/prettify.js +28 -0
  90. package/docs/styles/jsdoc-default.css +358 -0
  91. package/docs/styles/prettify-jsdoc.css +111 -0
  92. package/docs/styles/prettify-tomorrow.css +132 -0
  93. package/fix-imports.cjs +33 -6
  94. package/jest.config.cjs +2 -1
  95. package/package.json +19 -9
  96. package/src/App.jsx +16 -2
  97. package/src/components/ContainerCreationPrompt.jsx +26 -0
  98. package/src/components/ContainerList.jsx +12 -13
  99. package/src/components/ContainerRow.jsx +55 -20
  100. package/src/components/ContainerSection.jsx +15 -1
  101. package/src/components/Footer.jsx +6 -1
  102. package/src/components/Header.jsx +27 -3
  103. package/src/components/LogViewer.jsx +19 -2
  104. package/src/components/MessageFeedback.jsx +14 -0
  105. package/src/components/PromptField.jsx +30 -0
  106. package/src/components/StatsBar.jsx +47 -8
  107. package/src/components/UsageMenu.jsx +38 -8
  108. package/src/helpers/actionHelpers.js +16 -7
  109. package/src/helpers/appInfo.js +23 -0
  110. package/src/helpers/constants.js +30 -0
  111. package/src/helpers/dockerService/dockerService.js +19 -0
  112. package/src/helpers/dockerService/serviceComponents/containerActions.js +123 -12
  113. package/src/helpers/dockerService/serviceComponents/containerList.js +61 -23
  114. package/src/helpers/dockerService/serviceComponents/containerLogs.js +20 -6
  115. package/src/helpers/dockerService/serviceComponents/containerStats.js +24 -5
  116. package/src/helpers/dockerService/serviceComponents/imageUtils.js +1 -1
  117. package/src/helpers/exitWithMessage.js +2 -1
  118. package/src/helpers/logger.js +113 -0
  119. package/src/helpers/safeCall.js +18 -0
  120. package/src/helpers/validationHelpers.js +21 -3
  121. package/src/hooks/creation/useContainerActions.js +4 -3
  122. package/src/hooks/creation/useContainerCreation.js +5 -4
  123. package/src/hooks/creation/useLogsViewer.js +2 -1
  124. package/src/hooks/useContainers.js +6 -3
  125. package/src/hooks/useControls.js +244 -91
  126. package/src/hooks/useLogsStream.js +2 -1
  127. package/src/index.js +1 -0
  128. package/test/actionHelpers.test.js +106 -0
  129. package/test/containerActions.test.js +138 -0
  130. package/test/containerList.test.js +79 -0
  131. package/test/jest.setup.js +7 -0
  132. package/test/safeCall.test.js +25 -0
  133. package/test/useContainerCreation.dom.test.js +97 -0
  134. package/test/validationHelpers.test.js +2 -2
  135. package/dist/cdd.bundle.js +0 -8
  136. package/dist/components/ContainerCreator.js +0 -81
  137. package/dist/components/StatsViewer.js +0 -0
  138. package/dist/helpers/dockerActions.js +0 -64
  139. package/dist/helpers/dockerService.js +0 -284
  140. package/dist/hooks/useStatsPolling.js +0 -54
@@ -16,9 +16,11 @@ import React from "react";
16
16
  import { useContainerActions } from "./creation/useContainerActions.js";
17
17
  import { useContainerCreation } from "./creation/useContainerCreation.js";
18
18
  import { useLogsViewer } from "./creation/useLogsViewer.js";
19
- import { useInput } from "ink";
19
+ import { useInput, useApp } from "ink";
20
20
  import { getLogsStream } from "../helpers/dockerService/serviceComponents/containerLogs.js";
21
+ import { EXIT_DELAY } from "../helpers/constants.js";
21
22
  import { createContainer as svcCreateContainer } from "../helpers/dockerService/serviceComponents/containerActions.js";
23
+ import { logger } from "../helpers/logger.js";
22
24
 
23
25
  // Principal hook to manage user inputs and control the app state
24
26
  /**
@@ -43,6 +45,9 @@ import { createContainer as svcCreateContainer } from "../helpers/dockerService/
43
45
  * @property {Object} creation - The creation hook API (setters and helpers)
44
46
  * @property {Object} actions - The actions hook API (helpers to start/stop/remove)
45
47
  * @property {Object} logsViewer - The logs viewer hook API
48
+ * @property {boolean} showDebugLogs - Whether the debug log panel is visible
49
+ * @property {Array<string>} debugLogs - Buffered log lines captured from the shared logger
50
+ * @property {boolean} confirmErase - Whether the erase confirmation dialog is active
46
51
  */
47
52
  export function useControls() {
48
53
  var containers = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
@@ -58,7 +63,17 @@ export function useControls() {
58
63
  _React$useState6 = _slicedToArray(_React$useState5, 2),
59
64
  confirmErase = _React$useState6[0],
60
65
  setConfirmErase = _React$useState6[1];
66
+ var _React$useState7 = React.useState(false),
67
+ _React$useState8 = _slicedToArray(_React$useState7, 2),
68
+ showDebugLogs = _React$useState8[0],
69
+ setShowDebugLogs = _React$useState8[1];
70
+ var _React$useState9 = React.useState([]),
71
+ _React$useState0 = _slicedToArray(_React$useState9, 2),
72
+ debugLogs = _React$useState0[0],
73
+ setDebugLogs = _React$useState0[1];
61
74
  var total = containers.length;
75
+ var _useApp = useApp(),
76
+ exit = _useApp.exit;
62
77
 
63
78
  // Modular hooks
64
79
  var actions = useContainerActions({
@@ -142,120 +157,174 @@ export function useControls() {
142
157
 
143
158
  // Handler to exit logs (delegated to logsViewer)
144
159
  var exitLogs = logsViewer.closeLogs;
145
- useInput(function (input, key) {
146
- // Erase confirmation
147
- if (confirmErase) {
148
- if (input === "y" || input === "Y") {
149
- actions.handleAction({
150
- actionFn: function () {
151
- var _actionFn = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2(id) {
152
- return _regenerator().w(function (_context2) {
153
- while (1) switch (_context2.n) {
154
- case 0:
155
- _context2.n = 1;
156
- return actions.removeContainer(id);
157
- case 1:
158
- return _context2.a(2, _context2.v);
159
- }
160
- }, _callee2);
161
- }));
162
- function actionFn(_x2) {
163
- return _actionFn.apply(this, arguments);
164
- }
165
- return actionFn;
166
- }(),
167
- actionLabel: "Erasing",
168
- selected: selected
169
- });
170
- setConfirmErase(false);
171
- actions.setMessageColor("yellow");
172
- return;
173
- } else if (input === "n" || input === "N" || key.escape) {
174
- setConfirmErase(false);
175
- actions.setMessage("");
176
- actions.setMessageColor("");
177
- return;
178
- } else {
179
- actions.setMessage("Are you sure you want to erase this container? (y/n)");
180
- actions.setMessageColor("yellow");
181
- return;
182
- }
183
- }
184
160
 
185
- // Logs viewer
186
- if (logsViewer.showLogs) {
187
- if (input === "q" || key.escape) {
188
- logsViewer.closeLogs();
189
- }
161
+ /**
162
+ * Pipe container logs into the viewer while applying a hard limit.
163
+ * @param {string} containerId - Container identifier used by Docker.
164
+ */
165
+ var startLogsStream = React.useCallback(function (containerId) {
166
+ getLogsStream(containerId, function (data) {
167
+ return logsViewer.setLogs(function (prev) {
168
+ var newLogs = [].concat(_toConsumableArray(prev), _toConsumableArray(data.split("\n").filter(Boolean)));
169
+ return newLogs.slice(-1000);
170
+ });
171
+ }, function () {}, function (err) {
172
+ return logsViewer.setLogs(function (prev) {
173
+ return [].concat(_toConsumableArray(prev), ["Error: ".concat(err.message)]);
174
+ });
175
+ });
176
+ }, [logsViewer]);
177
+
178
+ /**
179
+ * Manage the erase confirmation short-circuit flow.
180
+ */
181
+ var processEraseConfirmation = React.useCallback(function (input, key) {
182
+ if (input === "y" || input === "Y") {
183
+ actions.handleAction({
184
+ actionFn: function () {
185
+ var _actionFn = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2(id) {
186
+ return _regenerator().w(function (_context2) {
187
+ while (1) switch (_context2.n) {
188
+ case 0:
189
+ _context2.n = 1;
190
+ return actions.removeContainer(id);
191
+ case 1:
192
+ return _context2.a(2, _context2.v);
193
+ }
194
+ }, _callee2);
195
+ }));
196
+ function actionFn(_x2) {
197
+ return _actionFn.apply(this, arguments);
198
+ }
199
+ return actionFn;
200
+ }(),
201
+ actionLabel: "Erasing",
202
+ selected: selected
203
+ });
204
+ setConfirmErase(false);
205
+ actions.setMessageColor("yellow");
190
206
  return;
191
207
  }
192
-
193
- // Container creation flow: delegate input to creation hook
194
- if (creatingContainer) {
195
- var step = creation.step;
196
- var appendCharToField = function appendCharToField(setter, value, ch) {
197
- setter((value || "") + ch);
198
- };
199
- // Escape -> cancel
200
- if (key.escape) {
201
- creation.cancelCreation();
202
- setCreatingContainer(false);
203
- return;
204
- }
205
- // Enter -> next step
206
- if (input === "\r" || input === "\n") {
207
- creation.nextStep();
208
- return;
209
- }
210
- // Backspace/Delete support
211
- if (key.backspace || key["delete"]) {
212
- if (step === 0) creation.setImageName(function (v) {
213
- return (v || "").slice(0, -1);
214
- });
215
- if (step === 1) creation.setContainerName(function (v) {
216
- return (v || "").slice(0, -1);
217
- });
218
- if (step === 2) creation.setPortInput(function (v) {
219
- return (v || "").slice(0, -1);
220
- });
221
- if (step === 3) creation.setEnvInput(function (v) {
222
- return (v || "").slice(0, -1);
223
- });
224
- return;
225
- }
226
- // Printable character input (append)
227
- if (input && input.length === 1 && !key.ctrl && !key.meta) {
228
- if (step === 0) appendCharToField(creation.setImageName, creation.imageName, input);
229
- if (step === 1) appendCharToField(creation.setContainerName, creation.containerName, input);
230
- if (step === 2) appendCharToField(creation.setPortInput, creation.portInput, input);
231
- if (step === 3) appendCharToField(creation.setEnvInput, creation.envInput, input);
232
- return;
233
- }
234
- // Otherwise ignore
208
+ if (input === "n" || input === "N" || key.escape) {
209
+ setConfirmErase(false);
210
+ actions.setMessage("");
211
+ actions.setMessageColor("");
235
212
  return;
236
213
  }
214
+ actions.setMessage("Are you sure you want to erase this container? (y/n)");
215
+ actions.setMessageColor("yellow");
216
+ }, [actions, selected]);
237
217
 
238
- //==========================================================
239
- // Menu Navigation
240
- //==========================================================
241
- if (key.upArrow && total > 0) setSelected(function (i) {
242
- return i === 0 ? total - 1 : i - 1;
243
- });
244
- if (key.downArrow && total > 0) setSelected(function (i) {
245
- return i === total - 1 ? 0 : i + 1;
246
- });
247
- if (input === "q") {
248
- actions.setMessage("Exiting...");
249
- actions.setMessageColor("yellow");
250
- setTimeout(function () {
251
- return process.exit(0);
252
- }, 500);
218
+ /**
219
+ * Handle inputs while the logs viewer is active.
220
+ */
221
+ var processLogsInput = React.useCallback(function (input, key) {
222
+ if (input === "q" || key.escape) {
223
+ logsViewer.closeLogs();
224
+ }
225
+ }, [logsViewer]);
226
+
227
+ /**
228
+ * Route keystrokes to the container creation wizard.
229
+ */
230
+ var processCreationInput = React.useCallback(function (input, key) {
231
+ var step = creation.step;
232
+ var removeLastChar = function removeLastChar(setter) {
233
+ return setter(function (value) {
234
+ return (value || "").slice(0, -1);
235
+ });
236
+ };
237
+ var appendChar = function appendChar(setter, current, ch) {
238
+ return setter((current || "") + ch);
239
+ };
240
+ if (key.escape) {
241
+ creation.cancelCreation();
242
+ setCreatingContainer(false);
253
243
  return;
254
244
  }
245
+ if (input === "\r" || input === "\n") {
246
+ creation.nextStep();
247
+ return;
248
+ }
249
+ if (key.backspace || key["delete"]) {
250
+ if (step === 0) removeLastChar(creation.setImageName);
251
+ if (step === 1) removeLastChar(creation.setContainerName);
252
+ if (step === 2) removeLastChar(creation.setPortInput);
253
+ if (step === 3) removeLastChar(creation.setEnvInput);
254
+ return;
255
+ }
256
+ if (input && input.length === 1 && !key.ctrl && !key.meta) {
257
+ if (step === 0) appendChar(creation.setImageName, creation.imageName, input);
258
+ if (step === 1) appendChar(creation.setContainerName, creation.containerName, input);
259
+ if (step === 2) appendChar(creation.setPortInput, creation.portInput, input);
260
+ if (step === 3) appendChar(creation.setEnvInput, creation.envInput, input);
261
+ }
262
+ }, [creation, setCreatingContainer]);
255
263
 
256
- //==========================================================
257
- // Docker commands
258
- //==========================================================
264
+ /**
265
+ * Navigate the container list using arrow keys.
266
+ * @returns {boolean} True when the input was consumed.
267
+ */
268
+ var handleNavigation = React.useCallback(function (input, key) {
269
+ if (total === 0) {
270
+ return false;
271
+ }
272
+ if (key.upArrow) {
273
+ setSelected(function (i) {
274
+ return i === 0 ? total - 1 : i - 1;
275
+ });
276
+ return true;
277
+ }
278
+ if (key.downArrow) {
279
+ setSelected(function (i) {
280
+ return i === total - 1 ? 0 : i + 1;
281
+ });
282
+ return true;
283
+ }
284
+ return false;
285
+ }, [total]);
286
+
287
+ /**
288
+ * Handle the quit command.
289
+ * @returns {boolean} True when the input was consumed.
290
+ */
291
+ var handleExitCommand = React.useCallback(function (input) {
292
+ if (input !== "q") {
293
+ return false;
294
+ }
295
+ actions.setMessage("Exiting...");
296
+ actions.setMessageColor("yellow");
297
+ logsViewer.closeLogs();
298
+ setShowDebugLogs(false);
299
+ var clearTerminal = function clearTerminal() {
300
+ try {
301
+ if (process.stdout && process.stdout.isTTY) {
302
+ process.stdout.write("\x1Bc");
303
+ } else {
304
+ console.clear();
305
+ }
306
+ } catch (err) {
307
+ // Ignore clear errors to avoid blocking exit.
308
+ }
309
+ };
310
+ setTimeout(function () {
311
+ clearTerminal();
312
+ exit();
313
+ if (process.env.NODE_ENV !== "test") {
314
+ setTimeout(function () {
315
+ return process.exit(0);
316
+ }, 50);
317
+ }
318
+ }, EXIT_DELAY);
319
+ return true;
320
+ }, [actions, exit, logsViewer]);
321
+
322
+ /**
323
+ * Execute Docker-related commands and prompt transitions.
324
+ * @returns {boolean} True when the input was consumed.
325
+ */
326
+ var handleDockerCommands = React.useCallback(function (input) {
327
+ var container = containers[selected];
259
328
  if (input === "i") {
260
329
  actions.handleAction({
261
330
  actionFn: function () {
@@ -281,6 +350,7 @@ export function useControls() {
281
350
  return (c.state === "running" || c.status === "running") && "Container is already running.";
282
351
  }
283
352
  });
353
+ return true;
284
354
  }
285
355
  if (input === "p") {
286
356
  actions.handleAction({
@@ -307,6 +377,7 @@ export function useControls() {
307
377
  return (c.state === "exited" || c.status === "exited" || c.state === "stopped" || c.status === "stopped") && "Container is already stopped.";
308
378
  }
309
379
  });
380
+ return true;
310
381
  }
311
382
  if (input === "r") {
312
383
  actions.handleAction({
@@ -330,27 +401,24 @@ export function useControls() {
330
401
  actionLabel: "Restarting",
331
402
  selected: selected
332
403
  });
404
+ return true;
333
405
  }
334
- if (input === "e" && containers[selected]) {
406
+ if (input === "e") {
407
+ if (!container) {
408
+ return true;
409
+ }
335
410
  setConfirmErase(true);
336
411
  actions.setMessage("Are you sure you want to erase this container? (y/n)");
337
412
  actions.setMessageColor("yellow");
338
- return;
413
+ return true;
339
414
  }
340
- if (input === "l" && containers[selected]) {
415
+ if (input === "l") {
416
+ if (!container) {
417
+ return true;
418
+ }
341
419
  logsViewer.openLogs();
342
- getLogsStream(containers[selected].id, function (data) {
343
- return logsViewer.setLogs(function (prev) {
344
- var newLogs = [].concat(_toConsumableArray(prev), _toConsumableArray(data.split("\n").filter(Boolean)));
345
- // Limit to last 1000 lines to prevent memory leak
346
- return newLogs.slice(-1000);
347
- });
348
- }, function () {}, function (err) {
349
- return logsViewer.setLogs(function (prev) {
350
- return [].concat(_toConsumableArray(prev), ["Error: ".concat(err.message)]);
351
- });
352
- });
353
- return;
420
+ startLogsStream(container.id);
421
+ return true;
354
422
  }
355
423
  if (input === "c") {
356
424
  setCreatingContainer(true);
@@ -361,8 +429,69 @@ export function useControls() {
361
429
  creation.setEnvInput("");
362
430
  creation.setMessage("Insert the name of the image to create: ");
363
431
  creation.setMessageColor("yellow");
432
+ return true;
433
+ }
434
+ if (input === "d") {
435
+ setShowDebugLogs(function (prev) {
436
+ return !prev;
437
+ });
438
+ return true;
364
439
  }
440
+ return false;
441
+ }, [actions, containers, creation, logsViewer, selected, setConfirmErase, setCreatingContainer, startLogsStream, setShowDebugLogs]);
442
+
443
+ /**
444
+ * Default handler executed when no special mode is active.
445
+ */
446
+ var processGlobalInput = React.useCallback(function (input, key) {
447
+ if (handleNavigation(input, key)) {
448
+ return;
449
+ }
450
+ if (handleExitCommand(input)) {
451
+ return;
452
+ }
453
+ handleDockerCommands(input);
454
+ }, [handleDockerCommands, handleExitCommand, handleNavigation]);
455
+ useInput(function (input, key) {
456
+ if (confirmErase) {
457
+ processEraseConfirmation(input, key);
458
+ return;
459
+ }
460
+ if (logsViewer.showLogs) {
461
+ processLogsInput(input, key);
462
+ return;
463
+ }
464
+ if (creatingContainer) {
465
+ processCreationInput(input, key);
466
+ return;
467
+ }
468
+ if (showDebugLogs && key.escape) {
469
+ setShowDebugLogs(false);
470
+ return;
471
+ }
472
+ processGlobalInput(input, key);
365
473
  });
474
+
475
+ // Mirror global logger entries so the D shortcut can surface them without leaving the CLI.
476
+ React.useEffect(function () {
477
+ var unsubscribe = logger.subscribe(function (entry) {
478
+ setDebugLogs(function (prev) {
479
+ var extras = (entry.args || []).map(function (arg) {
480
+ if (typeof arg === "string") return arg;
481
+ if (typeof arg === "number" || typeof arg === "boolean") return String(arg);
482
+ try {
483
+ return JSON.stringify(arg);
484
+ } catch (err) {
485
+ return "[unserializable]";
486
+ }
487
+ }).filter(Boolean);
488
+ var line = extras.length ? "".concat(entry.formatted, " ").concat(extras.join(" ")) : entry.formatted;
489
+ var next = [].concat(_toConsumableArray(prev), [line]);
490
+ return next.slice(-200);
491
+ });
492
+ });
493
+ return unsubscribe;
494
+ }, []);
366
495
  return {
367
496
  selected: selected,
368
497
  setSelected: setSelected,
@@ -382,6 +511,8 @@ export function useControls() {
382
511
  creation: creation,
383
512
  actions: actions,
384
513
  logsViewer: logsViewer,
385
- confirmErase: confirmErase
514
+ confirmErase: confirmErase,
515
+ showDebugLogs: showDebugLogs,
516
+ debugLogs: debugLogs
386
517
  };
387
518
  }
@@ -6,6 +6,7 @@ function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(
6
6
  function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
7
7
  import React, { useRef, useCallback } from "react";
8
8
  import { getLogsStream } from "../helpers/dockerService/serviceComponents/containerLogs.js";
9
+ import { safeCall } from "../helpers/safeCall.js";
9
10
 
10
11
  /**
11
12
  * Hook that manages opening and closing a logs stream for a container.
@@ -28,8 +29,8 @@ export function useLogsStream() {
28
29
  }, []);
29
30
  var closeLogs = useCallback(function () {
30
31
  if (logsStreamRef.current) {
31
- var _logsStreamRef$curren, _logsStreamRef$curren2;
32
- (_logsStreamRef$curren = (_logsStreamRef$curren2 = logsStreamRef.current).destroy) === null || _logsStreamRef$curren === void 0 || _logsStreamRef$curren.call(_logsStreamRef$curren2);
32
+ var _logsStreamRef$curren;
33
+ safeCall((_logsStreamRef$curren = logsStreamRef.current.destroy) === null || _logsStreamRef$curren === void 0 ? void 0 : _logsStreamRef$curren.bind(logsStreamRef.current));
33
34
  logsStreamRef.current = null;
34
35
  }
35
36
  }, []);
package/dist/index.js CHANGED
@@ -10,4 +10,5 @@
10
10
  import React from "react";
11
11
  import { render } from "ink";
12
12
  import App from './App.js';
13
+ console.clear();
13
14
  render(/*#__PURE__*/React.createElement(App, null));
@@ -0,0 +1,13 @@
1
+ title: CDD Documentation
2
+ # Disable the default GitHub Pages theme so Jekyll just copies our static output
3
+ # (the static HTML is generated by JSDoc and already styled).
4
+ theme: null
5
+
6
+ # Explicitly include asset folders that Jekyll might otherwise ignore.
7
+ include:
8
+ - fonts
9
+ - scripts
10
+ - styles
11
+
12
+ # No Jekyll plugins are required for this pre-rendered site.
13
+ plugins: []
@@ -0,0 +1,114 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>JSDoc: Source: components/ContainerCreationPrompt.jsx</title>
6
+
7
+ <script src="scripts/prettify/prettify.js"> </script>
8
+ <script src="scripts/prettify/lang-css.js"> </script>
9
+ <!--[if lt IE 9]>
10
+ <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
11
+ <![endif]-->
12
+ <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
13
+ <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
14
+ </head>
15
+
16
+ <body>
17
+
18
+ <div id="main">
19
+
20
+ <h1 class="page-title">Source: components/ContainerCreationPrompt.jsx</h1>
21
+
22
+
23
+
24
+
25
+
26
+
27
+ <section>
28
+ <article>
29
+ <pre class="prettyprint source linenums"><code>import React from "react";
30
+ import { Box, Text } from "ink";
31
+ import { PromptField, PromptMessage } from "./PromptField.jsx";
32
+ import PropTypes from 'prop-types';
33
+
34
+ /**
35
+ * Prompt UI shown when creating a new container.
36
+ * Presents a step-by-step form (image, name, ports, env) and displays
37
+ * a contextual message provided by the creation hook.
38
+ *
39
+ * @param {Object} props
40
+ * @param {number} props.step - Current step index (0..3)
41
+ * @param {string} props.imageName - Value for the image name field
42
+ * @param {string} props.containerName - Value for the container name field
43
+ * @param {string} props.portInput - Value for the ports input field
44
+ * @param {string} props.envInput - Value for the environment variables field
45
+ * @param {string} props.message - Contextual message to display (errors/hints)
46
+ * @param {string} props.messageColor - Color for the contextual message
47
+ * @returns {JSX.Element}
48
+ */
49
+ export default function ContainerCreationPrompt(props) {
50
+ const { step, imageName, containerName, portInput, envInput, message, messageColor } = props;
51
+ const prompts = [
52
+ {
53
+ label: "Name of the image to create (e.g., nginx:latest):",
54
+ value: imageName,
55
+ required: true,
56
+ },
57
+ {
58
+ label: "Name of the container (optional):",
59
+ value: containerName,
60
+ required: false,
61
+ },
62
+ {
63
+ label: "Ports (optional, format 8080:80,443:443):",
64
+ value: portInput,
65
+ required: false,
66
+ },
67
+ {
68
+ label: "Environment variables (optional, format VAR1=val1,VAR2=val2):",
69
+ value: envInput,
70
+ required: false,
71
+ },
72
+ ];
73
+ const { label, value, required } = prompts[step] || {};
74
+ return (
75
+ &lt;Box flexDirection="column" borderStyle="round" borderColor="yellow" padding={1}>
76
+ &lt;PromptField label={label} value={value} required={required} />
77
+ &lt;PromptMessage message={message} color={messageColor} />
78
+ &lt;Text dimColor>Press Enter to continue, Escape to cancel&lt;/Text>
79
+ &lt;/Box>
80
+ );
81
+ }
82
+
83
+ ContainerCreationPrompt.propTypes = {
84
+ step: PropTypes.number.isRequired,
85
+ imageName: PropTypes.string,
86
+ containerName: PropTypes.string,
87
+ portInput: PropTypes.string,
88
+ envInput: PropTypes.string,
89
+ message: PropTypes.string,
90
+ messageColor: PropTypes.string,
91
+ };
92
+ </code></pre>
93
+ </article>
94
+ </section>
95
+
96
+
97
+
98
+
99
+ </div>
100
+
101
+ <nav>
102
+ <h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-index.html">index</a></li></ul><h3>Global</h3><ul><li><a href="global.html#EXIT_DELAY">EXIT_DELAY</a></li><li><a href="global.html#MESSAGE_TIMEOUTS">MESSAGE_TIMEOUTS</a></li><li><a href="global.html#PromptField">PromptField</a></li><li><a href="global.html#PromptMessage">PromptMessage</a></li><li><a href="global.html#REFRESH_INTERVALS">REFRESH_INTERVALS</a></li><li><a href="global.html#TIMEOUTS">TIMEOUTS</a></li><li><a href="global.html#colorize">colorize</a></li><li><a href="global.html#createContainer">createContainer</a></li><li><a href="global.html#docker">docker</a></li><li><a href="global.html#exitWithMessage">exitWithMessage</a></li><li><a href="global.html#getContainers">getContainers</a></li><li><a href="global.html#getLogsStream">getLogsStream</a></li><li><a href="global.html#getStats">getStats</a></li><li><a href="global.html#handleAction">handleAction</a></li><li><a href="global.html#imageExists">imageExists</a></li><li><a href="global.html#makeBar">makeBar</a></li><li><a href="global.html#pullImage">pullImage</a></li><li><a href="global.html#removeContainer">removeContainer</a></li><li><a href="global.html#restartContainer">restartContainer</a></li><li><a href="global.html#safeCall">safeCall</a></li><li><a href="global.html#startContainer">startContainer</a></li><li><a href="global.html#stopContainer">stopContainer</a></li><li><a href="global.html#useContainerActions">useContainerActions</a></li><li><a href="global.html#useContainerCreation">useContainerCreation</a></li><li><a href="global.html#useControls">useControls</a></li><li><a href="global.html#useLogsStream">useLogsStream</a></li><li><a href="global.html#useLogsViewer">useLogsViewer</a></li><li><a href="global.html#validateEnvVars">validateEnvVars</a></li><li><a href="global.html#validatePorts">validatePorts</a></li><li><a href="global.html#withTimeout">withTimeout</a></li></ul>
103
+ </nav>
104
+
105
+ <br class="clear">
106
+
107
+ <footer>
108
+ Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.5</a> on Fri Oct 17 2025 16:07:18 GMT-0500 (hora estándar de Colombia)
109
+ </footer>
110
+
111
+ <script> prettyPrint(); </script>
112
+ <script src="scripts/linenumber.js"> </script>
113
+ </body>
114
+ </html>