cdd-cli 3.2.2 → 4.1.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 (126) hide show
  1. package/README.es.md +222 -0
  2. package/README.md +108 -26
  3. package/dist/App.js +7 -1
  4. package/dist/components/ContainerCreationPrompt.js +26 -10
  5. package/dist/components/ControlsHUD.js +106 -0
  6. package/dist/components/SuggestionPanel.js +16 -7
  7. package/dist/components/UsageMenu.js +1 -1
  8. package/dist/helpers/appState.js +26 -0
  9. package/dist/helpers/constants.js +60 -21
  10. package/dist/helpers/dockerHubService.js +111 -0
  11. package/dist/helpers/dockerService/serviceComponents/containerExec.js +211 -0
  12. package/dist/helpers/logger.js +1 -1
  13. package/dist/hooks/creation/useContainerActions.js +22 -5
  14. package/dist/hooks/creation/useContainerCreation.js +414 -107
  15. package/dist/hooks/useContainerCommandRouter.js +13 -3
  16. package/dist/hooks/useControls.js +28 -7
  17. package/dist/hooks/useShellMode.js +101 -0
  18. package/dist/index.js +10 -1
  19. package/package.json +4 -1
  20. package/.atl/skill-registry.md +0 -30
  21. package/.editorconfig +0 -12
  22. package/.eslintrc.json +0 -30
  23. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -30
  24. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -19
  25. package/.github/PULL_REQUEST_TEMPLATE/pull_request.md +0 -14
  26. package/.github/workflows/ci.yml +0 -32
  27. package/.github/workflows/docs.yml +0 -42
  28. package/.prettierignore +0 -4
  29. package/.prettierrc +0 -8
  30. package/CHANGELOG.md +0 -165
  31. package/CODE_OF_CONDUCT.md +0 -12
  32. package/CONTRIBUTING.md +0 -35
  33. package/SECURITY.md +0 -5
  34. package/__mocks__/ink.cjs +0 -17
  35. package/_config.yml +0 -13
  36. package/babel.config.cjs +0 -23
  37. package/coverage/clover.xml +0 -694
  38. package/coverage/coverage-final.json +0 -21
  39. package/coverage/lcov-report/base.css +0 -224
  40. package/coverage/lcov-report/block-navigation.js +0 -87
  41. package/coverage/lcov-report/components/ContainerCreationPrompt.jsx.html +0 -376
  42. package/coverage/lcov-report/components/PromptField.jsx.html +0 -229
  43. package/coverage/lcov-report/components/SuggestionPanel.jsx.html +0 -244
  44. package/coverage/lcov-report/components/index.html +0 -146
  45. package/coverage/lcov-report/favicon.png +0 -0
  46. package/coverage/lcov-report/helpers/constants.js.html +0 -298
  47. package/coverage/lcov-report/helpers/containerOptionsBuilder.js.html +0 -244
  48. package/coverage/lcov-report/helpers/dockerService/serviceComponents/containerActions.js.html +0 -931
  49. package/coverage/lcov-report/helpers/dockerService/serviceComponents/containerList.js.html +0 -307
  50. package/coverage/lcov-report/helpers/dockerService/serviceComponents/index.html +0 -131
  51. package/coverage/lcov-report/helpers/imageNameUtils.js.html +0 -181
  52. package/coverage/lcov-report/helpers/index.html +0 -191
  53. package/coverage/lcov-report/helpers/logger.js.html +0 -424
  54. package/coverage/lcov-report/helpers/safeCall.js.html +0 -139
  55. package/coverage/lcov-report/helpers/validationHelpers.js.html +0 -346
  56. package/coverage/lcov-report/hooks/creation/index.html +0 -146
  57. package/coverage/lcov-report/hooks/creation/useContainerActions.js.html +0 -313
  58. package/coverage/lcov-report/hooks/creation/useContainerCreation.js.html +0 -805
  59. package/coverage/lcov-report/hooks/creation/useLogsViewer.js.html +0 -238
  60. package/coverage/lcov-report/hooks/debug/index.html +0 -116
  61. package/coverage/lcov-report/hooks/debug/useDebugLogs.js.html +0 -187
  62. package/coverage/lcov-report/hooks/index.html +0 -161
  63. package/coverage/lcov-report/hooks/navigation/index.html +0 -116
  64. package/coverage/lcov-report/hooks/navigation/useContainerSelection.js.html +0 -169
  65. package/coverage/lcov-report/hooks/useContainerCommandRouter.js.html +0 -454
  66. package/coverage/lcov-report/hooks/useControls.js.html +0 -826
  67. package/coverage/lcov-report/hooks/useEraseConfirmation.js.html +0 -202
  68. package/coverage/lcov-report/hooks/useExitHandler.js.html +0 -292
  69. package/coverage/lcov-report/index.html +0 -206
  70. package/coverage/lcov-report/prettify.css +0 -1
  71. package/coverage/lcov-report/prettify.js +0 -2
  72. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  73. package/coverage/lcov-report/sorter.js +0 -210
  74. package/coverage/lcov.info +0 -1402
  75. package/fix-imports.cjs +0 -54
  76. package/jest.config.cjs +0 -14
  77. package/src/App.jsx +0 -96
  78. package/src/components/ContainerCreationPrompt.jsx +0 -97
  79. package/src/components/ContainerList.jsx +0 -32
  80. package/src/components/ContainerRow.jsx +0 -84
  81. package/src/components/ContainerSection.jsx +0 -24
  82. package/src/components/Footer.jsx +0 -15
  83. package/src/components/Header.jsx +0 -41
  84. package/src/components/LogViewer.jsx +0 -36
  85. package/src/components/MessageFeedback.jsx +0 -25
  86. package/src/components/PromptField.jsx +0 -48
  87. package/src/components/StatsBar.jsx +0 -70
  88. package/src/components/SuggestionPanel.jsx +0 -53
  89. package/src/components/UsageMenu.jsx +0 -52
  90. package/src/helpers/appInfo.js +0 -23
  91. package/src/helpers/constants.js +0 -71
  92. package/src/helpers/containerOptionsBuilder.js +0 -53
  93. package/src/helpers/dockerService/dockerService.js +0 -28
  94. package/src/helpers/dockerService/serviceComponents/containerActions.js +0 -282
  95. package/src/helpers/dockerService/serviceComponents/containerList.js +0 -74
  96. package/src/helpers/dockerService/serviceComponents/containerLogs.js +0 -60
  97. package/src/helpers/dockerService/serviceComponents/containerStats.js +0 -69
  98. package/src/helpers/dockerService/serviceComponents/imageUtils.js +0 -32
  99. package/src/helpers/exitWithMessage.js +0 -32
  100. package/src/helpers/imageNameUtils.js +0 -32
  101. package/src/helpers/logger.js +0 -113
  102. package/src/helpers/safeCall.js +0 -18
  103. package/src/helpers/validationHelpers.js +0 -87
  104. package/src/hooks/creation/useContainerActions.js +0 -76
  105. package/src/hooks/creation/useContainerCreation.js +0 -240
  106. package/src/hooks/creation/useLogsViewer.js +0 -51
  107. package/src/hooks/debug/useDebugLogs.js +0 -34
  108. package/src/hooks/navigation/useContainerSelection.js +0 -28
  109. package/src/hooks/useContainerCommandRouter.js +0 -123
  110. package/src/hooks/useContainerStats.js +0 -44
  111. package/src/hooks/useContainers.js +0 -26
  112. package/src/hooks/useControls.js +0 -247
  113. package/src/hooks/useEraseConfirmation.js +0 -39
  114. package/src/hooks/useExitHandler.js +0 -69
  115. package/src/index.js +0 -16
  116. package/test/ContainerCreationPrompt.dom.test.js +0 -68
  117. package/test/SuggestionPanel.dom.test.js +0 -53
  118. package/test/constants.test.js +0 -34
  119. package/test/containerActions.test.js +0 -229
  120. package/test/containerList.test.js +0 -79
  121. package/test/containerOptionsBuilder.test.js +0 -36
  122. package/test/jest.setup.js +0 -7
  123. package/test/safeCall.test.js +0 -25
  124. package/test/useContainerCreation.dom.test.js +0 -264
  125. package/test/useControls.dom.test.js +0 -313
  126. package/test/validationHelpers.test.js +0 -111
