@agents-at-scale/ark 0.1.53 → 0.1.56

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 (141) hide show
  1. package/dist/arkServices.js +14 -0
  2. package/dist/commands/completion/index.js +9 -6
  3. package/dist/commands/export/index.js +6 -5
  4. package/dist/commands/generate/generators/agent.js +2 -0
  5. package/dist/commands/generate/generators/marketplace.js +2 -0
  6. package/dist/commands/generate/generators/mcpserver.js +2 -0
  7. package/dist/commands/generate/generators/project.js +9 -2
  8. package/dist/commands/generate/generators/query.js +2 -0
  9. package/dist/commands/generate/generators/team.js +2 -1
  10. package/dist/commands/generate/templateDiscovery.js +1 -0
  11. package/dist/commands/generate/templateEngine.js +1 -3
  12. package/dist/commands/import/index.js +1 -1
  13. package/dist/commands/install/index.js +35 -31
  14. package/dist/commands/marketplace/index.js +18 -3
  15. package/dist/commands/models/create.js +1 -0
  16. package/dist/commands/models/kubernetes/manifest-builder.js +49 -10
  17. package/dist/commands/models/providers/anthropic.d.ts +15 -0
  18. package/dist/commands/models/providers/anthropic.js +72 -0
  19. package/dist/commands/models/providers/azure.d.ts +10 -7
  20. package/dist/commands/models/providers/azure.js +83 -21
  21. package/dist/commands/models/providers/factory.js +3 -0
  22. package/dist/commands/models/providers/index.d.ts +3 -4
  23. package/dist/commands/models/providers/index.js +1 -0
  24. package/dist/commands/uninstall/index.js +9 -3
  25. package/dist/components/ChatUI.js +21 -33
  26. package/dist/components/statusChecker.js +3 -3
  27. package/dist/index.js +0 -2
  28. package/dist/lib/arkApiClient.d.ts +14 -4
  29. package/dist/lib/arkApiClient.js +61 -42
  30. package/dist/lib/arkApiProxy.js +1 -0
  31. package/dist/lib/arkServiceProxy.js +5 -1
  32. package/dist/lib/chatClient.d.ts +4 -6
  33. package/dist/lib/chatClient.js +138 -95
  34. package/dist/lib/config.js +8 -3
  35. package/dist/lib/errors.d.ts +0 -1
  36. package/dist/lib/errors.js +3 -1
  37. package/dist/lib/marketplaceFetcher.d.ts +1 -0
  38. package/dist/lib/marketplaceFetcher.js +17 -0
  39. package/dist/lib/types.d.ts +0 -38
  40. package/dist/marketplaceServices.d.ts +6 -1
  41. package/dist/marketplaceServices.js +19 -3
  42. package/dist/types/arkService.d.ts +1 -0
  43. package/dist/types/marketplace.d.ts +1 -1
  44. package/dist/ui/asyncOperations/connectingToArk.js +2 -2
  45. package/package.json +19 -13
  46. package/templates/marketplace/marketplace.json.example +2 -2
  47. package/templates/tool/uv.lock +794 -95
  48. package/dist/arkServices.spec.d.ts +0 -1
  49. package/dist/arkServices.spec.js +0 -138
  50. package/dist/commands/agents/index.spec.d.ts +0 -1
  51. package/dist/commands/agents/index.spec.js +0 -67
  52. package/dist/commands/cluster/get.spec.d.ts +0 -1
  53. package/dist/commands/cluster/get.spec.js +0 -92
  54. package/dist/commands/cluster/index.spec.d.ts +0 -1
  55. package/dist/commands/cluster/index.spec.js +0 -24
  56. package/dist/commands/completion/index.spec.d.ts +0 -1
  57. package/dist/commands/completion/index.spec.js +0 -34
  58. package/dist/commands/config/index.spec.d.ts +0 -1
  59. package/dist/commands/config/index.spec.js +0 -78
  60. package/dist/commands/evaluation/index.d.ts +0 -3
  61. package/dist/commands/evaluation/index.js +0 -60
  62. package/dist/commands/evaluation/index.spec.d.ts +0 -1
  63. package/dist/commands/evaluation/index.spec.js +0 -161
  64. package/dist/commands/export/index.spec.d.ts +0 -1
  65. package/dist/commands/export/index.spec.js +0 -145
  66. package/dist/commands/import/index.spec.d.ts +0 -1
  67. package/dist/commands/import/index.spec.js +0 -46
  68. package/dist/commands/install/index.spec.d.ts +0 -1
  69. package/dist/commands/install/index.spec.js +0 -286
  70. package/dist/commands/marketplace/index.spec.d.ts +0 -1
  71. package/dist/commands/marketplace/index.spec.js +0 -88
  72. package/dist/commands/memory/index.spec.d.ts +0 -1
  73. package/dist/commands/memory/index.spec.js +0 -124
  74. package/dist/commands/models/create.spec.d.ts +0 -1
  75. package/dist/commands/models/create.spec.js +0 -167
  76. package/dist/commands/models/index.spec.d.ts +0 -1
  77. package/dist/commands/models/index.spec.js +0 -96
  78. package/dist/commands/models/providers/azure.spec.d.ts +0 -1
  79. package/dist/commands/models/providers/azure.spec.js +0 -232
  80. package/dist/commands/models/providers/bedrock.spec.d.ts +0 -1
  81. package/dist/commands/models/providers/bedrock.spec.js +0 -241
  82. package/dist/commands/models/providers/openai.spec.d.ts +0 -1
  83. package/dist/commands/models/providers/openai.spec.js +0 -180
  84. package/dist/commands/queries/delete.spec.d.ts +0 -1
  85. package/dist/commands/queries/delete.spec.js +0 -74
  86. package/dist/commands/queries/index.spec.d.ts +0 -1
  87. package/dist/commands/queries/index.spec.js +0 -167
  88. package/dist/commands/queries/list.spec.d.ts +0 -1
  89. package/dist/commands/queries/list.spec.js +0 -170
  90. package/dist/commands/queries/validation.spec.d.ts +0 -1
  91. package/dist/commands/queries/validation.spec.js +0 -27
  92. package/dist/commands/query/index.spec.d.ts +0 -1
  93. package/dist/commands/query/index.spec.js +0 -104
  94. package/dist/commands/targets/index.spec.d.ts +0 -1
  95. package/dist/commands/targets/index.spec.js +0 -154
  96. package/dist/commands/teams/index.spec.d.ts +0 -1
  97. package/dist/commands/teams/index.spec.js +0 -70
  98. package/dist/commands/tools/index.spec.d.ts +0 -1
  99. package/dist/commands/tools/index.spec.js +0 -70
  100. package/dist/commands/uninstall/index.spec.d.ts +0 -1
  101. package/dist/commands/uninstall/index.spec.js +0 -125
  102. package/dist/lib/arkServiceProxy.spec.d.ts +0 -1
  103. package/dist/lib/arkServiceProxy.spec.js +0 -100
  104. package/dist/lib/arkStatus.spec.d.ts +0 -1
  105. package/dist/lib/arkStatus.spec.js +0 -49
  106. package/dist/lib/chatClient.spec.d.ts +0 -1
  107. package/dist/lib/chatClient.spec.js +0 -108
  108. package/dist/lib/cluster.spec.d.ts +0 -1
  109. package/dist/lib/cluster.spec.js +0 -338
  110. package/dist/lib/commands.spec.d.ts +0 -1
  111. package/dist/lib/commands.spec.js +0 -146
  112. package/dist/lib/config.spec.d.ts +0 -1
  113. package/dist/lib/config.spec.js +0 -202
  114. package/dist/lib/duration.spec.d.ts +0 -1
  115. package/dist/lib/duration.spec.js +0 -13
  116. package/dist/lib/errors.spec.d.ts +0 -1
  117. package/dist/lib/errors.spec.js +0 -221
  118. package/dist/lib/executeEvaluation.d.ts +0 -16
  119. package/dist/lib/executeEvaluation.js +0 -155
  120. package/dist/lib/executeQuery.spec.d.ts +0 -1
  121. package/dist/lib/executeQuery.spec.js +0 -325
  122. package/dist/lib/kubectl.spec.d.ts +0 -1
  123. package/dist/lib/kubectl.spec.js +0 -192
  124. package/dist/lib/marketplaceFetcher.spec.d.ts +0 -1
  125. package/dist/lib/marketplaceFetcher.spec.js +0 -225
  126. package/dist/lib/nextSteps.spec.d.ts +0 -1
  127. package/dist/lib/nextSteps.spec.js +0 -59
  128. package/dist/lib/output.spec.d.ts +0 -1
  129. package/dist/lib/output.spec.js +0 -123
  130. package/dist/lib/startup.spec.d.ts +0 -1
  131. package/dist/lib/startup.spec.js +0 -152
  132. package/dist/lib/stdin.spec.d.ts +0 -1
  133. package/dist/lib/stdin.spec.js +0 -82
  134. package/dist/lib/timeout.spec.d.ts +0 -1
  135. package/dist/lib/timeout.spec.js +0 -14
  136. package/dist/lib/waitForReady.spec.d.ts +0 -1
  137. package/dist/lib/waitForReady.spec.js +0 -104
  138. package/dist/marketplaceServices.spec.d.ts +0 -1
  139. package/dist/marketplaceServices.spec.js +0 -74
  140. package/dist/ui/statusFormatter.spec.d.ts +0 -1
  141. 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 {};