cdd-cli 4.0.0 → 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 (130) hide show
  1. package/README.es.md +29 -5
  2. package/README.md +29 -5
  3. package/dist/components/UsageMenu.js +1 -1
  4. package/dist/helpers/appState.js +26 -0
  5. package/dist/helpers/dockerService/serviceComponents/containerExec.js +211 -0
  6. package/dist/hooks/creation/useContainerCreation.js +25 -6
  7. package/dist/hooks/useContainerCommandRouter.js +12 -2
  8. package/dist/hooks/useControls.js +5 -0
  9. package/dist/hooks/useShellMode.js +101 -0
  10. package/dist/index.js +3 -1
  11. package/package.json +4 -1
  12. package/.atl/skill-registry.md +0 -30
  13. package/.editorconfig +0 -12
  14. package/.eslintrc.json +0 -30
  15. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -30
  16. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -19
  17. package/.github/PULL_REQUEST_TEMPLATE/pull_request.md +0 -14
  18. package/.github/workflows/ci.yml +0 -32
  19. package/.github/workflows/docs.yml +0 -42
  20. package/.prettierignore +0 -4
  21. package/.prettierrc +0 -8
  22. package/.~lock.ROADMAP.md# +0 -1
  23. package/CHANGELOG.md +0 -216
  24. package/CODE_OF_CONDUCT.md +0 -12
  25. package/CONTRIBUTING.md +0 -35
  26. package/ROADMAP.md +0 -647
  27. package/SECURITY.md +0 -5
  28. package/__mocks__/ink.cjs +0 -17
  29. package/_config.yml +0 -13
  30. package/babel.config.cjs +0 -23
  31. package/coverage/clover.xml +0 -575
  32. package/coverage/coverage-final.json +0 -17
  33. package/coverage/lcov-report/ContainerCreationPrompt.jsx.html +0 -400
  34. package/coverage/lcov-report/ControlsHUD.jsx.html +0 -256
  35. package/coverage/lcov-report/base.css +0 -224
  36. package/coverage/lcov-report/block-navigation.js +0 -87
  37. package/coverage/lcov-report/components/ContainerCreationPrompt.jsx.html +0 -394
  38. package/coverage/lcov-report/components/PromptField.jsx.html +0 -229
  39. package/coverage/lcov-report/components/SuggestionPanel.jsx.html +0 -268
  40. package/coverage/lcov-report/components/index.html +0 -146
  41. package/coverage/lcov-report/favicon.png +0 -0
  42. package/coverage/lcov-report/helpers/constants.js.html +0 -352
  43. package/coverage/lcov-report/helpers/containerOptionsBuilder.js.html +0 -244
  44. package/coverage/lcov-report/helpers/dockerHubService.js.html +0 -310
  45. package/coverage/lcov-report/helpers/dockerService/serviceComponents/containerActions.js.html +0 -931
  46. package/coverage/lcov-report/helpers/dockerService/serviceComponents/containerList.js.html +0 -307
  47. package/coverage/lcov-report/helpers/dockerService/serviceComponents/index.html +0 -131
  48. package/coverage/lcov-report/helpers/imageNameUtils.js.html +0 -181
  49. package/coverage/lcov-report/helpers/index.html +0 -206
  50. package/coverage/lcov-report/helpers/logger.js.html +0 -424
  51. package/coverage/lcov-report/helpers/safeCall.js.html +0 -139
  52. package/coverage/lcov-report/helpers/validationHelpers.js.html +0 -346
  53. package/coverage/lcov-report/hooks/creation/index.html +0 -146
  54. package/coverage/lcov-report/hooks/creation/useContainerActions.js.html +0 -313
  55. package/coverage/lcov-report/hooks/creation/useContainerCreation.js.html +0 -982
  56. package/coverage/lcov-report/hooks/creation/useLogsViewer.js.html +0 -238
  57. package/coverage/lcov-report/hooks/debug/index.html +0 -116
  58. package/coverage/lcov-report/hooks/debug/useDebugLogs.js.html +0 -187
  59. package/coverage/lcov-report/hooks/index.html +0 -161
  60. package/coverage/lcov-report/hooks/navigation/index.html +0 -116
  61. package/coverage/lcov-report/hooks/navigation/useContainerSelection.js.html +0 -169
  62. package/coverage/lcov-report/hooks/useContainerCommandRouter.js.html +0 -454
  63. package/coverage/lcov-report/hooks/useControls.js.html +0 -868
  64. package/coverage/lcov-report/hooks/useEraseConfirmation.js.html +0 -202
  65. package/coverage/lcov-report/hooks/useExitHandler.js.html +0 -292
  66. package/coverage/lcov-report/index.html +0 -176
  67. package/coverage/lcov-report/prettify.css +0 -1
  68. package/coverage/lcov-report/prettify.js +0 -2
  69. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  70. package/coverage/lcov-report/sorter.js +0 -210
  71. package/coverage/lcov.info +0 -1163
  72. package/fix-imports.cjs +0 -54
  73. package/jest.config.cjs +0 -14
  74. package/src/App.jsx +0 -102
  75. package/src/components/ContainerCreationPrompt.jsx +0 -107
  76. package/src/components/ContainerList.jsx +0 -32
  77. package/src/components/ContainerRow.jsx +0 -84
  78. package/src/components/ContainerSection.jsx +0 -24
  79. package/src/components/ControlsHUD.jsx +0 -66
  80. package/src/components/Footer.jsx +0 -15
  81. package/src/components/Header.jsx +0 -41
  82. package/src/components/LogViewer.jsx +0 -36
  83. package/src/components/MessageFeedback.jsx +0 -25
  84. package/src/components/PromptField.jsx +0 -48
  85. package/src/components/StatsBar.jsx +0 -70
  86. package/src/components/SuggestionPanel.jsx +0 -61
  87. package/src/components/UsageMenu.jsx +0 -52
  88. package/src/helpers/appInfo.js +0 -23
  89. package/src/helpers/constants.js +0 -89
  90. package/src/helpers/containerOptionsBuilder.js +0 -53
  91. package/src/helpers/dockerHubService.js +0 -75
  92. package/src/helpers/dockerService/dockerService.js +0 -28
  93. package/src/helpers/dockerService/serviceComponents/containerActions.js +0 -282
  94. package/src/helpers/dockerService/serviceComponents/containerList.js +0 -74
  95. package/src/helpers/dockerService/serviceComponents/containerLogs.js +0 -60
  96. package/src/helpers/dockerService/serviceComponents/containerStats.js +0 -69
  97. package/src/helpers/dockerService/serviceComponents/imageUtils.js +0 -32
  98. package/src/helpers/exitWithMessage.js +0 -32
  99. package/src/helpers/imageNameUtils.js +0 -32
  100. package/src/helpers/logger.js +0 -112
  101. package/src/helpers/safeCall.js +0 -18
  102. package/src/helpers/validationHelpers.js +0 -87
  103. package/src/hooks/creation/useContainerActions.js +0 -89
  104. package/src/hooks/creation/useContainerCreation.js +0 -377
  105. package/src/hooks/creation/useLogsViewer.js +0 -51
  106. package/src/hooks/debug/useDebugLogs.js +0 -34
  107. package/src/hooks/navigation/useContainerSelection.js +0 -28
  108. package/src/hooks/useContainerCommandRouter.js +0 -123
  109. package/src/hooks/useContainerStats.js +0 -44
  110. package/src/hooks/useContainers.js +0 -26
  111. package/src/hooks/useControls.js +0 -263
  112. package/src/hooks/useEraseConfirmation.js +0 -39
  113. package/src/hooks/useExitHandler.js +0 -69
  114. package/src/index.js +0 -20
  115. package/test/ContainerCreationPrompt.dom.test.js +0 -313
  116. package/test/ControlsHUD.dom.test.js +0 -125
  117. package/test/SuggestionPanel.dom.test.js +0 -83
  118. package/test/constants.test.js +0 -41
  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/dockerHubService.test.js +0 -213
  123. package/test/jest.setup.js +0 -7
  124. package/test/logger.test.js +0 -58
  125. package/test/resolveImageTag.test.js +0 -26
  126. package/test/safeCall.test.js +0 -25
  127. package/test/useContainerCreation.dom.test.js +0 -567
  128. package/test/useContainerCreationHub.dom.test.js +0 -184
  129. package/test/useControls.dom.test.js +0 -519
  130. package/test/validationHelpers.test.js +0 -111