package/README.es.md ADDED
@@ -0,0 +1,222 @@
1
+ # CDD — CLI Docker Dashboard
2
+
3
+ <p align="center">
4
+ <img src="https://img.shields.io/npm/v/cdd-cli?color=blue&label=npm%20package" alt="npm version"/>
5
+ <img src="https://img.shields.io/npm/dt/cdd-cli?color=green&label=downloads" alt="npm downloads"/>
6
+ <a href="https://github.com/caertos/cdd/actions/workflows/ci.yml">
7
+ <img src="https://github.com/caertos/cdd/actions/workflows/ci.yml/badge.svg?branch=main" alt="CI status" />
8
+ </a>
9
+ <a href="https://deepwiki.com/Caertos/cdd"><img src="https://deepwiki.com/badge.svg" alt="Ask DeepWiki"></a>
10
+ </p>
11
+
12
+ > **Un dashboard de Docker para la terminal — monitorea, gestiona y crea contenedores sin salir del teclado.**
13
+
14
+ ---
15
+
16
+ ## 🎉 Novedades en v4.1
17
+
18
+ **Abrí un shell dentro de cualquier contenedor con una sola tecla.**
19
+
20
+ Presiona `S` y CDD te lleva a un shell interactivo completo (`bash` o `sh`) dentro del contenedor seleccionado — sin necesidad de escribir `docker exec`.
21
+
22
+ - **Shell auto-detectado** — CDD sondea el contenedor y elige `bash` o `sh` automáticamente
23
+ - **Soporte de terminal completo** — ejecutá `psql`, `python3`, `node`, `redis-cli`, o cualquier comando dentro del contenedor
24
+ - **Salida limpia** — escribí `exit` o presioná `Ctrl+D` para volver al dashboard
25
+
26
+ ---
27
+
28
+ ## Versiones anteriores
29
+
30
+ ### v3.2 — Asistente de creación interactivo
31
+
32
+ Olvídate de los flags de `docker run`, las variables de entorno olvidadas y los tags `:latest` que fallan en silencio. Presiona `C` y CDD te guía para crear un contenedor en segundos:
33
+
34
+ - **20 perfiles de imagen curados** disponibles sin conexión — postgres, redis, nginx, node, mysql, mongo y más
35
+ - **Tags por defecto que realmente funcionan**: `postgres:17-alpine`, `redis:7-alpine`, `nginx:1.27-alpine` — sin más fallos silenciosos por `:latest`
36
+ - **Búsqueda en vivo en Docker Hub** con un solo `Tab` — con indicador `[searching Docker Hub...]` para que siempre sepas qué está pasando
37
+ - **Sugerencias contextuales de variables de entorno** — ¿creando un contenedor de Postgres? CDD sugiere `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_DB` automáticamente
38
+ - **HUD sensible al contexto** — solo se muestran las teclas que tienen sentido en ese momento, nada más
39
+
40
+ Así debería sentirse la experiencia de desarrollo.
41
+
42
+ ---
43
+
44
+ ## Características
45
+
46
+ - 🐳 Vista en vivo de todos los contenedores Docker con estadísticas de CPU/memoria
47
+ - 🔄 Auto-refresco cada pocos segundos — siempre actualizado
48
+ - ⌨️ Acciones controladas por teclado: iniciar, detener, reiniciar, ver logs, eliminar
49
+ - 🎨 Estados de contenedor codificados por color y retroalimentación visual
50
+ - ✨ **Asistente de creación interactivo** — configuración paso a paso con perfiles curados y búsqueda en Hub
51
+ - 🪵 Streaming de logs en tiempo real para el contenedor seleccionado
52
+ - 🐛 Panel de debug en vivo activable con la tecla `D`
53
+
54
+ ---
55
+
56
+ ## Instalación global
57
+
58
+ ```bash
59
+ npm install -g cdd-cli
60
+ cdd
61
+ ```
62
+
63
+ ---
64
+
65
+ ## Inicio rápido (local)
66
+
67
+ ```bash
68
+ git clone https://github.com/caertos/cdd.git
69
+ cd cdd
70
+ npm install
71
+ npm run build
72
+ node dist/index.js
73
+ ```
74
+
75
+ Para usar como comando global durante el desarrollo:
76
+
77
+ ```bash
78
+ npm link
79
+ cdd
80
+ ```
81
+
82
+ ---
83
+
84
+ ## Uso
85
+
86
+ Usa `↑` / `↓` para navegar por los contenedores. Atajos de teclado disponibles:
87
+
88
+ | Tecla | Acción |
89
+ |-------|--------|
90
+ | `↑` / `↓` | Navegar la lista de contenedores |
91
+ | `I` | Iniciar el contenedor seleccionado |
92
+ | `P` | Detener el contenedor seleccionado |
93
+ | `R` | Reiniciar el contenedor seleccionado |
94
+ | `C` | Abrir el asistente de creación |
95
+ | `L` | Ver logs del contenedor seleccionado en tiempo real |
96
+ | `S` | Abrir shell interactivo dentro del contenedor seleccionado |
97
+ | `E` | Eliminar el contenedor seleccionado — requiere confirmación |
98
+ | `D` | Activar/desactivar panel de debug en vivo |
99
+ | `Q` | Salir |
100
+
101
+ ---
102
+
103
+ ## El Asistente de Creación
104
+
105
+ Presiona `C` desde el dashboard para abrir el asistente. Un **HUD sensible al contexto** en la parte inferior siempre muestra qué teclas están activas en cada paso — sin adivinar.
106
+
107
+ ### Paso 0 — Imagen
108
+
109
+ Escribe para filtrar entre **20 perfiles offline curados** (postgres, redis, nginx, node, mysql, mongo, python, golang y más). Los resultados aparecen al instante.
110
+
111
+ Presiona **`Tab`** en cualquier momento para buscar en Docker Hub en vivo. Un indicador `[searching Docker Hub...]` confirma que la búsqueda está en curso. Usa `↑` / `↓` para navegar las sugerencias y `Enter` para seleccionar.
112
+
113
+ **Tags inteligentes por defecto:** al seleccionar un perfil de imagen se aplica automáticamente un tag conocido y funcional — `postgres:17-alpine`, `redis:7-alpine`, `nginx:1.27-alpine`, etc. Sin más contenedores que fallan en silencio por un `:latest` desactualizado.
114
+
115
+ ### Paso 1 — Nombre del contenedor
116
+
117
+ Texto libre. Dale a tu contenedor un nombre memorable.
118
+
119
+ ### Paso 2 — Mapeo de puertos
120
+
121
+ Ingresa un mapeo de puertos en formato `HOST:CONTENEDOR`, por ejemplo `8080:80`, `5432:5432`. Deja en blanco para omitir.
122
+
123
+ ### Paso 3 — Variables de entorno
124
+
125
+ Ingresa pares `CLAVE=VALOR` de a uno. Las **sugerencias contextuales** muestran variables recomendadas para la imagen seleccionada:
126
+
127
+ | Imagen | Variables sugeridas |
128
+ |--------|---------------------|
129
+ | postgres | `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_DB` |
130
+ | mysql | `MYSQL_ROOT_PASSWORD`, `MYSQL_DATABASE` |
131
+ | redis | *(sin variables requeridas)* |
132
+ | mongo | `MONGO_INITDB_ROOT_USERNAME`, `MONGO_INITDB_ROOT_PASSWORD` |
133
+ | node / nginx / otros | Variables de runtime comunes según corresponda |
134
+
135
+ Presiona `Enter` en una línea vacía para terminar y crear el contenedor.
136
+
137
+ ---
138
+
139
+ ## Shell Interactivo
140
+
141
+ Presiona `S` desde el dashboard con un contenedor en ejecución seleccionado. CDD hará lo siguiente:
142
+
143
+ 1. Detectará el shell disponible dentro del contenedor (`bash` o `sh`)
144
+ 2. Abrirá una sesión de terminal interactiva completa
145
+ 3. Te dejará en el shell del contenedor
146
+
147
+ Desde ahí podés ejecutar cualquier comando — `psql` para PostgreSQL, `python3` para Python, `node` para Node.js, `redis-cli` para Redis, etc.
148
+
149
+ Escribí `exit` o presioná `Ctrl+D` para salir del shell y volver al dashboard de CDD.
150
+
151
+ ---
152
+
153
+ ## Requisitos
154
+
155
+ - Node.js >= 18
156
+ - Docker instalado y ejecutándose (CDD se conecta al socket local de Docker)
157
+
158
+ ---
159
+
160
+ ## Desarrollo
161
+
162
+ ```bash
163
+ npm install
164
+ npm run build # compila src/ → dist/
165
+ node dist/index.js # ejecuta desde la salida compilada
166
+ ```
167
+
168
+ Vuelve a ejecutar `npm run build` después de cualquier cambio en el código fuente. Usa `npm link` para probar el comando global `cdd` localmente.
169
+
170
+ ---
171
+
172
+ ## Tests
173
+
174
+ ```bash
175
+ npm test
176
+ ```
177
+
178
+ Los tests están en `test/` y cubren helpers, servicios y hooks.
179
+
180
+ ---
181
+
182
+ ## Logging
183
+
184
+ Por defecto CDD muestra mensajes `info`, `warn` y `error`. Para diagnósticos más detallados:
185
+
186
+ ```bash
187
+ CDD_LOG_LEVEL=debug cdd
188
+ ```
189
+
190
+ Presiona `D` dentro del dashboard para activar el panel de debug en vivo. Presiona `D` nuevamente para ocultarlo.
191
+
192
+ Para capturar los logs en un archivo:
193
+
194
+ ```bash
195
+ CDD_LOG_LEVEL=debug cdd > cdd-debug.log 2>&1
196
+ ```
197
+
198
+ ---
199
+
200
+ ## Solución de problemas
201
+
202
+ - **¿No ves contenedores?** Asegúrate de que Docker esté ejecutándose y de que tu usuario tenga acceso al socket de Docker.
203
+ - **¿Errores de permisos en Linux/macOS?** Prueba con `sudo cdd` o agrega tu usuario al grupo `docker`.
204
+ - **¿Windows?** Ejecuta la terminal como Administrador.
205
+ - **¿Falta el directorio `dist/`?** Ejecuta `npm run build` — está en `.gitignore` y no se incluye en el repositorio.
206
+ - **¿La búsqueda del asistente no funciona?** Verifica tu conexión a internet. Los perfiles offline siempre funcionan sin acceso a la red.
207
+
208
+ ---
209
+
210
+ ## Contribuciones
211
+
212
+ Consulta [CONTRIBUTING.md](CONTRIBUTING.md).
213
+
214
+ ---
215
+
216
+ ## Licencia
217
+
218
+ MIT/ISC — ver [`LICENSE`](LICENSE).
219
+
220
+ ---
221
+
222
+ 🇬🇧 [Read in English](README.md)
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- ## CDD-CLI — Docker Dashboard (Terminal)
1
+ # CDD — CLI Docker Dashboard
2
2
 
