@agents-at-scale/ark 0.1.52 → 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.
- package/dist/arkServices.js +11 -7
- package/dist/commands/export/index.js +6 -4
- package/dist/commands/generate/generators/agent.js +2 -0
- package/dist/commands/generate/generators/marketplace.js +2 -0
- package/dist/commands/generate/generators/mcpserver.js +2 -0
- package/dist/commands/generate/generators/project.js +9 -2
- package/dist/commands/generate/generators/query.js +2 -0
- package/dist/commands/generate/generators/team.js +2 -0
- package/dist/commands/generate/templateDiscovery.js +1 -0
- package/dist/commands/generate/templateEngine.js +1 -3
- package/dist/commands/import/index.js +1 -1
- package/dist/commands/install/index.js +2 -1
- package/dist/commands/models/kubernetes/manifest-builder.js +27 -10
- package/dist/commands/models/providers/azure.d.ts +10 -7
- package/dist/commands/models/providers/azure.js +83 -21
- package/dist/commands/uninstall/index.js +1 -1
- package/dist/components/ChatUI.js +17 -16
- package/dist/components/statusChecker.js +3 -3
- package/dist/lib/arkApiClient.js +11 -9
- package/dist/lib/arkApiProxy.js +1 -0
- package/dist/lib/arkServiceProxy.js +5 -1
- package/dist/lib/chatClient.js +9 -0
- package/dist/lib/config.js +8 -3
- package/dist/lib/errors.js +3 -0
- package/dist/ui/asyncOperations/connectingToArk.js +2 -2
- package/package.json +17 -13
- package/dist/arkServices.spec.d.ts +0 -1
- package/dist/arkServices.spec.js +0 -138
- package/dist/commands/agents/index.spec.d.ts +0 -1
- package/dist/commands/agents/index.spec.js +0 -67
- package/dist/commands/cluster/get.spec.d.ts +0 -1
- package/dist/commands/cluster/get.spec.js +0 -92
- package/dist/commands/cluster/index.spec.d.ts +0 -1
- package/dist/commands/cluster/index.spec.js +0 -24
- package/dist/commands/completion/index.spec.d.ts +0 -1
- package/dist/commands/completion/index.spec.js +0 -34
- package/dist/commands/config/index.spec.d.ts +0 -1
- package/dist/commands/config/index.spec.js +0 -78
- package/dist/commands/evaluation/index.spec.d.ts +0 -1
- package/dist/commands/evaluation/index.spec.js +0 -161
- package/dist/commands/export/index.spec.d.ts +0 -1
- package/dist/commands/export/index.spec.js +0 -145
- package/dist/commands/import/index.spec.d.ts +0 -1
- package/dist/commands/import/index.spec.js +0 -46
- package/dist/commands/install/index.spec.d.ts +0 -1
- package/dist/commands/install/index.spec.js +0 -286
- package/dist/commands/marketplace/index.spec.d.ts +0 -1
- package/dist/commands/marketplace/index.spec.js +0 -88
- package/dist/commands/memory/index.spec.d.ts +0 -1
- package/dist/commands/memory/index.spec.js +0 -124
- package/dist/commands/models/create.spec.d.ts +0 -1
- package/dist/commands/models/create.spec.js +0 -167
- package/dist/commands/models/index.spec.d.ts +0 -1
- package/dist/commands/models/index.spec.js +0 -96
- package/dist/commands/models/providers/azure.spec.d.ts +0 -1
- package/dist/commands/models/providers/azure.spec.js +0 -232
- package/dist/commands/models/providers/bedrock.spec.d.ts +0 -1
- package/dist/commands/models/providers/bedrock.spec.js +0 -241
- package/dist/commands/models/providers/openai.spec.d.ts +0 -1
- package/dist/commands/models/providers/openai.spec.js +0 -180
- package/dist/commands/queries/delete.spec.d.ts +0 -1
- package/dist/commands/queries/delete.spec.js +0 -74
- package/dist/commands/queries/index.spec.d.ts +0 -1
- package/dist/commands/queries/index.spec.js +0 -167
- package/dist/commands/queries/list.spec.d.ts +0 -1
- package/dist/commands/queries/list.spec.js +0 -170
- package/dist/commands/queries/validation.spec.d.ts +0 -1
- package/dist/commands/queries/validation.spec.js +0 -27
- package/dist/commands/query/index.spec.d.ts +0 -1
- package/dist/commands/query/index.spec.js +0 -104
- package/dist/commands/targets/index.spec.d.ts +0 -1
- package/dist/commands/targets/index.spec.js +0 -154
- package/dist/commands/teams/index.spec.d.ts +0 -1
- package/dist/commands/teams/index.spec.js +0 -70
- package/dist/commands/tools/index.spec.d.ts +0 -1
- package/dist/commands/tools/index.spec.js +0 -70
- package/dist/commands/uninstall/index.spec.d.ts +0 -1
- package/dist/commands/uninstall/index.spec.js +0 -125
- package/dist/lib/arkServiceProxy.spec.d.ts +0 -1
- package/dist/lib/arkServiceProxy.spec.js +0 -100
- package/dist/lib/arkStatus.spec.d.ts +0 -1
- package/dist/lib/arkStatus.spec.js +0 -49
- package/dist/lib/chatClient.spec.d.ts +0 -1
- package/dist/lib/chatClient.spec.js +0 -108
- package/dist/lib/cluster.spec.d.ts +0 -1
- package/dist/lib/cluster.spec.js +0 -338
- package/dist/lib/commands.spec.d.ts +0 -1
- package/dist/lib/commands.spec.js +0 -146
- package/dist/lib/config.spec.d.ts +0 -1
- package/dist/lib/config.spec.js +0 -202
- package/dist/lib/duration.spec.d.ts +0 -1
- package/dist/lib/duration.spec.js +0 -13
- package/dist/lib/errors.spec.d.ts +0 -1
- package/dist/lib/errors.spec.js +0 -221
- package/dist/lib/executeQuery.spec.d.ts +0 -1
- package/dist/lib/executeQuery.spec.js +0 -325
- package/dist/lib/kubectl.spec.d.ts +0 -1
- package/dist/lib/kubectl.spec.js +0 -192
- package/dist/lib/marketplaceFetcher.spec.d.ts +0 -1
- package/dist/lib/marketplaceFetcher.spec.js +0 -225
- package/dist/lib/nextSteps.spec.d.ts +0 -1
- package/dist/lib/nextSteps.spec.js +0 -59
- package/dist/lib/output.spec.d.ts +0 -1
- package/dist/lib/output.spec.js +0 -123
- package/dist/lib/startup.spec.d.ts +0 -1
- package/dist/lib/startup.spec.js +0 -152
- package/dist/lib/stdin.spec.d.ts +0 -1
- package/dist/lib/stdin.spec.js +0 -82
- package/dist/lib/timeout.spec.d.ts +0 -1
- package/dist/lib/timeout.spec.js +0 -14
- package/dist/lib/waitForReady.spec.d.ts +0 -1
- package/dist/lib/waitForReady.spec.js +0 -104
- package/dist/marketplaceServices.spec.d.ts +0 -1
- package/dist/marketplaceServices.spec.js +0 -74
- package/dist/ui/statusFormatter.spec.d.ts +0 -1
- 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 {};
|
package/dist/lib/kubectl.spec.js
DELETED
|
@@ -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 {};
|