@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,225 +0,0 @@
|
|
|
1
|
-
import { jest } from '@jest/globals';
|
|
2
|
-
const mockAxiosGet = jest.fn();
|
|
3
|
-
jest.unstable_mockModule('axios', () => ({
|
|
4
|
-
default: {
|
|
5
|
-
get: mockAxiosGet,
|
|
6
|
-
isAxiosError: (error) => {
|
|
7
|
-
return (typeof error === 'object' &&
|
|
8
|
-
error !== null &&
|
|
9
|
-
'isAxiosError' in error &&
|
|
10
|
-
error.isAxiosError === true);
|
|
11
|
-
},
|
|
12
|
-
},
|
|
13
|
-
}));
|
|
14
|
-
const mockGetMarketplaceRepoUrl = jest.fn();
|
|
15
|
-
const mockGetMarketplaceRegistry = jest.fn();
|
|
16
|
-
jest.unstable_mockModule('./config.js', () => ({
|
|
17
|
-
getMarketplaceRepoUrl: mockGetMarketplaceRepoUrl,
|
|
18
|
-
getMarketplaceRegistry: mockGetMarketplaceRegistry,
|
|
19
|
-
}));
|
|
20
|
-
const { fetchMarketplaceManifest, mapMarketplaceItemToArkService, getMarketplaceServicesFromManifest, } = await import('./marketplaceFetcher.js');
|
|
21
|
-
describe('marketplaceFetcher', () => {
|
|
22
|
-
beforeEach(() => {
|
|
23
|
-
jest.clearAllMocks();
|
|
24
|
-
mockAxiosGet.mockClear();
|
|
25
|
-
mockGetMarketplaceRepoUrl.mockReturnValue('https://test-repo.example.com/marketplace');
|
|
26
|
-
mockGetMarketplaceRegistry.mockReturnValue('oci://test-registry.example.com/charts');
|
|
27
|
-
});
|
|
28
|
-
describe('fetchMarketplaceManifest', () => {
|
|
29
|
-
it('fetches and returns manifest successfully', async () => {
|
|
30
|
-
const mockManifest = {
|
|
31
|
-
version: '1.0.0',
|
|
32
|
-
marketplace: 'ARK Marketplace',
|
|
33
|
-
items: [
|
|
34
|
-
{
|
|
35
|
-
name: 'test-service',
|
|
36
|
-
description: 'Test service',
|
|
37
|
-
ark: {
|
|
38
|
-
chartPath: 'oci://registry/test-service',
|
|
39
|
-
namespace: 'test',
|
|
40
|
-
},
|
|
41
|
-
},
|
|
42
|
-
],
|
|
43
|
-
};
|
|
44
|
-
mockAxiosGet.mockResolvedValue({
|
|
45
|
-
data: mockManifest,
|
|
46
|
-
status: 200,
|
|
47
|
-
statusText: 'OK',
|
|
48
|
-
headers: {},
|
|
49
|
-
config: {},
|
|
50
|
-
});
|
|
51
|
-
const result = await fetchMarketplaceManifest();
|
|
52
|
-
expect(result).toEqual(mockManifest);
|
|
53
|
-
expect(mockAxiosGet).toHaveBeenCalledWith(expect.stringContaining('marketplace.json'), expect.objectContaining({
|
|
54
|
-
timeout: 10000,
|
|
55
|
-
headers: { Accept: 'application/json' },
|
|
56
|
-
}));
|
|
57
|
-
});
|
|
58
|
-
it('returns null on network error', async () => {
|
|
59
|
-
const networkError = new Error('Network error');
|
|
60
|
-
networkError.code = 'ENOTFOUND';
|
|
61
|
-
networkError.isAxiosError = true;
|
|
62
|
-
mockAxiosGet.mockRejectedValue(networkError);
|
|
63
|
-
const result = await fetchMarketplaceManifest();
|
|
64
|
-
expect(result).toBeNull();
|
|
65
|
-
});
|
|
66
|
-
it('returns null on connection refused', async () => {
|
|
67
|
-
const connectionError = Object.assign(new Error('Connection refused'), {
|
|
68
|
-
code: 'ECONNREFUSED',
|
|
69
|
-
isAxiosError: true,
|
|
70
|
-
});
|
|
71
|
-
mockAxiosGet.mockRejectedValue(connectionError);
|
|
72
|
-
const result = await fetchMarketplaceManifest();
|
|
73
|
-
expect(result).toBeNull();
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
describe('mapMarketplaceItemToArkService', () => {
|
|
77
|
-
it('maps marketplace item to ARK service correctly', () => {
|
|
78
|
-
const item = {
|
|
79
|
-
name: 'test-service',
|
|
80
|
-
description: 'Test description',
|
|
81
|
-
ark: {
|
|
82
|
-
chartPath: 'oci://registry/test',
|
|
83
|
-
namespace: 'test-ns',
|
|
84
|
-
helmReleaseName: 'test-release',
|
|
85
|
-
installArgs: ['--create-namespace'],
|
|
86
|
-
k8sServiceName: 'test-svc',
|
|
87
|
-
k8sServicePort: 8080,
|
|
88
|
-
k8sDeploymentName: 'test-deploy',
|
|
89
|
-
},
|
|
90
|
-
};
|
|
91
|
-
const result = mapMarketplaceItemToArkService(item);
|
|
92
|
-
expect(result).toEqual({
|
|
93
|
-
name: 'test-service',
|
|
94
|
-
helmReleaseName: 'test-release',
|
|
95
|
-
description: 'Test description',
|
|
96
|
-
enabled: true,
|
|
97
|
-
category: 'marketplace',
|
|
98
|
-
namespace: 'test-ns',
|
|
99
|
-
chartPath: 'oci://registry/test',
|
|
100
|
-
installArgs: ['--create-namespace'],
|
|
101
|
-
k8sServiceName: 'test-svc',
|
|
102
|
-
k8sServicePort: 8080,
|
|
103
|
-
k8sDeploymentName: 'test-deploy',
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
it('uses defaults when ark fields are missing', () => {
|
|
107
|
-
const item = {
|
|
108
|
-
name: 'simple-service',
|
|
109
|
-
description: 'Simple service',
|
|
110
|
-
ark: {},
|
|
111
|
-
};
|
|
112
|
-
const result = mapMarketplaceItemToArkService(item);
|
|
113
|
-
expect(result.name).toBe('simple-service');
|
|
114
|
-
expect(result.helmReleaseName).toBe('simple-service');
|
|
115
|
-
expect(result.namespace).toBe('simple-service');
|
|
116
|
-
expect(result.chartPath).toContain('simple-service');
|
|
117
|
-
});
|
|
118
|
-
it('sanitizes service name', () => {
|
|
119
|
-
const item = {
|
|
120
|
-
name: 'Test Service 123!',
|
|
121
|
-
description: 'Test',
|
|
122
|
-
ark: {},
|
|
123
|
-
};
|
|
124
|
-
const result = mapMarketplaceItemToArkService(item);
|
|
125
|
-
expect(result.name).toBe('test-service-123');
|
|
126
|
-
});
|
|
127
|
-
});
|
|
128
|
-
describe('getMarketplaceServicesFromManifest', () => {
|
|
129
|
-
it('converts manifest items to service collection', async () => {
|
|
130
|
-
const mockManifest = {
|
|
131
|
-
version: '1.0.0',
|
|
132
|
-
marketplace: 'ARK Marketplace',
|
|
133
|
-
items: [
|
|
134
|
-
{
|
|
135
|
-
name: 'service1',
|
|
136
|
-
description: 'Service 1',
|
|
137
|
-
type: 'service',
|
|
138
|
-
ark: {
|
|
139
|
-
chartPath: 'oci://registry/service1',
|
|
140
|
-
namespace: 'ns1',
|
|
141
|
-
},
|
|
142
|
-
},
|
|
143
|
-
{
|
|
144
|
-
name: 'service2',
|
|
145
|
-
description: 'Service 2',
|
|
146
|
-
type: 'service',
|
|
147
|
-
ark: {
|
|
148
|
-
chartPath: 'oci://registry/service2',
|
|
149
|
-
namespace: 'ns2',
|
|
150
|
-
},
|
|
151
|
-
},
|
|
152
|
-
],
|
|
153
|
-
};
|
|
154
|
-
mockAxiosGet.mockResolvedValue({
|
|
155
|
-
data: mockManifest,
|
|
156
|
-
status: 200,
|
|
157
|
-
statusText: 'OK',
|
|
158
|
-
headers: {},
|
|
159
|
-
config: {},
|
|
160
|
-
});
|
|
161
|
-
const result = await getMarketplaceServicesFromManifest();
|
|
162
|
-
expect(result).not.toBeNull();
|
|
163
|
-
expect(result?.['service1']).toBeDefined();
|
|
164
|
-
expect(result?.['service2']).toBeDefined();
|
|
165
|
-
expect(result?.['service1']?.description).toBe('Service 1');
|
|
166
|
-
expect(result?.['service2']?.description).toBe('Service 2');
|
|
167
|
-
});
|
|
168
|
-
it('filters out items without ark field', async () => {
|
|
169
|
-
const mockManifest = {
|
|
170
|
-
version: '1.0.0',
|
|
171
|
-
marketplace: 'ARK Marketplace',
|
|
172
|
-
items: [
|
|
173
|
-
{
|
|
174
|
-
name: 'service1',
|
|
175
|
-
description: 'Service 1',
|
|
176
|
-
type: 'service',
|
|
177
|
-
ark: {
|
|
178
|
-
chartPath: 'oci://registry/service1',
|
|
179
|
-
},
|
|
180
|
-
},
|
|
181
|
-
{
|
|
182
|
-
name: 'service2',
|
|
183
|
-
description: 'Service 2',
|
|
184
|
-
type: 'service',
|
|
185
|
-
},
|
|
186
|
-
],
|
|
187
|
-
};
|
|
188
|
-
mockAxiosGet.mockResolvedValue({
|
|
189
|
-
data: mockManifest,
|
|
190
|
-
status: 200,
|
|
191
|
-
statusText: 'OK',
|
|
192
|
-
headers: {},
|
|
193
|
-
config: {},
|
|
194
|
-
});
|
|
195
|
-
const result = await getMarketplaceServicesFromManifest();
|
|
196
|
-
expect(result).not.toBeNull();
|
|
197
|
-
expect(result?.['service1']).toBeDefined();
|
|
198
|
-
expect(result?.['service2']).toBeUndefined();
|
|
199
|
-
});
|
|
200
|
-
it('returns null when manifest fetch fails', async () => {
|
|
201
|
-
const networkError = new Error('Network error');
|
|
202
|
-
networkError.code = 'ENOTFOUND';
|
|
203
|
-
networkError.isAxiosError = true;
|
|
204
|
-
mockAxiosGet.mockRejectedValue(networkError);
|
|
205
|
-
const result = await getMarketplaceServicesFromManifest();
|
|
206
|
-
expect(result).toBeNull();
|
|
207
|
-
});
|
|
208
|
-
it('returns null when manifest has no items', async () => {
|
|
209
|
-
const mockManifest = {
|
|
210
|
-
version: '1.0.0',
|
|
211
|
-
marketplace: 'ARK Marketplace',
|
|
212
|
-
items: [],
|
|
213
|
-
};
|
|
214
|
-
mockAxiosGet.mockResolvedValue({
|
|
215
|
-
data: mockManifest,
|
|
216
|
-
status: 200,
|
|
217
|
-
statusText: 'OK',
|
|
218
|
-
headers: {},
|
|
219
|
-
config: {},
|
|
220
|
-
});
|
|
221
|
-
const result = await getMarketplaceServicesFromManifest();
|
|
222
|
-
expect(result).toBeNull();
|
|
223
|
-
});
|
|
224
|
-
});
|
|
225
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { jest } from '@jest/globals';
|
|
2
|
-
import { printNextSteps } from './nextSteps.js';
|
|
3
|
-
describe('printNextSteps', () => {
|
|
4
|
-
let consoleLogSpy;
|
|
5
|
-
let output = [];
|
|
6
|
-
beforeEach(() => {
|
|
7
|
-
output = [];
|
|
8
|
-
consoleLogSpy = jest.spyOn(console, 'log').mockImplementation((...args) => {
|
|
9
|
-
output.push(args.join(' '));
|
|
10
|
-
});
|
|
11
|
-
});
|
|
12
|
-
afterEach(() => {
|
|
13
|
-
consoleLogSpy.mockRestore();
|
|
14
|
-
});
|
|
15
|
-
it('prints successful installation message', () => {
|
|
16
|
-
printNextSteps();
|
|
17
|
-
const fullOutput = output.join('\n');
|
|
18
|
-
expect(fullOutput).toContain('✓ Installation complete');
|
|
19
|
-
});
|
|
20
|
-
it('includes all required commands', () => {
|
|
21
|
-
printNextSteps();
|
|
22
|
-
const fullOutput = output.join('\n');
|
|
23
|
-
// Check for each command
|
|
24
|
-
expect(fullOutput).toContain('ark models create default');
|
|
25
|
-
expect(fullOutput).toContain('ark dashboard');
|
|
26
|
-
expect(fullOutput).toContain('kubectl get agents');
|
|
27
|
-
expect(fullOutput).toContain('ark query model/default "What are large language models?"');
|
|
28
|
-
expect(fullOutput).toContain('ark');
|
|
29
|
-
expect(fullOutput).toContain("# then choose 'Chat'");
|
|
30
|
-
expect(fullOutput).toContain('ark generate project my-agents');
|
|
31
|
-
});
|
|
32
|
-
it('includes all required links', () => {
|
|
33
|
-
printNextSteps();
|
|
34
|
-
const fullOutput = output.join('\n');
|
|
35
|
-
// Check for documentation links
|
|
36
|
-
expect(fullOutput).toContain('https://mckinsey.github.io/agents-at-scale-ark/');
|
|
37
|
-
expect(fullOutput).toContain('https://mckinsey.github.io/agents-at-scale-ark/developer-guide/cli-tools/');
|
|
38
|
-
});
|
|
39
|
-
it('includes all section labels', () => {
|
|
40
|
-
printNextSteps();
|
|
41
|
-
const fullOutput = output.join('\n');
|
|
42
|
-
// Check for labels
|
|
43
|
-
expect(fullOutput).toContain('Next steps:');
|
|
44
|
-
expect(fullOutput).toContain('docs:');
|
|
45
|
-
expect(fullOutput).toContain('create model:');
|
|
46
|
-
expect(fullOutput).toContain('open dashboard:');
|
|
47
|
-
expect(fullOutput).toContain('show agents:');
|
|
48
|
-
expect(fullOutput).toContain('run a query:');
|
|
49
|
-
expect(fullOutput).toContain('interactive chat:');
|
|
50
|
-
expect(fullOutput).toContain('new project:');
|
|
51
|
-
expect(fullOutput).toContain('install fark:');
|
|
52
|
-
});
|
|
53
|
-
it('has correct structure with empty lines', () => {
|
|
54
|
-
printNextSteps();
|
|
55
|
-
// Should have empty lines for formatting
|
|
56
|
-
expect(output[0]).toBe('');
|
|
57
|
-
expect(output[output.length - 1]).toBe('');
|
|
58
|
-
});
|
|
59
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/lib/output.spec.js
DELETED
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach, jest } from '@jest/globals';
|
|
2
|
-
import chalk from 'chalk';
|
|
3
|
-
import output from './output.js';
|
|
4
|
-
describe('output', () => {
|
|
5
|
-
let consoleErrorSpy;
|
|
6
|
-
let consoleLogSpy;
|
|
7
|
-
beforeEach(() => {
|
|
8
|
-
consoleErrorSpy = jest
|
|
9
|
-
.spyOn(console, 'error')
|
|
10
|
-
.mockImplementation(() => undefined);
|
|
11
|
-
consoleLogSpy = jest
|
|
12
|
-
.spyOn(console, 'log')
|
|
13
|
-
.mockImplementation(() => undefined);
|
|
14
|
-
});
|
|
15
|
-
afterEach(() => {
|
|
16
|
-
jest.clearAllMocks();
|
|
17
|
-
});
|
|
18
|
-
describe('error', () => {
|
|
19
|
-
it('should output error message with red cross and prefix', () => {
|
|
20
|
-
output.error('Something went wrong');
|
|
21
|
-
expect(consoleErrorSpy).toHaveBeenCalledWith(chalk.red('✗'), chalk.red('error:'), 'Something went wrong');
|
|
22
|
-
});
|
|
23
|
-
it('should handle additional arguments', () => {
|
|
24
|
-
const error = new Error('Test error');
|
|
25
|
-
output.error('Failed to connect', error, 123);
|
|
26
|
-
expect(consoleErrorSpy).toHaveBeenCalledWith(chalk.red('✗'), chalk.red('error:'), 'Failed to connect', error, 123);
|
|
27
|
-
});
|
|
28
|
-
});
|
|
29
|
-
describe('success', () => {
|
|
30
|
-
it('should output success message with green checkmark', () => {
|
|
31
|
-
output.success('Operation completed');
|
|
32
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(chalk.green('✓'), 'Operation completed');
|
|
33
|
-
});
|
|
34
|
-
it('should handle additional arguments', () => {
|
|
35
|
-
output.success('Deployed', 'v1.0.0', { status: 'ok' });
|
|
36
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(chalk.green('✓'), 'Deployed', 'v1.0.0', { status: 'ok' });
|
|
37
|
-
});
|
|
38
|
-
});
|
|
39
|
-
describe('info', () => {
|
|
40
|
-
it('should output info message in gray', () => {
|
|
41
|
-
output.info('Processing request...');
|
|
42
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(chalk.gray('Processing request...'));
|
|
43
|
-
});
|
|
44
|
-
it('should handle additional arguments', () => {
|
|
45
|
-
output.info('Status:', 'running', 42);
|
|
46
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(chalk.gray('Status:'), 'running', 42);
|
|
47
|
-
});
|
|
48
|
-
});
|
|
49
|
-
describe('warning', () => {
|
|
50
|
-
it('should output warning message with yellow exclamation and prefix', () => {
|
|
51
|
-
output.warning('Resource limit approaching');
|
|
52
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(chalk.yellow.bold('!'), chalk.yellow('warning:'), 'Resource limit approaching');
|
|
53
|
-
});
|
|
54
|
-
it('should handle additional arguments', () => {
|
|
55
|
-
const details = { cpu: '85%', memory: '92%' };
|
|
56
|
-
output.warning('High resource usage', details);
|
|
57
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(chalk.yellow.bold('!'), chalk.yellow('warning:'), 'High resource usage', details);
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
describe('statusCheck', () => {
|
|
61
|
-
it('should display found status with value and details', () => {
|
|
62
|
-
output.statusCheck('found', 'platform', 'python3', 'v3.10');
|
|
63
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(` ${chalk.green('✓')} ${chalk.green('platform')} ${chalk.bold.white('python3')}${chalk.gray(' v3.10')}`);
|
|
64
|
-
});
|
|
65
|
-
it('should display found status with value only', () => {
|
|
66
|
-
output.statusCheck('found', 'fastmcp', 'v0.1.0');
|
|
67
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(` ${chalk.green('✓')} ${chalk.green('fastmcp')} ${chalk.bold.white('v0.1.0')}`);
|
|
68
|
-
});
|
|
69
|
-
it('should display found status with label only', () => {
|
|
70
|
-
output.statusCheck('found', '3 tools');
|
|
71
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(` ${chalk.green('✓')} ${chalk.green('3 tools')}`);
|
|
72
|
-
});
|
|
73
|
-
it('should display missing status with details', () => {
|
|
74
|
-
output.statusCheck('missing', 'fastmcp', undefined, 'not in dependencies');
|
|
75
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(` ${chalk.yellow('?')} ${chalk.yellow('fastmcp')}${chalk.gray(' not in dependencies')}`);
|
|
76
|
-
});
|
|
77
|
-
it('should display warning status', () => {
|
|
78
|
-
output.statusCheck('warning', 'version', '0.0.1', 'pre-release');
|
|
79
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(` ${chalk.yellow('!')} ${chalk.yellow('version')} ${chalk.bold.white('0.0.1')}${chalk.gray(' pre-release')}`);
|
|
80
|
-
});
|
|
81
|
-
it('should display error status', () => {
|
|
82
|
-
output.statusCheck('error', 'tools', undefined, 'discovery failed');
|
|
83
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(` ${chalk.red('✗')} ${chalk.red('tools')}${chalk.gray(' discovery failed')}`);
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
|
-
describe('section', () => {
|
|
87
|
-
it('should display section header with colon', () => {
|
|
88
|
-
output.section('dev-tests');
|
|
89
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(chalk.cyan.bold('dev-tests:'));
|
|
90
|
-
});
|
|
91
|
-
it('should display section header with custom text', () => {
|
|
92
|
-
output.section('ark services');
|
|
93
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(chalk.cyan.bold('ark services:'));
|
|
94
|
-
});
|
|
95
|
-
});
|
|
96
|
-
describe('statusMessage', () => {
|
|
97
|
-
it('should output success status with title and message', () => {
|
|
98
|
-
output.statusMessage('success', 'fastmcp', 'installed (v0.1.0)');
|
|
99
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(chalk.green('✓'), chalk.green('fastmcp:'), 'installed (v0.1.0)');
|
|
100
|
-
});
|
|
101
|
-
it('should output warning status with title and message', () => {
|
|
102
|
-
output.statusMessage('warning', 'virtual environment', 'not found');
|
|
103
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(chalk.yellow.bold('!'), chalk.yellow('virtual environment:'), 'not found');
|
|
104
|
-
});
|
|
105
|
-
it('should output error status with title and message', () => {
|
|
106
|
-
output.statusMessage('error', 'fastmcp', 'not found in dependencies');
|
|
107
|
-
expect(consoleErrorSpy).toHaveBeenCalledWith(chalk.red('✗'), chalk.red('fastmcp:'), 'not found in dependencies');
|
|
108
|
-
});
|
|
109
|
-
it('should output info status with title and message', () => {
|
|
110
|
-
output.statusMessage('info', 'platform', 'python3');
|
|
111
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(chalk.blue('ℹ'), chalk.blue('platform:'), 'python3');
|
|
112
|
-
});
|
|
113
|
-
it('should handle title-only messages', () => {
|
|
114
|
-
output.statusMessage('success', 'Operation completed');
|
|
115
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(chalk.green('✓'), 'Operation completed');
|
|
116
|
-
});
|
|
117
|
-
it('should handle additional arguments', () => {
|
|
118
|
-
const extra = { version: '1.0' };
|
|
119
|
-
output.statusMessage('info', 'status', 'running', extra, 42);
|
|
120
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(chalk.blue('ℹ'), chalk.blue('status:'), 'running', extra, 42);
|
|
121
|
-
});
|
|
122
|
-
});
|
|
123
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/lib/startup.spec.js
DELETED
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, jest, beforeEach, afterEach } from '@jest/globals';
|
|
2
|
-
// Mock chalk to avoid ANSI codes in tests
|
|
3
|
-
jest.unstable_mockModule('chalk', () => ({
|
|
4
|
-
default: {
|
|
5
|
-
red: (str) => str,
|
|
6
|
-
yellow: (str) => str,
|
|
7
|
-
gray: (str) => str,
|
|
8
|
-
blue: (str) => str,
|
|
9
|
-
},
|
|
10
|
-
}));
|
|
11
|
-
// Mock commands module
|
|
12
|
-
jest.unstable_mockModule('./commands.js', () => ({
|
|
13
|
-
checkCommandExists: jest.fn(),
|
|
14
|
-
}));
|
|
15
|
-
// Mock config module
|
|
16
|
-
jest.unstable_mockModule('./config.js', () => ({
|
|
17
|
-
loadConfig: jest.fn(),
|
|
18
|
-
}));
|
|
19
|
-
// Mock execa module
|
|
20
|
-
jest.unstable_mockModule('execa', () => ({
|
|
21
|
-
execa: jest.fn(),
|
|
22
|
-
}));
|
|
23
|
-
// Dynamic imports after mocks
|
|
24
|
-
const { checkCommandExists } = await import('./commands.js');
|
|
25
|
-
const { loadConfig } = await import('./config.js');
|
|
26
|
-
const { execa } = await import('execa');
|
|
27
|
-
const { startup } = await import('./startup.js');
|
|
28
|
-
// Type the mocks
|
|
29
|
-
const mockCheckCommandExists = checkCommandExists;
|
|
30
|
-
const mockLoadConfig = loadConfig;
|
|
31
|
-
const mockExeca = execa;
|
|
32
|
-
describe('startup', () => {
|
|
33
|
-
let mockExit;
|
|
34
|
-
let mockConsoleError;
|
|
35
|
-
beforeEach(() => {
|
|
36
|
-
jest.clearAllMocks();
|
|
37
|
-
// Mock execa to reject by default (no kubectl context)
|
|
38
|
-
mockExeca.mockRejectedValue(new Error('No context'));
|
|
39
|
-
mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {
|
|
40
|
-
throw new Error('process.exit');
|
|
41
|
-
});
|
|
42
|
-
mockConsoleError = jest
|
|
43
|
-
.spyOn(console, 'error')
|
|
44
|
-
.mockImplementation(() => { });
|
|
45
|
-
});
|
|
46
|
-
afterEach(() => {
|
|
47
|
-
mockExit.mockRestore();
|
|
48
|
-
mockConsoleError.mockRestore();
|
|
49
|
-
});
|
|
50
|
-
it('returns config when all required commands are installed', async () => {
|
|
51
|
-
const expectedConfig = {
|
|
52
|
-
chat: {
|
|
53
|
-
streaming: true,
|
|
54
|
-
outputFormat: 'text',
|
|
55
|
-
},
|
|
56
|
-
};
|
|
57
|
-
// Mock all commands as available
|
|
58
|
-
mockCheckCommandExists.mockResolvedValue(true);
|
|
59
|
-
mockLoadConfig.mockReturnValue(expectedConfig);
|
|
60
|
-
const config = await startup();
|
|
61
|
-
expect(config).toEqual(expectedConfig);
|
|
62
|
-
expect(mockCheckCommandExists).toHaveBeenCalledWith('kubectl', [
|
|
63
|
-
'version',
|
|
64
|
-
'--client',
|
|
65
|
-
]);
|
|
66
|
-
expect(mockCheckCommandExists).toHaveBeenCalledWith('helm', [
|
|
67
|
-
'version',
|
|
68
|
-
'--short',
|
|
69
|
-
]);
|
|
70
|
-
expect(mockLoadConfig).toHaveBeenCalledTimes(1);
|
|
71
|
-
expect(mockExit).not.toHaveBeenCalled();
|
|
72
|
-
});
|
|
73
|
-
it('exits with error when kubectl is missing', async () => {
|
|
74
|
-
// Mock kubectl as missing, helm as available
|
|
75
|
-
mockCheckCommandExists
|
|
76
|
-
.mockResolvedValueOnce(false) // kubectl
|
|
77
|
-
.mockResolvedValueOnce(true); // helm
|
|
78
|
-
await expect(startup()).rejects.toThrow('process.exit');
|
|
79
|
-
expect(mockConsoleError).toHaveBeenCalledWith('error: kubectl is required');
|
|
80
|
-
expect(mockConsoleError).toHaveBeenCalledWith(' https://kubernetes.io/docs/tasks/tools/');
|
|
81
|
-
expect(mockExit).toHaveBeenCalledWith(1);
|
|
82
|
-
});
|
|
83
|
-
it('exits with error when helm is missing', async () => {
|
|
84
|
-
// Mock kubectl as available, helm as missing
|
|
85
|
-
mockCheckCommandExists
|
|
86
|
-
.mockResolvedValueOnce(true) // kubectl
|
|
87
|
-
.mockResolvedValueOnce(false); // helm
|
|
88
|
-
await expect(startup()).rejects.toThrow('process.exit');
|
|
89
|
-
expect(mockConsoleError).toHaveBeenCalledWith('error: helm is required');
|
|
90
|
-
expect(mockConsoleError).toHaveBeenCalledWith(' https://helm.sh/docs/intro/install/');
|
|
91
|
-
expect(mockExit).toHaveBeenCalledWith(1);
|
|
92
|
-
});
|
|
93
|
-
it('exits with error when both commands are missing', async () => {
|
|
94
|
-
// Mock both commands as missing
|
|
95
|
-
mockCheckCommandExists.mockResolvedValue(false);
|
|
96
|
-
await expect(startup()).rejects.toThrow('process.exit');
|
|
97
|
-
expect(mockConsoleError).toHaveBeenCalledWith('error: kubectl is required');
|
|
98
|
-
expect(mockConsoleError).toHaveBeenCalledWith(' https://kubernetes.io/docs/tasks/tools/');
|
|
99
|
-
expect(mockConsoleError).toHaveBeenCalledWith('error: helm is required');
|
|
100
|
-
expect(mockConsoleError).toHaveBeenCalledWith(' https://helm.sh/docs/intro/install/');
|
|
101
|
-
expect(mockExit).toHaveBeenCalledWith(1);
|
|
102
|
-
});
|
|
103
|
-
it('checks commands with correct arguments', async () => {
|
|
104
|
-
mockCheckCommandExists.mockResolvedValue(true);
|
|
105
|
-
mockLoadConfig.mockReturnValue({ chat: {} });
|
|
106
|
-
await startup();
|
|
107
|
-
expect(mockCheckCommandExists).toHaveBeenCalledTimes(2);
|
|
108
|
-
expect(mockCheckCommandExists).toHaveBeenNthCalledWith(1, 'kubectl', [
|
|
109
|
-
'version',
|
|
110
|
-
'--client',
|
|
111
|
-
]);
|
|
112
|
-
expect(mockCheckCommandExists).toHaveBeenNthCalledWith(2, 'helm', [
|
|
113
|
-
'version',
|
|
114
|
-
'--short',
|
|
115
|
-
]);
|
|
116
|
-
});
|
|
117
|
-
it('loads config after checking requirements', async () => {
|
|
118
|
-
mockCheckCommandExists.mockResolvedValue(true);
|
|
119
|
-
const expectedConfig = { chat: { streaming: false } };
|
|
120
|
-
mockLoadConfig.mockReturnValue(expectedConfig);
|
|
121
|
-
const config = await startup();
|
|
122
|
-
// Verify order - checkCommandExists should be called before loadConfig
|
|
123
|
-
const checkCallOrder = mockCheckCommandExists.mock.invocationCallOrder[0];
|
|
124
|
-
const loadCallOrder = mockLoadConfig.mock.invocationCallOrder[0];
|
|
125
|
-
expect(checkCallOrder).toBeLessThan(loadCallOrder);
|
|
126
|
-
expect(config).toEqual(expectedConfig);
|
|
127
|
-
});
|
|
128
|
-
it('includes cluster context when available', async () => {
|
|
129
|
-
mockCheckCommandExists.mockResolvedValue(true);
|
|
130
|
-
mockLoadConfig.mockReturnValue({ chat: { streaming: true } });
|
|
131
|
-
// Mock successful kubectl context check
|
|
132
|
-
mockExeca.mockResolvedValue({
|
|
133
|
-
stdout: 'minikube',
|
|
134
|
-
stderr: '',
|
|
135
|
-
});
|
|
136
|
-
const config = await startup();
|
|
137
|
-
expect(config.clusterInfo).toEqual({
|
|
138
|
-
type: 'unknown',
|
|
139
|
-
context: 'minikube',
|
|
140
|
-
});
|
|
141
|
-
expect(mockExeca).toHaveBeenCalledWith('kubectl', ['config', 'current-context'], { timeout: 5000 });
|
|
142
|
-
});
|
|
143
|
-
it('handles missing kubectl context gracefully', async () => {
|
|
144
|
-
mockCheckCommandExists.mockResolvedValue(true);
|
|
145
|
-
const expectedConfig = { chat: { streaming: false } };
|
|
146
|
-
mockLoadConfig.mockReturnValue(expectedConfig);
|
|
147
|
-
// mockExeca already mocked to reject in beforeEach
|
|
148
|
-
const config = await startup();
|
|
149
|
-
expect(config).toEqual(expectedConfig);
|
|
150
|
-
expect(config.clusterInfo).toBeUndefined();
|
|
151
|
-
});
|
|
152
|
-
});
|
package/dist/lib/stdin.spec.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/lib/stdin.spec.js
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach, jest } from '@jest/globals';
|
|
2
|
-
import { readStdin } from './stdin.js';
|
|
3
|
-
import { Readable } from 'stream';
|
|
4
|
-
describe('readStdin', () => {
|
|
5
|
-
let originalStdin;
|
|
6
|
-
let mockStdin;
|
|
7
|
-
beforeEach(() => {
|
|
8
|
-
originalStdin = process.stdin;
|
|
9
|
-
mockStdin = new Readable({
|
|
10
|
-
read() { },
|
|
11
|
-
});
|
|
12
|
-
Object.defineProperty(process, 'stdin', {
|
|
13
|
-
value: mockStdin,
|
|
14
|
-
writable: true,
|
|
15
|
-
configurable: true,
|
|
16
|
-
});
|
|
17
|
-
});
|
|
18
|
-
afterEach(() => {
|
|
19
|
-
Object.defineProperty(process, 'stdin', {
|
|
20
|
-
value: originalStdin,
|
|
21
|
-
writable: true,
|
|
22
|
-
configurable: true,
|
|
23
|
-
});
|
|
24
|
-
jest.clearAllMocks();
|
|
25
|
-
});
|
|
26
|
-
it('should return empty string when stdin is TTY', async () => {
|
|
27
|
-
mockStdin.isTTY = true;
|
|
28
|
-
const result = await readStdin();
|
|
29
|
-
expect(result).toBe('');
|
|
30
|
-
});
|
|
31
|
-
it('should read single chunk from stdin', async () => {
|
|
32
|
-
mockStdin.isTTY = false;
|
|
33
|
-
const promise = readStdin();
|
|
34
|
-
mockStdin.push('test-query');
|
|
35
|
-
mockStdin.push(null);
|
|
36
|
-
const result = await promise;
|
|
37
|
-
expect(result).toBe('test-query');
|
|
38
|
-
});
|
|
39
|
-
it('should read multiple chunks from stdin', async () => {
|
|
40
|
-
mockStdin.isTTY = false;
|
|
41
|
-
const promise = readStdin();
|
|
42
|
-
mockStdin.push('test-');
|
|
43
|
-
mockStdin.push('query-');
|
|
44
|
-
mockStdin.push('name');
|
|
45
|
-
mockStdin.push(null);
|
|
46
|
-
const result = await promise;
|
|
47
|
-
expect(result).toBe('test-query-name');
|
|
48
|
-
});
|
|
49
|
-
it('should trim whitespace from stdin input', async () => {
|
|
50
|
-
mockStdin.isTTY = false;
|
|
51
|
-
const promise = readStdin();
|
|
52
|
-
mockStdin.push(' test-query \n');
|
|
53
|
-
mockStdin.push(null);
|
|
54
|
-
const result = await promise;
|
|
55
|
-
expect(result).toBe('test-query');
|
|
56
|
-
});
|
|
57
|
-
it('should handle empty stdin input', async () => {
|
|
58
|
-
mockStdin.isTTY = false;
|
|
59
|
-
const promise = readStdin();
|
|
60
|
-
mockStdin.push(null);
|
|
61
|
-
const result = await promise;
|
|
62
|
-
expect(result).toBe('');
|
|
63
|
-
});
|
|
64
|
-
it('should handle stdin with only whitespace', async () => {
|
|
65
|
-
mockStdin.isTTY = false;
|
|
66
|
-
const promise = readStdin();
|
|
67
|
-
mockStdin.push(' \n\n ');
|
|
68
|
-
mockStdin.push(null);
|
|
69
|
-
const result = await promise;
|
|
70
|
-
expect(result).toBe('');
|
|
71
|
-
});
|
|
72
|
-
it('should handle multiline input', async () => {
|
|
73
|
-
mockStdin.isTTY = false;
|
|
74
|
-
const promise = readStdin();
|
|
75
|
-
mockStdin.push('line1\n');
|
|
76
|
-
mockStdin.push('line2\n');
|
|
77
|
-
mockStdin.push('line3');
|
|
78
|
-
mockStdin.push(null);
|
|
79
|
-
const result = await promise;
|
|
80
|
-
expect(result).toBe('line1\nline2\nline3');
|
|
81
|
-
});
|
|
82
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/lib/timeout.spec.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from '@jest/globals';
|
|
2
|
-
import { parseTimeoutToSeconds } from './timeout.js';
|
|
3
|
-
describe('parseTimeoutToSeconds', () => {
|
|
4
|
-
it('should parse time units correctly', () => {
|
|
5
|
-
expect(parseTimeoutToSeconds('30s')).toBe(30);
|
|
6
|
-
expect(parseTimeoutToSeconds('2m')).toBe(120);
|
|
7
|
-
expect(parseTimeoutToSeconds('1h')).toBe(3600);
|
|
8
|
-
expect(parseTimeoutToSeconds('60')).toBe(60);
|
|
9
|
-
});
|
|
10
|
-
it('should throw error for invalid formats', () => {
|
|
11
|
-
expect(() => parseTimeoutToSeconds('abc')).toThrow('Invalid timeout format');
|
|
12
|
-
expect(() => parseTimeoutToSeconds('-5s')).toThrow('Invalid timeout format');
|
|
13
|
-
});
|
|
14
|
-
});
|