3
3
  <p align="center">
4
4
  <img src="https://img.shields.io/npm/v/cdd-cli?color=blue&label=npm%20package" alt="npm version"/>
@@ -6,24 +6,50 @@
6
6
  <a href="https://github.com/caertos/cdd/actions/workflows/ci.yml">
7
7
  <img src="https://github.com/caertos/cdd/actions/workflows/ci.yml/badge.svg?branch=main" alt="CI status" />
8
8
  </a>
9
- <a href="https://caertos.github.io/cdd/">
10
- <img src="https://img.shields.io/badge/docs-GitHub%20Pages-blue" alt="Docs" />
11
- </a>
12
9
  <a href="https://deepwiki.com/Caertos/cdd"><img src="https://deepwiki.com/badge.svg" alt="Ask DeepWiki"></a>
13
10
  </p>
14
11
 
15
- A terminal dashboard for monitoring and managing Docker containers in real time. Shows live CPU/memory stats, supports keyboard-driven actions, and requires no GUI.
12
+ > **A terminal dashboard for Docker containers monitor, manage, and create, all without leaving your keyboard.**
13
+
14
+ ---
15
+
16
+ ## 🎉 What's new in v4.1
17
+
18
+ **Open a shell inside any container with a single keystroke.**
19
+
20
+ Press `S` and CDD drops you into a full interactive shell (`bash` or `sh`) inside the selected container — no `docker exec` typing needed.
21
+
22
+ - **Auto-detected shell** — CDD probes the container and picks `bash` or `sh` automatically
23
+ - **Full terminal support** — run `psql`, `python3`, `node`, `redis-cli`, or any command inside the container
24
+ - **Clean exit** — type `exit` or press `Ctrl+D` to return to the dashboard
25
+
26
+ ---
27
+
28
+ ## Previous releases
29
+
30
+ ### v3.2 — Interactive creation wizard
31
+
32
+ Forget `docker run` flags, forgotten env vars, and broken `:latest` tags. Press `C` and CDD guides you through creating a container in seconds:
33
+
34
+ - **20 curated image profiles** available offline — postgres, redis, nginx, node, mysql, mongo, and more
35
+ - **Smart default tags** that actually work: `postgres:17-alpine`, `redis:7-alpine`, `nginx:1.27-alpine` — no more silent `:latest` failures
36
+ - **Live Docker Hub search** with a single `Tab` keystroke — with a `[searching Docker Hub...]` indicator so you always know what's happening
37
+ - **Contextual env var hints** — creating a Postgres container? CDD suggests `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_DB` automatically
38
+ - **Context-sensitive HUD** — only the keys that make sense right now are shown, nothing more
39
+
40
+ This is what developer experience should feel like.
16
41
 