@@ -1,184 +0,0 @@
1
- /**
2
- * @jest-environment jsdom
3
- *
4
- * Tests for Hub-search additions to useContainerCreation:
5
- * - isSearchingHub state
6
- * - hubResults state (string[] after formatHubResult mapping)
7
- * - triggerHubSearch() guards (empty input, already searching)
8
- * - stale response ignored via requestId
9
- * - updateImageInput() aborts in-flight search and clears hubResults
10
- */
11
- import React, { useEffect } from 'react';
12
- import { render, act } from '@testing-library/react';
13
- import { jest } from '@jest/globals';
14
-
15
- // ── Mock dockerHubService BEFORE any import that might pull it in ─────────────
16
- jest.unstable_mockModule('../src/helpers/dockerHubService.js', () => ({
17
- searchDockerHub: jest.fn(),
18
- formatHubResult: jest.fn((r) => r.name), // identity-like stub: returns name string
19
- }));
20
-
21
- // Dynamic import resolves AFTER jest.unstable_mockModule is registered
22
- const { useContainerCreation } = await import('../src/hooks/creation/useContainerCreation.js');
23
- const { searchDockerHub } = await import('../src/helpers/dockerHubService.js');
24
-
25
- const mockSearchDockerHub = searchDockerHub;
26
-
27
- // ── Test harness ─────────────────────────────────────────────────────────────
28
-
29
- function HookTester({ onCreate, onCancel, dbImages, imageProfiles, expose }) {
30
- const hook = useContainerCreation({
31
- onCreate: onCreate ?? (() => {}),
32
- onCancel: onCancel ?? (() => {}),
33
- dbImages: dbImages ?? [],
34
- imageProfiles: imageProfiles ?? {},
35
- });
36
- useEffect(() => {
37
- if (expose) expose.current = hook;
38
- });
39
- return null;
40
- }
41
-
42
- function makeExpose() {
43
- const expose = { current: null };
44
- render(<HookTester expose={expose} />);
45
- return expose;
46
- }
47
-
48
- // ── Tests ─────────────────────────────────────────────────────────────────────
49
-
50
- describe('useContainerCreation — Hub search state', () => {
51
- beforeEach(() => {
52
- mockSearchDockerHub.mockReset();
53
- });
54
-
55
- test('exposes isSearchingHub (initially false) and hubResults (initially null)', () => {
56
- const expose = makeExpose();
57
-
58
- expect(expose.current.isSearchingHub).toBe(false);
59
- expect(expose.current.hubResults).toBeNull();
60
- });
61
-
62
- test('triggerHubSearch() ignores empty imageName', async () => {
63
- const expose = makeExpose();
64
- // imageName is '' by default
65
- await act(async () => {
66
- expose.current.triggerHubSearch();
67
- });
68
- expect(mockSearchDockerHub).not.toHaveBeenCalled();
69
- expect(expose.current.isSearchingHub).toBe(false);
70
- });
71
-
72
- test('triggerHubSearch() sets isSearchingHub=true during the request', async () => {
73
- const expose = makeExpose();
74
- let resolveSearch;
75
- mockSearchDockerHub.mockReturnValue(
76
- new Promise((res) => { resolveSearch = res; })
77
- );
78
-
79
- act(() => { expose.current.updateImageInput('nginx'); });
80
-
81
- let searchPromise;
82
- act(() => { searchPromise = expose.current.triggerHubSearch(); });
83
-
84
- expect(expose.current.isSearchingHub).toBe(true);
85
-
86
- await act(async () => { resolveSearch([]); await searchPromise; });
87
- expect(expose.current.isSearchingHub).toBe(false);
88
- });
89
-
90
- test('triggerHubSearch() ignores call when isSearchingHub is already true', async () => {
91
- const expose = makeExpose();
92
- let resolveFirst;
93
- mockSearchDockerHub.mockReturnValue(
94
- new Promise((res) => { resolveFirst = res; })
95
- );
96
-
97
- act(() => { expose.current.updateImageInput('nginx'); });
98
- act(() => { expose.current.triggerHubSearch(); }); // first call — now searching
99
- expect(expose.current.isSearchingHub).toBe(true);
100
-
101
- // second call — should be ignored
102
- act(() => { expose.current.triggerHubSearch(); });
103
- expect(mockSearchDockerHub).toHaveBeenCalledTimes(1);
104
-
105
- // cleanup
106
- await act(async () => { resolveFirst([]); });
107
- });
108
-
109
- test('triggerHubSearch() stores formatted results (strings) in hubResults on success', async () => {
110
- const expose = makeExpose();
111
- const fakeResults = [
112
- { name: 'library/nginx', isOfficial: true, pullCount: 1e9, description: 'official' },
113
- ];
114
- mockSearchDockerHub.mockResolvedValue(fakeResults);
115
-
116
- act(() => { expose.current.updateImageInput('nginx'); });
117
- await act(async () => { await expose.current.triggerHubSearch(); });
118
-
119
- // hubResults should be string[] (after formatHubResult mapping)
120
- expect(Array.isArray(expose.current.hubResults)).toBe(true);
121
- expect(expose.current.hubResults).toHaveLength(1);
122
- expect(typeof expose.current.hubResults[0]).toBe('string');
123
- expect(expose.current.isSearchingHub).toBe(false);
124
- });
125
-
126
- test('stale response is ignored — only the latest requestId wins', async () => {
127
- const expose = makeExpose();
128
-
129
- let resolveFirst;
130
- let resolveSecond;
131
-
132
- mockSearchDockerHub
133
- .mockReturnValueOnce(new Promise((res) => { resolveFirst = res; }))
134
- .mockReturnValueOnce(new Promise((res) => { resolveSecond = res; }));
135
-
136
- act(() => { expose.current.updateImageInput('nginx'); });
137
- act(() => { expose.current.triggerHubSearch(); }); // request #1 starts, isSearchingHub=true
138
-
139
- // Simulate user typing (aborts #1, clears hub state)
140
- act(() => { expose.current.updateImageInput('ngi'); });
141
- // Now trigger again (request #2)
142
- act(() => { expose.current.triggerHubSearch(); });
143
-
144
- const secondResults = [{ name: 'ngi/x', isOfficial: false, pullCount: 0, description: '' }];
145
-
146
- // Resolve second first (fresh), then first (stale)
147
- await act(async () => { resolveSecond(secondResults); });
148
- await act(async () => { resolveFirst([{ name: 'stale', isOfficial: false, pullCount: 0, description: '' }]); });
149
-
150
- // Only second results should be stored (as strings)
151
- expect(Array.isArray(expose.current.hubResults)).toBe(true);
152
- expect(expose.current.hubResults).toHaveLength(1);
153
- expect(expose.current.hubResults[0]).toBe('ngi/x');
154
- });
155
-
156
- test('updateImageInput() clears hubResults and sets isSearchingHub=false', async () => {
157
- const expose = makeExpose();
158
- mockSearchDockerHub.mockResolvedValue([
159
- { name: 'library/nginx', isOfficial: true, pullCount: 1e9, description: '' },
160
- ]);
161
-
162
- act(() => { expose.current.updateImageInput('nginx'); });
163
- await act(async () => { await expose.current.triggerHubSearch(); });
164
- expect(expose.current.hubResults).not.toBeNull();
165
-
166
- // Typing clears Hub results
167
- act(() => { expose.current.updateImageInput('nginy'); });
168
- expect(expose.current.hubResults).toBeNull();
169
- expect(expose.current.isSearchingHub).toBe(false);
170
- });
171
-
172
- test('failed Hub search (non-abort) sets hubResults=null silently', async () => {
173
- const expose = makeExpose();
174
- mockSearchDockerHub.mockRejectedValue(new Error('Network Error'));
175
-
176
- act(() => { expose.current.updateImageInput('nginx'); });
177
- await act(async () => {
178
- try { await expose.current.triggerHubSearch(); } catch (_) { /* silenced */ }
179
- });
180
-
181
- expect(expose.current.hubResults).toBeNull();
182
- expect(expose.current.isSearchingHub).toBe(false);
183
- });
184
- });