@agents-at-scale/ark 0.1.53 → 0.1.55

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 (115) hide show
  1. package/dist/commands/export/index.js +6 -4
  2. package/dist/commands/generate/generators/agent.js +2 -0
  3. package/dist/commands/generate/generators/marketplace.js +2 -0
  4. package/dist/commands/generate/generators/mcpserver.js +2 -0
  5. package/dist/commands/generate/generators/project.js +9 -2
  6. package/dist/commands/generate/generators/query.js +2 -0
  7. package/dist/commands/generate/generators/team.js +2 -0
  8. package/dist/commands/generate/templateDiscovery.js +1 -0
  9. package/dist/commands/generate/templateEngine.js +1 -3
  10. package/dist/commands/import/index.js +1 -1
  11. package/dist/commands/install/index.js +2 -1
  12. package/dist/commands/models/kubernetes/manifest-builder.js +27 -10
  13. package/dist/commands/models/providers/azure.d.ts +10 -7
  14. package/dist/commands/models/providers/azure.js +83 -21
  15. package/dist/commands/uninstall/index.js +1 -1
  16. package/dist/components/ChatUI.js +17 -16
  17. package/dist/components/statusChecker.js +3 -3
  18. package/dist/lib/arkApiClient.js +11 -9
  19. package/dist/lib/arkApiProxy.js +1 -0
  20. package/dist/lib/arkServiceProxy.js +5 -1
  21. package/dist/lib/chatClient.js +9 -0
  22. package/dist/lib/config.js +8 -3
  23. package/dist/lib/errors.js +3 -0
  24. package/dist/ui/asyncOperations/connectingToArk.js +2 -2
  25. package/package.json +16 -12
  26. package/dist/arkServices.spec.d.ts +0 -1
  27. package/dist/arkServices.spec.js +0 -138
  28. package/dist/commands/agents/index.spec.d.ts +0 -1
  29. package/dist/commands/agents/index.spec.js +0 -67
  30. package/dist/commands/cluster/get.spec.d.ts +0 -1
  31. package/dist/commands/cluster/get.spec.js +0 -92
  32. package/dist/commands/cluster/index.spec.d.ts +0 -1
  33. package/dist/commands/cluster/index.spec.js +0 -24
  34. package/dist/commands/completion/index.spec.d.ts +0 -1
  35. package/dist/commands/completion/index.spec.js +0 -34
  36. package/dist/commands/config/index.spec.d.ts +0 -1
  37. package/dist/commands/config/index.spec.js +0 -78
  38. package/dist/commands/evaluation/index.spec.d.ts +0 -1
  39. package/dist/commands/evaluation/index.spec.js +0 -161
  40. package/dist/commands/export/index.spec.d.ts +0 -1
  41. package/dist/commands/export/index.spec.js +0 -145
  42. package/dist/commands/import/index.spec.d.ts +0 -1
  43. package/dist/commands/import/index.spec.js +0 -46
  44. package/dist/commands/install/index.spec.d.ts +0 -1
  45. package/dist/commands/install/index.spec.js +0 -286
  46. package/dist/commands/marketplace/index.spec.d.ts +0 -1
  47. package/dist/commands/marketplace/index.spec.js +0 -88
  48. package/dist/commands/memory/index.spec.d.ts +0 -1
  49. package/dist/commands/memory/index.spec.js +0 -124
  50. package/dist/commands/models/create.spec.d.ts +0 -1
  51. package/dist/commands/models/create.spec.js +0 -167
  52. package/dist/commands/models/index.spec.d.ts +0 -1
  53. package/dist/commands/models/index.spec.js +0 -96
  54. package/dist/commands/models/providers/azure.spec.d.ts +0 -1
  55. package/dist/commands/models/providers/azure.spec.js +0 -232
  56. package/dist/commands/models/providers/bedrock.spec.d.ts +0 -1
  57. package/dist/commands/models/providers/bedrock.spec.js +0 -241
  58. package/dist/commands/models/providers/openai.spec.d.ts +0 -1
  59. package/dist/commands/models/providers/openai.spec.js +0 -180
  60. package/dist/commands/queries/delete.spec.d.ts +0 -1
  61. package/dist/commands/queries/delete.spec.js +0 -74
  62. package/dist/commands/queries/index.spec.d.ts +0 -1
  63. package/dist/commands/queries/index.spec.js +0 -167
  64. package/dist/commands/queries/list.spec.d.ts +0 -1
  65. package/dist/commands/queries/list.spec.js +0 -170
  66. package/dist/commands/queries/validation.spec.d.ts +0 -1
  67. package/dist/commands/queries/validation.spec.js +0 -27
  68. package/dist/commands/query/index.spec.d.ts +0 -1
  69. package/dist/commands/query/index.spec.js +0 -104
  70. package/dist/commands/targets/index.spec.d.ts +0 -1
  71. package/dist/commands/targets/index.spec.js +0 -154
  72. package/dist/commands/teams/index.spec.d.ts +0 -1
  73. package/dist/commands/teams/index.spec.js +0 -70
  74. package/dist/commands/tools/index.spec.d.ts +0 -1
  75. package/dist/commands/tools/index.spec.js +0 -70
  76. package/dist/commands/uninstall/index.spec.d.ts +0 -1
  77. package/dist/commands/uninstall/index.spec.js +0 -125
  78. package/dist/lib/arkServiceProxy.spec.d.ts +0 -1
  79. package/dist/lib/arkServiceProxy.spec.js +0 -100
  80. package/dist/lib/arkStatus.spec.d.ts +0 -1
  81. package/dist/lib/arkStatus.spec.js +0 -49
  82. package/dist/lib/chatClient.spec.d.ts +0 -1
  83. package/dist/lib/chatClient.spec.js +0 -108
  84. package/dist/lib/cluster.spec.d.ts +0 -1
  85. package/dist/lib/cluster.spec.js +0 -338
  86. package/dist/lib/commands.spec.d.ts +0 -1
  87. package/dist/lib/commands.spec.js +0 -146
  88. package/dist/lib/config.spec.d.ts +0 -1
  89. package/dist/lib/config.spec.js +0 -202
  90. package/dist/lib/duration.spec.d.ts +0 -1
  91. package/dist/lib/duration.spec.js +0 -13
  92. package/dist/lib/errors.spec.d.ts +0 -1
  93. package/dist/lib/errors.spec.js +0 -221
  94. package/dist/lib/executeQuery.spec.d.ts +0 -1
  95. package/dist/lib/executeQuery.spec.js +0 -325
  96. package/dist/lib/kubectl.spec.d.ts +0 -1
  97. package/dist/lib/kubectl.spec.js +0 -192
  98. package/dist/lib/marketplaceFetcher.spec.d.ts +0 -1
  99. package/dist/lib/marketplaceFetcher.spec.js +0 -225
  100. package/dist/lib/nextSteps.spec.d.ts +0 -1
  101. package/dist/lib/nextSteps.spec.js +0 -59
  102. package/dist/lib/output.spec.d.ts +0 -1
  103. package/dist/lib/output.spec.js +0 -123
  104. package/dist/lib/startup.spec.d.ts +0 -1
  105. package/dist/lib/startup.spec.js +0 -152
  106. package/dist/lib/stdin.spec.d.ts +0 -1
  107. package/dist/lib/stdin.spec.js +0 -82
  108. package/dist/lib/timeout.spec.d.ts +0 -1
  109. package/dist/lib/timeout.spec.js +0 -14
  110. package/dist/lib/waitForReady.spec.d.ts +0 -1
  111. package/dist/lib/waitForReady.spec.js +0 -104
  112. package/dist/marketplaceServices.spec.d.ts +0 -1
  113. package/dist/marketplaceServices.spec.js +0 -74
  114. package/dist/ui/statusFormatter.spec.d.ts +0 -1
  115. package/dist/ui/statusFormatter.spec.js +0 -58