17
42
  ---
18
43
 
19
44
  ## Features
20
45
 
21
- - 🐳 Clear, compact view of all Docker containers
22
- - 🔄 Auto-refresh every few seconds
23
- - ⌨️ Keyboard shortcuts for fast actions (navigate, start, stop, logs, quit)
24
- - 📊 Live CPU and memory stats for running containers
25
- - 🪵 Real-time log streaming for selected containers
26
- - 🎨 Color-coded states and visual feedback
46
+ - 🐳 Live view of all Docker containers with CPU/memory stats
47
+ - 🔄 Auto-refresh every few seconds — always up to date
48
+ - ⌨️ Keyboard-driven actions: start, stop, restart, log streaming, removal
49
+ - 🎨 Color-coded container states and visual feedback
50
+ - **Interactive creation wizard** — step-by-step container setup with curated profiles and live Hub search
51
+ - 🪵 Real-time log streaming for any selected container
52
+ - 🐛 Toggleable live debug panel (`D` key)
27
53
 
28
54
  ---
29
55
 
@@ -46,7 +72,7 @@ npm run build
46
72
  node dist/index.js
47
73
  ```
48
74
 
49
- To use it as a global command during development:
75
+ To use as a global command during development:
50
76
 
51
77
  ```bash
52
78
  npm link
