@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,325 +0,0 @@
1
- import { jest } from '@jest/globals';
2
- const mockExeca = jest.fn();
3
- jest.unstable_mockModule('execa', () => ({
4
- execa: mockExeca,
5
- }));
6
- const mockSpinner = {
7
- start: jest.fn(),
8
- succeed: jest.fn(),
9
- fail: jest.fn(),
10
- warn: jest.fn(),
11
- stop: jest.fn(),
12
- text: '',
13
- isSpinning: false,
14
- };
15
- const mockOra = jest.fn(() => mockSpinner);
16
- jest.unstable_mockModule('ora', () => ({
17
- default: mockOra,
18
- }));
19
- let mockSendMessage = jest.fn();
20
- const mockChatClient = jest.fn(() => ({
21
- sendMessage: mockSendMessage,
22
- }));
23
- let mockArkApiProxyInstance = {
24
- start: jest.fn(),
25
- stop: jest.fn(),
26
- };
27
- const mockArkApiProxy = jest.fn(() => mockArkApiProxyInstance);
28
- jest.unstable_mockModule('./arkApiProxy.js', () => ({
29
- ArkApiProxy: mockArkApiProxy,
30
- }));
31
- jest.unstable_mockModule('./chatClient.js', () => ({
32
- ChatClient: mockChatClient,
33
- }));
34
- const mockExit = jest.spyOn(process, 'exit').mockImplementation((() => {
35
- throw new Error('process.exit called');
36
- }));
37
- const mockConsoleLog = jest.spyOn(console, 'log').mockImplementation(() => { });
38
- const mockConsoleError = jest
39
- .spyOn(console, 'error')
40
- .mockImplementation(() => { });
41
- const mockStdoutWrite = jest
42
- .spyOn(process.stdout, 'write')
43
- .mockImplementation(() => true);
44
- const { executeQuery, parseTarget } = await import('./executeQuery.js');
45
- const { ExitCodes } = await import('./errors.js');
46
- describe('executeQuery', () => {
47
- beforeEach(() => {
48
- jest.clearAllMocks();
49
- mockSpinner.start.mockReturnValue(mockSpinner);
50
- mockSpinner.isSpinning = false;
51
- mockSendMessage = jest.fn();
52
- mockChatClient.mockReturnValue({ sendMessage: mockSendMessage });
53
- const startMock = jest.fn();
54
- startMock.mockResolvedValue({});
55
- mockArkApiProxyInstance = {
56
- start: startMock,
57
- stop: jest.fn(),
58
- };
59
- mockArkApiProxy.mockReturnValue(mockArkApiProxyInstance);
60
- });
61
- describe('parseTarget', () => {
62
- it('should parse valid target strings', () => {
63
- expect(parseTarget('model/default')).toEqual({
64
- type: 'model',
65
- name: 'default',
66
- });
67
- expect(parseTarget('agent/weather-agent')).toEqual({
68
- type: 'agent',
69
- name: 'weather-agent',
70
- });
71
- expect(parseTarget('team/my-team')).toEqual({
72
- type: 'team',
73
- name: 'my-team',
74
- });
75
- });
76
- it('should return null for invalid target strings', () => {
77
- expect(parseTarget('invalid')).toBeNull();
78
- expect(parseTarget('')).toBeNull();
79
- expect(parseTarget('model/default/extra')).toBeNull();
80
- });
81
- });
82
- describe('executeQuery with streaming', () => {
83
- it('should execute query with streaming and display chunks', async () => {
84
- mockSendMessage.mockImplementation(async (targetId, messages, options, callback) => {
85
- callback('Hello', undefined, { agent: 'test-agent' });
86
- callback(' world', undefined, { agent: 'test-agent' });
87
- });
88
- await executeQuery({
89
- targetType: 'model',
90
- targetName: 'default',
91
- message: 'Hello',
92
- });
93
- expect(mockArkApiProxy).toHaveBeenCalled();
94
- expect(mockArkApiProxyInstance.start).toHaveBeenCalled();
95
- expect(mockChatClient).toHaveBeenCalled();
96
- expect(mockSendMessage).toHaveBeenCalledWith('model/default', [{ role: 'user', content: 'Hello' }], { streamingEnabled: true }, expect.any(Function));
97
- });
98
- it('should pass sessionId to sendMessage when provided', async () => {
99
- mockSendMessage.mockImplementation(async (targetId, messages, options, callback) => {
100
- callback('Hello', undefined, { agent: 'test-agent' });
101
- });
102
- await executeQuery({
103
- targetType: 'model',
104
- targetName: 'default',
105
- message: 'Hello',
106
- sessionId: 'test-session-123',
107
- });
108
- expect(mockSendMessage).toHaveBeenCalledWith('model/default', [{ role: 'user', content: 'Hello' }], { streamingEnabled: true, sessionId: 'test-session-123' }, expect.any(Function));
109
- expect(mockSpinner.stop).toHaveBeenCalled();
110
- expect(mockArkApiProxyInstance.stop).toHaveBeenCalled();
111
- expect(mockStdoutWrite).toHaveBeenCalled();
112
- });
113
- it('should display agent names with correct formatting', async () => {
114
- mockSendMessage.mockImplementation(async (targetId, messages, options, callback) => {
115
- callback('Response 1', undefined, { agent: 'agent-1' });
116
- callback('Response 2', undefined, { agent: 'agent-2' });
117
- });
118
- await executeQuery({
119
- targetType: 'agent',
120
- targetName: 'test-agent',
121
- message: 'Hello',
122
- });
123
- expect(mockStdoutWrite).toHaveBeenCalled();
124
- const calls = mockStdoutWrite.mock.calls.map((call) => String(call[0]));
125
- expect(calls.some((call) => call.includes('agent-1'))).toBe(true);
126
- expect(calls.some((call) => call.includes('agent-2'))).toBe(true);
127
- });
128
- it('should display team names with diamond prefix', async () => {
129
- mockSendMessage.mockImplementation(async (targetId, messages, options, callback) => {
130
- callback('Team response', undefined, { team: 'my-team' });
131
- });
132
- await executeQuery({
133
- targetType: 'team',
134
- targetName: 'my-team',
135
- message: 'Hello',
136
- });
137
- const calls = mockStdoutWrite.mock.calls.map((call) => String(call[0]));
138
- expect(calls.some((call) => call.includes('◆'))).toBe(true);
139
- expect(calls.some((call) => call.includes('my-team'))).toBe(true);
140
- });
141
- it('should display tool calls', async () => {
142
- mockSendMessage.mockImplementation(async (targetId, messages, options, callback) => {
143
- callback('', [{ id: 1, function: { name: 'get_weather' } }], {
144
- agent: 'weather-agent',
145
- });
146
- callback('The weather is sunny', undefined, {
147
- agent: 'weather-agent',
148
- });
149
- });
150
- await executeQuery({
151
- targetType: 'agent',
152
- targetName: 'weather-agent',
153
- message: 'What is the weather?',
154
- });
155
- const calls = mockStdoutWrite.mock.calls.map((call) => String(call[0]));
156
- expect(calls.some((call) => call.includes('get_weather'))).toBe(true);
157
- expect(calls.some((call) => call.includes('The weather is sunny'))).toBe(true);
158
- });
159
- it('should handle errors and exit with CliError', async () => {
160
- mockSpinner.isSpinning = true;
161
- const startMock = jest.fn();
162
- startMock.mockRejectedValue(new Error('Connection failed'));
163
- mockArkApiProxyInstance.start = startMock;
164
- await expect(executeQuery({
165
- targetType: 'model',
166
- targetName: 'default',
167
- message: 'Hello',
168
- })).rejects.toThrow('process.exit called');
169
- expect(mockSpinner.stop).toHaveBeenCalled();
170
- expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('Connection failed'));
171
- expect(mockExit).toHaveBeenCalledWith(ExitCodes.CliError);
172
- expect(mockArkApiProxyInstance.stop).toHaveBeenCalled();
173
- });
174
- it('should stop spinner when first output arrives', async () => {
175
- mockSpinner.isSpinning = true;
176
- mockSendMessage.mockImplementation(async (targetId, messages, options, callback) => {
177
- callback('First chunk', undefined, { agent: 'test-agent' });
178
- });
179
- await executeQuery({
180
- targetType: 'model',
181
- targetName: 'default',
182
- message: 'Hello',
183
- });
184
- expect(mockSpinner.stop).toHaveBeenCalled();
185
- });
186
- });
187
- describe('executeQuery with output format', () => {
188
- it('should create query and output name format', async () => {
189
- mockExeca.mockImplementation(async (command, args) => {
190
- if (args.includes('apply')) {
191
- return { stdout: '', stderr: '', exitCode: 0 };
192
- }
193
- if (args.includes('wait')) {
194
- return { stdout: '', stderr: '', exitCode: 0 };
195
- }
196
- return { stdout: '', stderr: '', exitCode: 0 };
197
- });
198
- await executeQuery({
199
- targetType: 'model',
200
- targetName: 'default',
201
- message: 'Hello',
202
- outputFormat: 'name',
203
- });
204
- expect(mockExeca).toHaveBeenCalledWith('kubectl', expect.arrayContaining(['apply', '-f', '-']), expect.any(Object));
205
- expect(mockExeca).toHaveBeenCalledWith('kubectl', expect.arrayContaining(['wait', '--for=condition=Completed']), expect.any(Object));
206
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringMatching(/cli-query-\d+/));
207
- });
208
- it('should include sessionId in query manifest when outputFormat is specified', async () => {
209
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
210
- let appliedManifest = '';
211
- mockExeca.mockImplementation(async (command, args) => {
212
- if (args.includes('apply') &&
213
- args.includes('-f') &&
214
- args.includes('-')) {
215
- // Capture the stdin input
216
- const stdinIndex = args.indexOf('-');
217
- if (stdinIndex >= 0 && args[stdinIndex + 1]) {
218
- appliedManifest = args[stdinIndex + 1];
219
- }
220
- return { stdout: '', stderr: '', exitCode: 0 };
221
- }
222
- if (args.includes('wait')) {
223
- return { stdout: '', stderr: '', exitCode: 0 };
224
- }
225
- return { stdout: '', stderr: '', exitCode: 0 };
226
- });
227
- await executeQuery({
228
- targetType: 'model',
229
- targetName: 'default',
230
- message: 'Hello',
231
- outputFormat: 'name',
232
- sessionId: 'test-session-456',
233
- });
234
- // Check that the manifest includes sessionId in spec
235
- const applyCall = mockExeca.mock.calls.find((call) => call[1]?.includes('apply'));
236
- expect(applyCall).toBeDefined();
237
- // The manifest should be passed via stdin, so we need to check the actual call
238
- // Since execa handles stdin separately, we verify the call was made
239
- expect(mockExeca).toHaveBeenCalledWith('kubectl', expect.arrayContaining(['apply', '-f', '-']), expect.any(Object));
240
- });
241
- it('should output json format', async () => {
242
- const mockQuery = {
243
- apiVersion: 'ark.mckinsey.com/v1alpha1',
244
- kind: 'Query',
245
- metadata: { name: 'test-query' },
246
- };
247
- mockExeca.mockImplementation(async (command, args) => {
248
- if (args.includes('apply')) {
249
- return { stdout: '', stderr: '', exitCode: 0 };
250
- }
251
- if (args.includes('wait')) {
252
- return { stdout: '', stderr: '', exitCode: 0 };
253
- }
254
- if (args.includes('get') && args.includes('-o')) {
255
- return { stdout: JSON.stringify(mockQuery), stderr: '', exitCode: 0 };
256
- }
257
- return { stdout: '', stderr: '', exitCode: 0 };
258
- });
259
- await executeQuery({
260
- targetType: 'model',
261
- targetName: 'default',
262
- message: 'Hello',
263
- outputFormat: 'json',
264
- });
265
- expect(mockConsoleLog).toHaveBeenCalledWith(JSON.stringify(mockQuery));
266
- });
267
- it('should output yaml format', async () => {
268
- const mockYaml = 'apiVersion: ark.mckinsey.com/v1alpha1\nkind: Query';
269
- mockExeca.mockImplementation(async (command, args) => {
270
- if (args.includes('apply')) {
271
- return { stdout: '', stderr: '', exitCode: 0 };
272
- }
273
- if (args.includes('wait')) {
274
- return { stdout: '', stderr: '', exitCode: 0 };
275
- }
276
- if (args.includes('get') && args.includes('yaml')) {
277
- return { stdout: mockYaml, stderr: '', exitCode: 0 };
278
- }
279
- return { stdout: '', stderr: '', exitCode: 0 };
280
- });
281
- await executeQuery({
282
- targetType: 'model',
283
- targetName: 'default',
284
- message: 'Hello',
285
- outputFormat: 'yaml',
286
- });
287
- expect(mockConsoleLog).toHaveBeenCalledWith(mockYaml);
288
- });
289
- it('should reject invalid output format', async () => {
290
- mockExeca.mockImplementation(async (command, args) => {
291
- if (args.includes('apply')) {
292
- return { stdout: '', stderr: '', exitCode: 0 };
293
- }
294
- if (args.includes('wait')) {
295
- return { stdout: '', stderr: '', exitCode: 0 };
296
- }
297
- return { stdout: '', stderr: '', exitCode: 0 };
298
- });
299
- await expect(executeQuery({
300
- targetType: 'model',
301
- targetName: 'default',
302
- message: 'Hello',
303
- outputFormat: 'invalid',
304
- })).rejects.toThrow('process.exit called');
305
- expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('Invalid output format'));
306
- expect(mockExit).toHaveBeenCalledWith(ExitCodes.CliError);
307
- });
308
- it('should handle kubectl errors', async () => {
309
- mockExeca.mockImplementation(async (command, args) => {
310
- if (args.includes('apply')) {
311
- throw new Error('kubectl apply failed');
312
- }
313
- return { stdout: '', stderr: '', exitCode: 0 };
314
- });
315
- await expect(executeQuery({
316
- targetType: 'model',
317
- targetName: 'default',
318
- message: 'Hello',
319
- outputFormat: 'name',
320
- })).rejects.toThrow('process.exit called');
321
- expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('kubectl apply failed'));
322
- expect(mockExit).toHaveBeenCalledWith(ExitCodes.CliError);
323
- });
324
- });
325
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,192 +0,0 @@
1
- import { jest } from '@jest/globals';
2
- const mockExeca = jest.fn();
3
- jest.unstable_mockModule('execa', () => ({
4
- execa: mockExeca,
5
- }));
6
- const { getResource, listResources, deleteResource } = await import('./kubectl.js');
7
- describe('kubectl', () => {
8
- beforeEach(() => {
9
- jest.clearAllMocks();
10
- });
11
- describe('getResource', () => {
12
- it('should get a specific resource by name', async () => {
13
- const mockResource = {
14
- metadata: {
15
- name: 'test-query',
16
- creationTimestamp: '2024-01-01T00:00:00Z',
17
- },
18
- spec: {
19
- value: 'test',
20
- },
21
- };
22
- mockExeca.mockResolvedValue({
23
- stdout: JSON.stringify(mockResource),
24
- });
25
- const result = await getResource('queries', 'test-query');
26
- expect(result).toEqual(mockResource);
27
- expect(mockExeca).toHaveBeenCalledWith('kubectl', ['get', 'queries', 'test-query', '-o', 'json'], { stdio: 'pipe' });
28
- });
29
- it('should get latest resource when name is @latest', async () => {
30
- const mockResources = [
31
- {
32
- metadata: {
33
- name: 'query-1',
34
- creationTimestamp: '2024-01-01T00:00:00Z',
35
- },
36
- },
37
- {
38
- metadata: {
39
- name: 'query-2',
40
- creationTimestamp: '2024-01-02T00:00:00Z',
41
- },
42
- },
43
- {
44
- metadata: {
45
- name: 'query-3',
46
- creationTimestamp: '2024-01-03T00:00:00Z',
47
- },
48
- },
49
- ];
50
- mockExeca.mockResolvedValue({
51
- stdout: JSON.stringify({ items: mockResources }),
52
- });
53
- const result = await getResource('queries', '@latest');
54
- expect(result).toEqual(mockResources[2]);
55
- expect(mockExeca).toHaveBeenCalledWith('kubectl', [
56
- 'get',
57
- 'queries',
58
- '--sort-by=.metadata.creationTimestamp',
59
- '-o',
60
- 'json',
61
- ], { stdio: 'pipe' });
62
- });
63
- it('should throw error when @latest finds no resources', async () => {
64
- mockExeca.mockResolvedValue({
65
- stdout: JSON.stringify({ items: [] }),
66
- });
67
- await expect(getResource('queries', '@latest')).rejects.toThrow('No queries found');
68
- });
69
- it('should handle kubectl errors', async () => {
70
- mockExeca.mockRejectedValue(new Error('kubectl error'));
71
- await expect(getResource('queries', 'test-query')).rejects.toThrow('kubectl error');
72
- });
73
- it('should work with different resource types', async () => {
74
- const mockAgent = {
75
- metadata: {
76
- name: 'test-agent',
77
- creationTimestamp: '2024-01-01T00:00:00Z',
78
- },
79
- };
80
- mockExeca.mockResolvedValue({
81
- stdout: JSON.stringify(mockAgent),
82
- });
83
- const result = await getResource('agents', 'test-agent');
84
- expect(result).toEqual(mockAgent);
85
- expect(mockExeca).toHaveBeenCalledWith('kubectl', ['get', 'agents', 'test-agent', '-o', 'json'], { stdio: 'pipe' });
86
- });
87
- });
88
- describe('listResources', () => {
89
- it('should list all resources of a given type', async () => {
90
- const mockResources = [
91
- {
92
- metadata: {
93
- name: 'query-1',
94
- creationTimestamp: '2024-01-01T00:00:00Z',
95
- },
96
- spec: {
97
- value: 'test1',
98
- },
99
- },
100
- {
101
- metadata: {
102
- name: 'query-2',
103
- creationTimestamp: '2024-01-02T00:00:00Z',
104
- },
105
- spec: {
106
- value: 'test2',
107
- },
108
- },
109
- ];
110
- mockExeca.mockResolvedValue({
111
- stdout: JSON.stringify({ items: mockResources }),
112
- });
113
- const result = await listResources('queries');
114
- expect(result).toEqual(mockResources);
115
- expect(mockExeca).toHaveBeenCalledWith('kubectl', ['get', 'queries', '-o', 'json'], { stdio: 'pipe' });
116
- });
117
- it('should return an empty array when no resources exist', async () => {
118
- mockExeca.mockResolvedValue({
119
- stdout: JSON.stringify({ items: [] }),
120
- });
121
- const result = await listResources('queries');
122
- expect(result).toEqual([]);
123
- expect(mockExeca).toHaveBeenCalledWith('kubectl', ['get', 'queries', '-o', 'json'], { stdio: 'pipe' });
124
- });
125
- it('should list resources with custom sort option', async () => {
126
- const mockResources = [
127
- {
128
- metadata: {
129
- name: 'query-1',
130
- creationTimestamp: '2024-01-01T00:00:00Z',
131
- },
132
- },
133
- {
134
- metadata: {
135
- name: 'query-2',
136
- creationTimestamp: '2024-01-02T00:00:00Z',
137
- },
138
- },
139
- ];
140
- mockExeca.mockResolvedValue({
141
- stdout: JSON.stringify({ items: mockResources }),
142
- });
143
- const result = await listResources('queries', {
144
- sortBy: '.metadata.creationTimestamp',
145
- });
146
- expect(result).toEqual(mockResources);
147
- expect(mockExeca).toHaveBeenCalledWith('kubectl', [
148
- 'get',
149
- 'queries',
150
- '--sort-by=.metadata.creationTimestamp',
151
- '-o',
152
- 'json',
153
- ], { stdio: 'pipe' });
154
- });
155
- it('should pass namespace and label filters', async () => {
156
- const result = await listResources('queries', {
157
- labels: 'app=test',
158
- namespace: 'foo'
159
- });
160
- expect(mockExeca).toHaveBeenCalledWith('kubectl', [
161
- 'get',
162
- 'queries',
163
- '-n',
164
- 'foo',
165
- '-l',
166
- 'app=test',
167
- '-o',
168
- 'json',
169
- ], { stdio: 'pipe' });
170
- });
171
- it('should handle kubectl errors when listing resources', async () => {
172
- mockExeca.mockRejectedValue(new Error('kubectl connection error'));
173
- await expect(listResources('queries')).rejects.toThrow('kubectl connection error');
174
- });
175
- });
176
- describe('deleteResource', () => {
177
- it('should delete a resource by name', async () => {
178
- mockExeca.mockResolvedValue({
179
- stdout: '',
180
- });
181
- await deleteResource('queries', 'test-query');
182
- expect(mockExeca).toHaveBeenCalledWith('kubectl', ['delete', 'queries', 'test-query'], { stdio: 'pipe' });
183
- });
184
- it('should delete all resources of a type when all option is true', async () => {
185
- mockExeca.mockResolvedValue({
186
- stdout: '',
187
- });
188
- await deleteResource('queries', undefined, { all: true });
189
- expect(mockExeca).toHaveBeenCalledWith('kubectl', ['delete', 'queries', '--all'], { stdio: 'pipe' });
190
- });
191
- });
192
- });
@@ -1 +0,0 @@
1
- export {};