@@ -1,108 +0,0 @@
1
- import { jest } from '@jest/globals';
2
- import { QUERY_ANNOTATIONS } from './constants.js';
3
- const mockCreateChatCompletion = jest.fn();
4
- const mockArkApiClient = {
5
- createChatCompletion: mockCreateChatCompletion,
6
- createChatCompletionStream: jest.fn(),
7
- getQueryTargets: jest.fn(),
8
- };
9
- const { ChatClient } = await import('./chatClient.js');
10
- describe('ChatClient', () => {
11
- beforeEach(() => {
12
- jest.clearAllMocks();
13
- });
14
- describe('sendMessage', () => {
15
- it('should include sessionId directly in metadata when provided', async () => {
16
- const client = new ChatClient(mockArkApiClient);
17
- mockCreateChatCompletion.mockResolvedValue({
18
- id: 'test-id',
19
- object: 'chat.completion',
20
- created: 1234567890,
21
- model: 'test-model',
22
- choices: [
23
- {
24
- index: 0,
25
- message: { role: 'assistant', content: 'Hello' },
26
- finish_reason: 'stop',
27
- },
28
- ],
29
- usage: {
30
- prompt_tokens: 10,
31
- completion_tokens: 5,
32
- total_tokens: 15,
33
- },
34
- });
35
- await client.sendMessage('agent/test-agent', [{ role: 'user', content: 'Hello' }], { streamingEnabled: false, sessionId: 'test-session-123' });
36
- expect(mockCreateChatCompletion).toHaveBeenCalledWith(expect.objectContaining({
37
- model: 'agent/test-agent',
38
- messages: [{ role: 'user', content: 'Hello' }],
39
- metadata: {
40
- sessionId: 'test-session-123',
41
- },
42
- }));
43
- });
44
- it('should include both sessionId in metadata and a2aContextId in queryAnnotations when both provided', async () => {
45
- const client = new ChatClient(mockArkApiClient);
46
- mockCreateChatCompletion.mockResolvedValue({
47
- id: 'test-id',
48
- object: 'chat.completion',
49
- created: 1234567890,
50
- model: 'test-model',
51
- choices: [
52
- {
53
- index: 0,
54
- message: { role: 'assistant', content: 'Hello' },
55
- finish_reason: 'stop',
56
- },
57
- ],
58
- usage: {
59
- prompt_tokens: 10,
60
- completion_tokens: 5,
61
- total_tokens: 15,
62
- },
63
- });
64
- await client.sendMessage('agent/test-agent', [{ role: 'user', content: 'Hello' }], {
65
- streamingEnabled: false,
66
- sessionId: 'test-session-123',
67
- a2aContextId: 'a2a-context-456',
68
- });
69
- expect(mockCreateChatCompletion).toHaveBeenCalled();
70
- const callArgs = mockCreateChatCompletion.mock.calls[0][0];
71
- expect(callArgs.model).toBe('agent/test-agent');
72
- expect(callArgs.messages).toEqual([{ role: 'user', content: 'Hello' }]);
73
- expect(callArgs.metadata).toBeDefined();
74
- expect(callArgs.metadata.sessionId).toBe('test-session-123');
75
- expect(callArgs.metadata.queryAnnotations).toBeDefined();
76
- const queryAnnotations = JSON.parse(callArgs.metadata.queryAnnotations);
77
- expect(queryAnnotations[QUERY_ANNOTATIONS.A2A_CONTEXT_ID]).toBe('a2a-context-456');
78
- });
79
- it('should not include metadata when neither sessionId nor a2aContextId is provided', async () => {
80
- const client = new ChatClient(mockArkApiClient);
81
- mockCreateChatCompletion.mockResolvedValue({
82
- id: 'test-id',
83
- object: 'chat.completion',
84
- created: 1234567890,
85
- model: 'test-model',
86
- choices: [
87
- {
88
- index: 0,
89
- message: { role: 'assistant', content: 'Hello' },
90
- finish_reason: 'stop',
91
- },
92
- ],
93
- usage: {
94
- prompt_tokens: 10,
95
- completion_tokens: 5,
96
- total_tokens: 15,
97
- },
98
- });
99
- await client.sendMessage('agent/test-agent', [{ role: 'user', content: 'Hello' }], { streamingEnabled: false });
100
- expect(mockCreateChatCompletion).toHaveBeenCalledWith(expect.objectContaining({
101
- model: 'agent/test-agent',
102
- messages: [{ role: 'user', content: 'Hello' }],
103
- }));
104
- const callArgs = mockCreateChatCompletion.mock.calls[0];
105
- expect(callArgs[0].metadata).toBeUndefined();
106
- });
107
- });
108
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,338 +0,0 @@
1
- import { jest } from '@jest/globals';
2
- const mockExeca = jest.fn();
3
- jest.unstable_mockModule('execa', () => ({
4
- execa: mockExeca,
5
- }));
6
- const { getClusterInfo, detectClusterType } = await import('./cluster.js');
7
- describe('cluster', () => {
8
- beforeEach(() => {
9
- jest.clearAllMocks();
10
- });
11
- describe('detectClusterType', () => {
12
- it('detects minikube cluster', async () => {
13
- mockExeca.mockResolvedValue({ stdout: 'minikube' });
14
- const result = await detectClusterType();
15
- expect(result).toEqual({ type: 'minikube', context: 'minikube' });
16
- expect(mockExeca).toHaveBeenCalledWith('kubectl', [
17
- 'config',
18
- 'current-context',
19
- ]);
20
- });
21
- it('detects kind cluster', async () => {
22
- mockExeca.mockResolvedValue({ stdout: 'kind-kind' });
23
- const result = await detectClusterType();
24
- expect(result).toEqual({ type: 'kind', context: 'kind-kind' });
25
- });
26
- it('detects k3s cluster', async () => {
27
- mockExeca.mockResolvedValue({ stdout: 'k3s-default' });
28
- const result = await detectClusterType();
29
- expect(result).toEqual({ type: 'k3s', context: 'k3s-default' });
30
- });
31
- it('detects docker-desktop cluster', async () => {
32
- mockExeca.mockResolvedValue({ stdout: 'docker-desktop' });
33
- const result = await detectClusterType();
34
- expect(result).toEqual({
35
- type: 'docker-desktop',
36
- context: 'docker-desktop',
37
- });
38
- });
39
- it('detects gke cloud cluster', async () => {
40
- mockExeca.mockResolvedValue({ stdout: 'gke_project_zone_cluster' });
41
- const result = await detectClusterType();
42
- expect(result).toEqual({
43
- type: 'cloud',
44
- context: 'gke_project_zone_cluster',
45
- });
46
- });
47
- it('detects eks cloud cluster', async () => {
48
- mockExeca.mockResolvedValue({
49
- stdout: 'arn:aws:eks:region:account:cluster/name',
50
- });
51
- const result = await detectClusterType();
52
- expect(result).toEqual({
53
- type: 'cloud',
54
- context: 'arn:aws:eks:region:account:cluster/name',
55
- });
56
- });
57
- it('detects aks cloud cluster', async () => {
58
- mockExeca.mockResolvedValue({ stdout: 'aks-cluster-name' });
59
- const result = await detectClusterType();
60
- expect(result).toEqual({ type: 'cloud', context: 'aks-cluster-name' });
61
- });
62
- it('returns unknown for unrecognized cluster', async () => {
63
- mockExeca.mockResolvedValue({ stdout: 'some-other-cluster' });
64
- const result = await detectClusterType();
65
- expect(result).toEqual({ type: 'unknown', context: 'some-other-cluster' });
66
- });
67
- it('handles kubectl error', async () => {
68
- mockExeca.mockRejectedValue(new Error('kubectl not found'));
69
- const result = await detectClusterType();
70
- expect(result).toEqual({ type: 'unknown', error: 'kubectl not found' });
71
- });
72
- });
73
- describe('getClusterInfo', () => {
74
- const mockConfig = {
75
- 'current-context': 'minikube',
76
- contexts: [
77
- {
78
- name: 'minikube',
79
- context: {
80
- namespace: 'default',
81
- },
82
- },
83
- ],
84
- };
85
- it('gets minikube cluster info with IP', async () => {
86
- mockExeca
87
- .mockResolvedValueOnce({ stdout: JSON.stringify(mockConfig) })
88
- .mockResolvedValueOnce({ stdout: 'minikube' })
89
- .mockResolvedValueOnce({ stdout: '192.168.49.2' });
90
- const result = await getClusterInfo();
91
- expect(result).toEqual({
92
- type: 'minikube',
93
- context: 'minikube',
94
- namespace: 'default',
95
- ip: '192.168.49.2',
96
- });
97
- expect(mockExeca).toHaveBeenCalledWith('kubectl', [
98
- 'config',
99
- 'view',
100
- '--minify',
101
- '-o',
102
- 'json',
103
- ]);
104
- expect(mockExeca).toHaveBeenCalledWith('kubectl', [
105
- 'config',
106
- 'current-context',
107
- ]);
108
- expect(mockExeca).toHaveBeenCalledWith('minikube', ['ip']);
109
- });
110
- it('falls back to kubectl for minikube IP if minikube command fails', async () => {
111
- mockExeca
112
- .mockResolvedValueOnce({ stdout: JSON.stringify(mockConfig) })
113
- .mockResolvedValueOnce({ stdout: 'minikube' })
114
- .mockRejectedValueOnce(new Error('minikube not found'))
115
- .mockResolvedValueOnce({ stdout: '192.168.49.2' });
116
- const result = await getClusterInfo();
117
- expect(result.ip).toBe('192.168.49.2');
118
- expect(mockExeca).toHaveBeenCalledWith('kubectl', [
119
- 'get',
120
- 'nodes',
121
- '-o',
122
- 'jsonpath={.items[0].status.addresses[?(@.type=="InternalIP")].address}',
123
- ]);
124
- });
125
- it('gets kind cluster info with IP', async () => {
126
- const kindConfig = {
127
- 'current-context': 'kind-kind',
128
- contexts: [
129
- {
130
- name: 'kind-kind',
131
- context: {
132
- namespace: 'kube-system',
133
- },
134
- },
135
- ],
136
- };
137
- mockExeca
138
- .mockResolvedValueOnce({ stdout: JSON.stringify(kindConfig) })
139
- .mockResolvedValueOnce({ stdout: 'kind-kind' })
140
- .mockResolvedValueOnce({ stdout: '172.18.0.2' });
141
- const result = await getClusterInfo();
142
- expect(result).toEqual({
143
- type: 'kind',
144
- context: 'kind-kind',
145
- namespace: 'kube-system',
146
- ip: '172.18.0.2',
147
- });
148
- });
149
- it('gets docker-desktop cluster info', async () => {
150
- const dockerConfig = {
151
- 'current-context': 'docker-desktop',
152
- contexts: [
153
- {
154
- name: 'docker-desktop',
155
- context: {},
156
- },
157
- ],
158
- };
159
- mockExeca
160
- .mockResolvedValueOnce({ stdout: JSON.stringify(dockerConfig) })
161
- .mockResolvedValueOnce({ stdout: 'docker-desktop' });
162
- const result = await getClusterInfo();
163
- expect(result).toEqual({
164
- type: 'docker-desktop',
165
- context: 'docker-desktop',
166
- namespace: 'default',
167
- ip: 'localhost',
168
- });
169
- });
170
- it('gets cloud cluster info with load balancer IP', async () => {
171
- const cloudConfig = {
172
- 'current-context': 'gke_project_zone_cluster',
173
- contexts: [
174
- {
175
- name: 'gke_project_zone_cluster',
176
- context: {
177
- namespace: 'production',
178
- },
179
- },
180
- ],
181
- };
182
- mockExeca
183
- .mockResolvedValueOnce({ stdout: JSON.stringify(cloudConfig) })
184
- .mockResolvedValueOnce({ stdout: 'gke_project_zone_cluster' })
185
- .mockResolvedValueOnce({ stdout: '35.201.125.17' });
186
- const result = await getClusterInfo();
187
- expect(result).toEqual({
188
- type: 'cloud',
189
- context: 'gke_project_zone_cluster',
190
- namespace: 'production',
191
- ip: '35.201.125.17',
192
- });
193
- expect(mockExeca).toHaveBeenCalledWith('kubectl', [
194
- 'get',
195
- 'svc',
196
- '-n',
197
- 'istio-system',
198
- 'istio-ingressgateway',
199
- '-o',
200
- 'jsonpath={.status.loadBalancer.ingress[0].ip}',
201
- ]);
202
- });
203
- it('falls back to hostname for cloud cluster if no IP', async () => {
204
- const cloudConfig = {
205
- 'current-context': 'eks-cluster',
206
- contexts: [
207
- {
208
- name: 'eks-cluster',
209
- context: {},
210
- },
211
- ],
212
- };
213
- mockExeca
214
- .mockResolvedValueOnce({ stdout: JSON.stringify(cloudConfig) })
215
- .mockResolvedValueOnce({ stdout: 'eks-cluster' })
216
- .mockResolvedValueOnce({ stdout: '' })
217
- .mockResolvedValueOnce({ stdout: 'a1234.elb.amazonaws.com' });
218
- const result = await getClusterInfo();
219
- expect(result.ip).toBe('a1234.elb.amazonaws.com');
220
- });
221
- it('falls back to external node IP for cloud cluster', async () => {
222
- const cloudConfig = {
223
- 'current-context': 'gke-cluster',
224
- contexts: [
225
- {
226
- name: 'gke-cluster',
227
- context: {},
228
- },
229
- ],
230
- };
231
- mockExeca
232
- .mockResolvedValueOnce({ stdout: JSON.stringify(cloudConfig) })
233
- .mockResolvedValueOnce({ stdout: 'gke-cluster' })
234
- .mockRejectedValueOnce(new Error('service not found'))
235
- .mockResolvedValueOnce({ stdout: '35.201.125.18' });
236
- const result = await getClusterInfo();
237
- expect(result.ip).toBe('35.201.125.18');
238
- expect(mockExeca).toHaveBeenCalledWith('kubectl', [
239
- 'get',
240
- 'nodes',
241
- '-o',
242
- 'jsonpath={.items[0].status.addresses[?(@.type=="ExternalIP")].address}',
243
- ]);
244
- });
245
- it('gets k3s cluster info', async () => {
246
- const k3sConfig = {
247
- 'current-context': 'k3s-default',
248
- contexts: [
249
- {
250
- name: 'k3s-default',
251
- context: {},
252
- },
253
- ],
254
- };
255
- mockExeca
256
- .mockResolvedValueOnce({ stdout: JSON.stringify(k3sConfig) })
257
- .mockResolvedValueOnce({ stdout: 'k3s-default' })
258
- .mockResolvedValueOnce({ stdout: '10.0.0.5' });
259
- const result = await getClusterInfo();
260
- expect(result).toEqual({
261
- type: 'k3s',
262
- context: 'k3s-default',
263
- namespace: 'default',
264
- ip: '10.0.0.5',
265
- });
266
- });
267
- it('uses provided context parameter', async () => {
268
- const multiConfig = {
269
- 'current-context': 'kind-staging',
270
- contexts: [
271
- {
272
- name: 'kind-staging',
273
- context: {
274
- namespace: 'staging-ns',
275
- },
276
- },
277
- ],
278
- };
279
- mockExeca
280
- .mockResolvedValueOnce({ stdout: JSON.stringify(multiConfig) })
281
- .mockResolvedValueOnce({ stdout: 'kind-staging' })
282
- .mockResolvedValueOnce({ stdout: '172.18.0.3' });
283
- const result = await getClusterInfo('kind-staging');
284
- expect(result.context).toBe('kind-staging');
285
- expect(mockExeca).toHaveBeenCalledWith('kubectl', [
286
- 'config',
287
- 'view',
288
- '--minify',
289
- '-o',
290
- 'json',
291
- '--context',
292
- 'kind-staging',
293
- ]);
294
- });
295
- it('handles unknown cluster type', async () => {
296
- const unknownConfig = {
297
- 'current-context': 'custom-cluster',
298
- contexts: [
299
- {
300
- name: 'custom-cluster',
301
- context: {},
302
- },
303
- ],
304
- };
305
- mockExeca
306
- .mockResolvedValueOnce({ stdout: JSON.stringify(unknownConfig) })
307
- .mockResolvedValueOnce({ stdout: 'custom-cluster' })
308
- .mockResolvedValueOnce({ stdout: '10.0.0.1' });
309
- const result = await getClusterInfo();
310
- expect(result).toEqual({
311
- type: 'unknown',
312
- context: 'custom-cluster',
313
- namespace: 'default',
314
- ip: '10.0.0.1',
315
- });
316
- });
317
- it('handles kubectl config error', async () => {
318
- mockExeca.mockRejectedValue(new Error('kubectl not configured'));
319
- const result = await getClusterInfo();
320
- expect(result).toEqual({
321
- type: 'unknown',
322
- error: 'kubectl not configured',
323
- });
324
- });
325
- it('handles missing context in config', async () => {
326
- const emptyConfig = {
327
- contexts: [],
328
- };
329
- mockExeca
330
- .mockResolvedValueOnce({ stdout: JSON.stringify(emptyConfig) })
331
- .mockResolvedValueOnce({ stdout: '' })
332
- .mockResolvedValueOnce({ stdout: '10.0.0.1' });
333
- const result = await getClusterInfo();
334
- expect(result.context).toBe('');
335
- expect(result.namespace).toBe('default');
336
- });
337
- });
338
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,146 +0,0 @@
1
- import { describe, it, expect, jest, beforeEach } from '@jest/globals';
2
- // Mock chalk to avoid ANSI codes in tests
3
- jest.unstable_mockModule('chalk', () => ({
4
- default: {
5
- gray: (str) => str,
6
- },
7
- }));
8
- // Mock execa using unstable_mockModule
9
- jest.unstable_mockModule('execa', () => ({
10
- execa: jest.fn(),
11
- }));
12
- // Dynamic imports after mock
13
- const { execa } = await import('execa');
14
- const { checkCommandExists, execute } = await import('./commands.js');
15
- // Type the mock properly
16
- const mockExeca = execa;
17
- describe('commands', () => {
18
- describe('checkCommandExists', () => {
19
- beforeEach(() => {
20
- jest.clearAllMocks();
21
- });
22
- it('returns true when command executes successfully', async () => {
23
- mockExeca.mockResolvedValue({
24
- stdout: 'v1.0.0',
25
- stderr: '',
26
- exitCode: 0,
27
- });
28
- const result = await checkCommandExists('helm', ['version']);
29
- expect(result).toBe(true);
30
- expect(mockExeca).toHaveBeenCalledWith('helm', ['version']);
31
- });
32
- it('returns false when command fails', async () => {
33
- mockExeca.mockRejectedValue(new Error('Command not found'));
34
- const result = await checkCommandExists('nonexistent', ['--version']);
35
- expect(result).toBe(false);
36
- expect(mockExeca).toHaveBeenCalledWith('nonexistent', ['--version']);
37
- });
38
- it('uses default --version arg when no args provided', async () => {
39
- mockExeca.mockResolvedValue({
40
- stdout: '1.0.0',
41
- stderr: '',
42
- exitCode: 0,
43
- });
44
- const result = await checkCommandExists('node');
45
- expect(result).toBe(true);
46
- expect(mockExeca).toHaveBeenCalledWith('node', ['--version']);
47
- });
48
- it('uses custom args when provided', async () => {
49
- mockExeca.mockResolvedValue({
50
- stdout: 'Client Version: v1.28.0',
51
- stderr: '',
52
- exitCode: 0,
53
- });
54
- const result = await checkCommandExists('kubectl', [
55
- 'version',
56
- '--client',
57
- ]);
58
- expect(result).toBe(true);
59
- expect(mockExeca).toHaveBeenCalledWith('kubectl', [
60
- 'version',
61
- '--client',
62
- ]);
63
- });
64
- it('handles empty args array', async () => {
65
- mockExeca.mockResolvedValue({
66
- stdout: '',
67
- stderr: '',
68
- exitCode: 0,
69
- });
70
- const result = await checkCommandExists('echo', []);
71
- expect(result).toBe(true);
72
- expect(mockExeca).toHaveBeenCalledWith('echo', []);
73
- });
74
- });
75
- describe('execute', () => {
76
- let mockConsoleLog;
77
- beforeEach(() => {
78
- jest.clearAllMocks();
79
- mockConsoleLog = jest.spyOn(console, 'log').mockImplementation(() => { });
80
- });
81
- afterEach(() => {
82
- mockConsoleLog.mockRestore();
83
- });
84
- it('executes command without verbose output by default', async () => {
85
- mockExeca.mockResolvedValue({
86
- stdout: 'success',
87
- stderr: '',
88
- exitCode: 0,
89
- });
90
- await execute('helm', ['install', 'test'], { stdio: 'inherit' });
91
- expect(mockConsoleLog).not.toHaveBeenCalled();
92
- expect(mockExeca).toHaveBeenCalledWith('helm', ['install', 'test'], {
93
- stdio: 'inherit',
94
- });
95
- });
96
- it('prints command when verbose is true', async () => {
97
- mockExeca.mockResolvedValue({
98
- stdout: 'success',
99
- stderr: '',
100
- exitCode: 0,
101
- });
102
- await execute('helm', ['install', 'test'], { stdio: 'inherit' }, { verbose: true });
103
- expect(mockConsoleLog).toHaveBeenCalledWith('$ helm install test');
104
- expect(mockExeca).toHaveBeenCalledWith('helm', ['install', 'test'], {
105
- stdio: 'inherit',
106
- });
107
- });
108
- it('works with empty args array', async () => {
109
- mockExeca.mockResolvedValue({
110
- stdout: '',
111
- stderr: '',
112
- exitCode: 0,
113
- });
114
- await execute('ls', [], {}, { verbose: true });
115
- expect(mockConsoleLog).toHaveBeenCalledWith('$ ls ');
116
- expect(mockExeca).toHaveBeenCalledWith('ls', [], {});
117
- });
118
- it('passes through execa options correctly', async () => {
119
- mockExeca.mockResolvedValue({
120
- stdout: '',
121
- stderr: '',
122
- exitCode: 0,
123
- });
124
- const execaOpts = { stdio: 'pipe', timeout: 5000, cwd: '/tmp' };
125
- await execute('kubectl', ['get', 'pods'], execaOpts);
126
- expect(mockConsoleLog).not.toHaveBeenCalled();
127
- expect(mockExeca).toHaveBeenCalledWith('kubectl', ['get', 'pods'], execaOpts);
128
- });
129
- it('handles command failure', async () => {
130
- const error = new Error('Command failed');
131
- mockExeca.mockRejectedValue(error);
132
- await expect(execute('fail', ['now'])).rejects.toThrow('Command failed');
133
- expect(mockExeca).toHaveBeenCalledWith('fail', ['now'], {});
134
- });
135
- it('defaults to no verbose when additionalOptions not provided', async () => {
136
- mockExeca.mockResolvedValue({
137
- stdout: 'ok',
138
- stderr: '',
139
- exitCode: 0,
140
- });
141
- await execute('echo', ['test']);
142
- expect(mockConsoleLog).not.toHaveBeenCalled();
143
- expect(mockExeca).toHaveBeenCalledWith('echo', ['test'], {});
144
- });
145
- });
146
- });
@@ -1 +0,0 @@
1
- export {};