@@ -57,25 +83,77 @@ cdd
57
83
 
58
84
  ## Usage
59
85
 
60
- Use ↑/↓ to navigate containers. Available keyboard shortcuts:
86
+ Use `↑` / `↓` to navigate containers. Available keyboard shortcuts:
61
87
 
62
88
  | Key | Action |
63
89
  |-----|--------|
90
+ | `↑` / `↓` | Navigate container list |
64
91
  | `I` | Start selected container |
65
92
  | `P` | Stop selected container |
66
93
  | `R` | Restart selected container |
67
- | `C` | Create container (interactive prompt) |
68
- | `L` | View logs for selected container |
94
+ | `C` | Open creation wizard |
95
+ | `L` | Stream logs for selected container |
96
+ | `S` | Open interactive shell inside selected container |
69
97
  | `E` | Erase (remove) selected container — confirmation required |
70
- | `D` | Toggle live debug log panel |
98
+ | `D` | Toggle live debug panel |
71
99
  | `Q` | Quit |
72
100
 
73
101
  ---
74
102
 
103
+ ## The Creation Wizard
104
+
105
+ Press `C` from the dashboard to launch the wizard. A **context-sensitive HUD** at the bottom always shows which keys are active at each step — no guessing required.
106
+
107
+ ### Step 0 — Image
108
+
109
+ Type to filter through **20 curated offline profiles** (postgres, redis, nginx, node, mysql, mongo, python, golang, and more). Results appear instantly.
110
+
111
+ Press **`Tab`** at any time to search Docker Hub live. A `[searching Docker Hub...]` indicator confirms the search is running. Use `↑` / `↓` to navigate suggestions, `Enter` to select.
112
+
113
+ **Smart default tags:** selecting an image profile automatically applies a known-good tag — `postgres:17-alpine`, `redis:7-alpine`, `nginx:1.27-alpine`, etc. No more containers that fail silently because of a stale `:latest`.
114
+
115
+ ### Step 1 — Container name
116
+
117
+ Free-text input. Give your container a memorable name.
118
+
119
+ ### Step 2 — Port mapping
120
+
121
+ Enter a port mapping in `HOST:CONTAINER` format, e.g. `8080:80`, `5432:5432`. Leave blank to skip.
122
+
123
+ ### Step 3 — Environment variables
124
+
125
+ Enter `KEY=VALUE` pairs one at a time. **Contextual hints** show recommended variables for the selected image:
126
+
127
+ | Image | Suggested vars |
128
+ |-------|---------------|
129
+ | postgres | `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_DB` |
130
+ | mysql | `MYSQL_ROOT_PASSWORD`, `MYSQL_DATABASE` |
131
+ | redis | *(no required vars)* |
132
+ | mongo | `MONGO_INITDB_ROOT_USERNAME`, `MONGO_INITDB_ROOT_PASSWORD` |
133
+ | node / nginx / others | Common runtime vars as applicable |
134
+
135
+ Press `Enter` on an empty line to finish and create the container.
136
+
137
+ ---
138
+
139
+ ## Interactive Shell
140
+
141
+ Press `S` from the dashboard while a running container is selected. CDD will:
142
+
143
+ 1. Detect the available shell inside the container (`bash` or `sh`)
144
+ 2. Open a full interactive terminal session
145
+ 3. Drop you into the container's shell
146
+
147
+ From there you can run any command — `psql` for PostgreSQL, `python3` for Python, `node` for Node.js, `redis-cli` for Redis, etc.
148
+
149
+ Type `exit` or press `Ctrl+D` to leave the shell and return to the CDD dashboard.
150
+
151
+ ---
152
+
75
153
  ## Requirements
76
154
 
77
155
  - Node.js >= 18
78
- - Docker installed and running (CLI connects to the local Docker socket)
156
+ - Docker installed and running (CDD connects to the local Docker socket)
79
157
 
80
158
  ---
81
159
 
@@ -87,7 +165,7 @@ npm run build # compile src/ → dist/
87
165
  node dist/index.js # run from compiled output
88
166
  ```
89
167
 
90
- Re-run `npm run build` after any source changes.
168
+ Re-run `npm run build` after any source changes. Use `npm link` to test the global `cdd` command locally.
91
169
 
92
170
  ---
93
171
 
@@ -97,21 +175,19 @@ Re-run `npm run build` after any source changes.
97
175
  npm test
98
176
  ```
99
177
 
100
- Tests are in `test/` and cover helpers, services, and hooks.
178
+ Tests live in `test/` and cover helpers, services, and hooks.
101
179
 
102
180
  ---
103
181
 
104
182
  ## Logging
105
183
 
106
- By default the CLI shows `info`, `warn`, and `error` messages. For deeper diagnostics:
184
+ By default CDD shows `info`, `warn`, and `error` messages. For deeper diagnostics:
107
185
 
108
186
  ```bash
109
187
  CDD_LOG_LEVEL=debug cdd
110
- # or
111
- CDD_LOG_LEVEL=debug node dist/index.js
112
188
  ```
113
189
 
114
- Press `D` inside the CLI to toggle the live debug panel. Press `D` again or `Esc` to hide it.
190
+ Press `D` inside the dashboard to toggle the live debug panel in real time. Press `D` again to hide it.
115
191
 
116
192
  To capture logs to a file:
117
193
 
@@ -123,9 +199,11 @@ CDD_LOG_LEVEL=debug cdd > cdd-debug.log 2>&1
123
199
 
124
200
  ## Troubleshooting
125
201
 
126
- - If you don't see containers, ensure Docker is running and your user has access to the Docker socket.
127
- - On Linux/macOS, try `sudo cdd` if you have permission issues. On Windows, run as Administrator.
128
- - `dist/` is generated by the build — it's in `.gitignore` and should not be committed.
202
+ - **No containers visible?** Make sure Docker is running and your user has access to the Docker socket.
203
+ - **Permission errors on Linux/macOS?** Try `sudo cdd` or add your user to the `docker` group.
204
+ - **Windows?** Run your terminal as Administrator.
205
+ - **`dist/` missing?** Run `npm run build` — it's in `.gitignore` and not committed.
206
+ - **Wizard search not working?** Check your internet connection. Offline profiles always work without network access.
129
207
 
130
208
  ---
131
209
 
@@ -138,3 +216,7 @@ See [CONTRIBUTING.md](CONTRIBUTING.md).
138
216
  ## License
139
217
 
140
218
  MIT/ISC — see [`LICENSE`](LICENSE).
219
+
220
+ ---
221
+
222
+ 🇪🇸 [Ver en Español](README.es.md)
package/dist/App.js CHANGED
@@ -32,7 +32,13 @@ export default function App() {
32
32
  portInput: controls.portInput,
33
33
  envInput: controls.envInput,
34
34
  message: controls.message,
35
- messageColor: controls.messageColor
35
+ messageColor: controls.messageColor,
36
+ suggestions: controls.creation.suggestions,
37
+ selectedSuggestionIndex: controls.creation.selectedSuggestionIndex,
38
+ visibleOffset: controls.creation.visibleOffset,
39
+ isSearchingHub: controls.creation.isSearchingHub,
40
+ hubResults: controls.creation.hubResults,
41
+ hasSuggestedEnv: controls.creation.hasSuggestedEnv
36
42
  });
37
43
  }
38
44
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Box, {
@@ -1,7 +1,8 @@
1
1
  import React from 'react';
2
- import { Box, Text } from 'ink';
2
+ import { Box } from 'ink';
3
3
  import { PromptField, PromptMessage } from './PromptField.js';
4
4
  import { SuggestionPanel } from './SuggestionPanel.js';
5
+ import { ControlsHUD } from './ControlsHUD.js';
5
6
  import PropTypes from 'prop-types';
6
7
 
7
8
  /**
@@ -35,9 +36,15 @@ export default function ContainerCreationPrompt(props) {
35
36
  _props$selectedSugges = props.selectedSuggestionIndex,
36
37
  selectedSuggestionIndex = _props$selectedSugges === void 0 ? -1 : _props$selectedSugges,
37
38
  _props$visibleOffset = props.visibleOffset,
38
- visibleOffset = _props$visibleOffset === void 0 ? 0 : _props$visibleOffset;
39
+ visibleOffset = _props$visibleOffset === void 0 ? 0 : _props$visibleOffset,
40
+ _props$hubResults = props.hubResults,
41
+ hubResults = _props$hubResults === void 0 ? null : _props$hubResults,
42
+ _props$isSearchingHub = props.isSearchingHub,
43
+ isSearchingHub = _props$isSearchingHub === void 0 ? false : _props$isSearchingHub,
44
+ _props$hasSuggestedEn = props.hasSuggestedEnv,
45
+ hasSuggestedEnv = _props$hasSuggestedEn === void 0 ? false : _props$hasSuggestedEn;
39
46
  var prompts = [{
40
- label: 'Name of the image to create (e.g., nginx:latest):',
47
+ label: 'Name of the image to create (e.g., nginx:1.27-alpine):',
41
48
  value: imageName,
42
49
  required: true
43
50
  }, {
@@ -57,7 +64,9 @@ export default function ContainerCreationPrompt(props) {
57
64
  label = _ref.label,
58
65
  value = _ref.value,
59
66
  required = _ref.required;
60
- var showSuggestions = step === 0 && suggestions.length > 0;
67
+ var activeItems = hubResults !== null && hubResults !== void 0 ? hubResults : suggestions;
68
+ var showSuggestions = step === 0 && (isSearchingHub || activeItems.length > 0);
69
+ var hasSuggestions = (suggestions === null || suggestions === void 0 ? void 0 : suggestions.length) > 0 || (hubResults === null || hubResults === void 0 ? void 0 : hubResults.length) > 0;
61
70
  return /*#__PURE__*/React.createElement(Box, {
62
71
  flexDirection: "column",
63
72
  borderStyle: "round",
@@ -68,15 +77,19 @@ export default function ContainerCreationPrompt(props) {
68
77
  value: value,
69
78
  required: required
70
79
  }), showSuggestions && /*#__PURE__*/React.createElement(SuggestionPanel, {
71
- items: suggestions,
80
+ items: activeItems,
72
81
  selectedIndex: selectedSuggestionIndex,
73
- visibleOffset: visibleOffset
82
+ visibleOffset: visibleOffset,
83
+ isLoading: isSearchingHub
74
84
  }), /*#__PURE__*/React.createElement(PromptMessage, {
75
85
  message: message,
76
86
  color: messageColor
77
- }), /*#__PURE__*/React.createElement(Text, {
78
- dimColor: true
79
- }, "Press Enter to continue, Escape to cancel"));
87
+ }), /*#__PURE__*/React.createElement(ControlsHUD, {
88
+ step: step,
89
+ hasSuggestions: hasSuggestions,
90
+ isSearchingHub: isSearchingHub,
91
+ hasSuggestedEnv: hasSuggestedEnv
92
+ }));
80
93
  }
81
94
  ContainerCreationPrompt.propTypes = {
82
95
  step: PropTypes.number.isRequired,
@@ -88,7 +101,10 @@ ContainerCreationPrompt.propTypes = {
88
101
  messageColor: PropTypes.string,
89
102
  suggestions: PropTypes.arrayOf(PropTypes.string),
90
103
  selectedSuggestionIndex: PropTypes.number,
91
- visibleOffset: PropTypes.number
104
+ visibleOffset: PropTypes.number,
105
+ hubResults: PropTypes.arrayOf(PropTypes.string),
106
+ isSearchingHub: PropTypes.bool,
107
+ hasSuggestedEnv: PropTypes.bool
92
108
  };
93
109
 
94
110
  // Named export for test compatibility with jest ESM interop
@@ -0,0 +1,106 @@
1
+ import React from 'react';
2
+ import { Box, Text } from 'ink';
3
+
4
+ /**
5
+ * Returns the contextual keyboard hints for the current wizard state.
6
+ *
7
+ * @param {number} step - Current wizard step (0-3)
8
+ * @param {boolean} hasSuggestions - Whether suggestions/hub results are visible
9
+ * @param {boolean} isSearchingHub - Whether a Hub search is in progress
10
+ * @param {boolean} [hasSuggestedEnv=false] - Whether the image has suggestedEnv entries
11
+ * @returns {{ key: string, label: string }[]}
12
+ */
13
+ function getHints(step, hasSuggestions, isSearchingHub) {
14
+ var hasSuggestedEnv = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
15
+ if (step === 0) {
16
+ if (hasSuggestions) {
17
+ return [{
18
+ key: '↑↓',
19
+ label: 'Navigate'
20
+ }, {
21
+ key: 'Enter',
22
+ label: 'Select'
23
+ }, {
24
+ key: 'Esc',
25
+ label: 'Cancel'
26
+ }];
27
+ }
28
+ var hints = [];
29
+ if (!isSearchingHub) hints.push({
30
+ key: 'Tab',
31
+ label: 'Search Hub'
32
+ });
33
+ hints.push({
34
+ key: '↑↓',
35
+ label: 'Browse'
36
+ });
37
+ hints.push({
38
+ key: 'Enter',
39
+ label: 'Confirm'
40
+ });
41
+ hints.push({
42
+ key: 'Esc',
43
+ label: 'Cancel'
44
+ });
45
+ return hints;
46
+ }
47
+ if (step === 3) {
48
+ var _hints = [];
49
+ if (hasSuggestedEnv) _hints.push({
50
+ key: 'Tab',
51
+ label: 'Insert next env'
52
+ });
53
+ _hints.push({
54
+ key: 'Enter',
55
+ label: 'Continue'
56
+ });
57
+ _hints.push({
58
+ key: 'Esc',
59
+ label: 'Cancel'
60
+ });
61
+ return _hints;
62
+ }
63
+ return [{
64
+ key: 'Enter',
65
+ label: 'Continue'
66
+ }, {
67
+ key: 'Esc',
68
+ label: 'Cancel'
69
+ }];
70
+ }
71
+
72
+ /**
73
+ * Displays a row of contextual keyboard shortcut hints for the active wizard step.
74
+ *
75
+ * @param {Object} props
76
+ * @param {number} props.step - Current wizard step
77
+ * @param {boolean} [props.hasSuggestions=false] - Whether suggestions/hub results are visible
78
+ * @param {boolean} [props.isSearchingHub=false] - Whether a Hub search is in progress
79
+ * @param {boolean} [props.hasSuggestedEnv=false] - Whether the image has suggestedEnv entries
80
+ */
81
+ function ControlsHUD(_ref) {
82
+ var step = _ref.step,
83
+ _ref$hasSuggestions = _ref.hasSuggestions,
84
+ hasSuggestions = _ref$hasSuggestions === void 0 ? false : _ref$hasSuggestions,
85
+ _ref$isSearchingHub = _ref.isSearchingHub,
86
+ isSearchingHub = _ref$isSearchingHub === void 0 ? false : _ref$isSearchingHub,
87
+ _ref$hasSuggestedEnv = _ref.hasSuggestedEnv,
88
+ hasSuggestedEnv = _ref$hasSuggestedEnv === void 0 ? false : _ref$hasSuggestedEnv;
89
+ var hints = getHints(step, hasSuggestions, isSearchingHub, hasSuggestedEnv);
90
+ return /*#__PURE__*/React.createElement(Box, {
91
+ flexDirection: "row",
92
+ columnGap: 2
93
+ }, hints.map(function (_ref2) {
94
+ var key = _ref2.key,
95
+ label = _ref2.label;
96
+ return /*#__PURE__*/React.createElement(Box, {
97
+ key: key
98
+ }, /*#__PURE__*/React.createElement(Text, {
99
+ color: "cyan"
100
+ }, "[", key, "]"), /*#__PURE__*/React.createElement(Text, {
101
+ dimColor: true
102
+ }, " ", label));
103
+ }));
104
+ }
105
+ export default ControlsHUD;
106
+ export { getHints, ControlsHUD };
@@ -19,26 +19,35 @@ export function SuggestionPanel(_ref) {
19
19
  selectedIndex = _ref.selectedIndex,
20
20
  visibleOffset = _ref.visibleOffset,
21
21
  _ref$maxVisible = _ref.maxVisible,
22
- maxVisible = _ref$maxVisible === void 0 ? 6 : _ref$maxVisible;
23
- if (!items || items.length === 0) return null;
24
- var visible = items.slice(visibleOffset, visibleOffset + maxVisible);
22
+ maxVisible = _ref$maxVisible === void 0 ? 6 : _ref$maxVisible,
23
+ _ref$isLoading = _ref.isLoading,
24
+ isLoading = _ref$isLoading === void 0 ? false : _ref$isLoading;
25
+ var hasItems = items && items.length > 0;
26
+ if (!hasItems && !isLoading) return null;
27
+ var visible = hasItems ? items.slice(visibleOffset, visibleOffset + maxVisible) : [];
25
28
  return /*#__PURE__*/React.createElement(Box, {
26
29
  flexDirection: "column",
27
30
  borderStyle: "single",
28
31
  borderColor: "cyan",
29
- paddingX: 1
32
+ paddingX: 1,
33
+ "data-testid": "suggestion-panel"
30
34
  }, visible.map(function (item, localIdx) {
31
35
  var globalIdx = visibleOffset + localIdx;
32
36
  var isFocused = globalIdx === selectedIndex;
33
37
  return /*#__PURE__*/React.createElement(Text, {
34
38
  key: item,
35
- color: isFocused ? 'cyan' : undefined
39
+ color: isFocused ? 'cyan' : undefined,
40
+ dimColor: !isFocused
36
41
  }, isFocused ? "\u203A ".concat(item) : " ".concat(item));
37
- }));
42
+ }), isLoading && /*#__PURE__*/React.createElement(Text, {
43
+ dimColor: true,
44
+ color: "gray"
45
+ }, ' [searching Docker Hub...]'));
38
46
  }
39
47
  SuggestionPanel.propTypes = {
40
48
  items: PropTypes.arrayOf(PropTypes.string).isRequired,
41
49
  selectedIndex: PropTypes.number.isRequired,
42
50
  visibleOffset: PropTypes.number.isRequired,
43
- maxVisible: PropTypes.number
51
+ maxVisible: PropTypes.number,
52
+ isLoading: PropTypes.bool
44
53
  };
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { Box, Text } from 'ink';
3
- var SHORTCUTS = ['Use ↑/↓ for navigation', 'I to initiate selected container', 'P to stop selected container', 'R to restart selected container', 'C to create a container', 'L to view logs of selected container', 'D to toggle debug log panel', 'E to remove selected container', 'Q to quit'];
3
+ var SHORTCUTS = ['Use ↑/↓ for navigation', 'I to initiate selected container', 'P to stop selected container', 'R to restart selected container', 'C to create a container', 'L to view logs of selected container', 'S to open shell in selected container', 'D to toggle debug log panel', 'E to remove selected container', 'Q to quit'];
4
4
  var GRID_COLUMNS = 3;
5
5
 
6
6
  /**