@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,88 +0,0 @@
|
|
|
1
|
-
import { jest } from '@jest/globals';
|
|
2
|
-
import { Command } from 'commander';
|
|
3
|
-
const mockGetAllMarketplaceServices = jest.fn();
|
|
4
|
-
const mockGetAllMarketplaceAgents = jest.fn();
|
|
5
|
-
const mockFetchMarketplaceManifest = jest.fn();
|
|
6
|
-
const mockConsoleLog = jest.spyOn(console, 'log').mockImplementation(() => { });
|
|
7
|
-
jest.unstable_mockModule('../../marketplaceServices.js', () => ({
|
|
8
|
-
getAllMarketplaceServices: mockGetAllMarketplaceServices,
|
|
9
|
-
getAllMarketplaceAgents: mockGetAllMarketplaceAgents,
|
|
10
|
-
}));
|
|
11
|
-
jest.unstable_mockModule('../../lib/marketplaceFetcher.js', () => ({
|
|
12
|
-
fetchMarketplaceManifest: mockFetchMarketplaceManifest,
|
|
13
|
-
}));
|
|
14
|
-
const { createMarketplaceCommand } = await import('./index.js');
|
|
15
|
-
describe('marketplace command', () => {
|
|
16
|
-
beforeEach(() => {
|
|
17
|
-
jest.clearAllMocks();
|
|
18
|
-
});
|
|
19
|
-
it('creates marketplace command with correct structure', () => {
|
|
20
|
-
const command = createMarketplaceCommand({});
|
|
21
|
-
expect(command).toBeInstanceOf(Command);
|
|
22
|
-
expect(command.name()).toBe('marketplace');
|
|
23
|
-
});
|
|
24
|
-
it('lists services and agents from manifest', async () => {
|
|
25
|
-
const mockServices = {
|
|
26
|
-
'test-service': {
|
|
27
|
-
name: 'test-service',
|
|
28
|
-
helmReleaseName: 'test-service',
|
|
29
|
-
description: 'Test service description',
|
|
30
|
-
enabled: true,
|
|
31
|
-
category: 'marketplace',
|
|
32
|
-
namespace: 'test-ns',
|
|
33
|
-
},
|
|
34
|
-
};
|
|
35
|
-
const mockAgents = {
|
|
36
|
-
'test-agent': {
|
|
37
|
-
name: 'test-agent',
|
|
38
|
-
helmReleaseName: 'test-agent',
|
|
39
|
-
description: 'Test agent description',
|
|
40
|
-
enabled: true,
|
|
41
|
-
category: 'marketplace',
|
|
42
|
-
namespace: 'test-ns',
|
|
43
|
-
},
|
|
44
|
-
};
|
|
45
|
-
const mockManifest = {
|
|
46
|
-
version: '1.0.0',
|
|
47
|
-
marketplace: 'ARK Marketplace',
|
|
48
|
-
items: [
|
|
49
|
-
{
|
|
50
|
-
name: 'test-service',
|
|
51
|
-
description: 'Test service',
|
|
52
|
-
type: 'service',
|
|
53
|
-
ark: {
|
|
54
|
-
chartPath: 'oci://registry/test-service',
|
|
55
|
-
namespace: 'test',
|
|
56
|
-
},
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
name: 'test-agent',
|
|
60
|
-
description: 'Test agent',
|
|
61
|
-
type: 'agent',
|
|
62
|
-
ark: {
|
|
63
|
-
chartPath: 'oci://registry/test-agent',
|
|
64
|
-
namespace: 'test',
|
|
65
|
-
},
|
|
66
|
-
},
|
|
67
|
-
],
|
|
68
|
-
};
|
|
69
|
-
mockGetAllMarketplaceServices.mockResolvedValue(mockServices);
|
|
70
|
-
mockGetAllMarketplaceAgents.mockResolvedValue(mockAgents);
|
|
71
|
-
mockFetchMarketplaceManifest.mockResolvedValue(mockManifest);
|
|
72
|
-
const command = createMarketplaceCommand({});
|
|
73
|
-
await command.parseAsync(['node', 'test', 'list']);
|
|
74
|
-
expect(mockGetAllMarketplaceServices).toHaveBeenCalled();
|
|
75
|
-
expect(mockGetAllMarketplaceAgents).toHaveBeenCalled();
|
|
76
|
-
expect(mockConsoleLog).toHaveBeenCalled();
|
|
77
|
-
});
|
|
78
|
-
it('shows unavailable message when marketplace unavailable', async () => {
|
|
79
|
-
mockGetAllMarketplaceServices.mockResolvedValue(null);
|
|
80
|
-
mockGetAllMarketplaceAgents.mockResolvedValue(null);
|
|
81
|
-
mockFetchMarketplaceManifest.mockResolvedValue(null);
|
|
82
|
-
const command = createMarketplaceCommand({});
|
|
83
|
-
await command.parseAsync(['node', 'test', 'list']);
|
|
84
|
-
expect(mockConsoleLog).toHaveBeenCalled();
|
|
85
|
-
const logCalls = mockConsoleLog.mock.calls.map((c) => c[0]).join(' ');
|
|
86
|
-
expect(logCalls).toContain('unavailable');
|
|
87
|
-
});
|
|
88
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, jest, beforeEach, afterEach, beforeAll, } from '@jest/globals';
|
|
2
|
-
// ESM-safe mocking: declare variables to hold dynamically imported modules
|
|
3
|
-
let createMemoryCommand;
|
|
4
|
-
let deleteSession;
|
|
5
|
-
let deleteQuery;
|
|
6
|
-
let deleteAll;
|
|
7
|
-
let ArkApiProxy;
|
|
8
|
-
let output;
|
|
9
|
-
// Mock dependencies
|
|
10
|
-
jest.unstable_mockModule('../../lib/output.js', () => ({
|
|
11
|
-
default: {
|
|
12
|
-
info: jest.fn(),
|
|
13
|
-
success: jest.fn(),
|
|
14
|
-
error: jest.fn(),
|
|
15
|
-
},
|
|
16
|
-
}));
|
|
17
|
-
// Mock ArkApiProxy with a simpler approach
|
|
18
|
-
jest.unstable_mockModule('../../lib/arkApiProxy.js', () => ({
|
|
19
|
-
__esModule: true,
|
|
20
|
-
ArkApiProxy: jest.fn().mockImplementation(() => ({
|
|
21
|
-
start: jest.fn(),
|
|
22
|
-
stop: jest.fn(),
|
|
23
|
-
})),
|
|
24
|
-
}));
|
|
25
|
-
beforeAll(async () => {
|
|
26
|
-
// After mocks are registered, dynamically import modules
|
|
27
|
-
({ ArkApiProxy } = await import('../../lib/arkApiProxy.js'));
|
|
28
|
-
({ default: output } = await import('../../lib/output.js'));
|
|
29
|
-
({ createMemoryCommand, deleteSession, deleteQuery, deleteAll } = await import('./index.js'));
|
|
30
|
-
});
|
|
31
|
-
describe('Memory Command', () => {
|
|
32
|
-
let mockConfig;
|
|
33
|
-
beforeEach(() => {
|
|
34
|
-
jest.clearAllMocks();
|
|
35
|
-
mockConfig = {};
|
|
36
|
-
});
|
|
37
|
-
afterEach(() => {
|
|
38
|
-
jest.restoreAllMocks();
|
|
39
|
-
});
|
|
40
|
-
describe('Command Structure', () => {
|
|
41
|
-
it('should create memory command with correct structure', () => {
|
|
42
|
-
const command = createMemoryCommand(mockConfig);
|
|
43
|
-
expect(command.name()).toBe('memory');
|
|
44
|
-
expect(command.alias()).toBe('mem');
|
|
45
|
-
expect(command.description()).toBe('Manage memory sessions and queries');
|
|
46
|
-
});
|
|
47
|
-
it('should have list subcommand', () => {
|
|
48
|
-
const command = createMemoryCommand(mockConfig);
|
|
49
|
-
const subcommands = command.commands.map((cmd) => cmd.name());
|
|
50
|
-
expect(subcommands).toContain('list');
|
|
51
|
-
});
|
|
52
|
-
it('should have delete subcommand with nested commands and flags', () => {
|
|
53
|
-
const command = createMemoryCommand(mockConfig);
|
|
54
|
-
const deleteCommand = command.commands.find((cmd) => cmd.name() === 'delete');
|
|
55
|
-
expect(deleteCommand).toBeDefined();
|
|
56
|
-
expect(deleteCommand?.description()).toBe('Delete memory data');
|
|
57
|
-
const deleteSubcommands = deleteCommand?.commands.map((cmd) => cmd.name()) || [];
|
|
58
|
-
expect(deleteSubcommands).toContain('session');
|
|
59
|
-
expect(deleteSubcommands).toContain('query');
|
|
60
|
-
// --all flag is supported on the delete root instead of an 'all' subcommand
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
|
-
describe('Command Creation', () => {
|
|
64
|
-
it('should create command without errors', () => {
|
|
65
|
-
expect(() => createMemoryCommand(mockConfig)).not.toThrow();
|
|
66
|
-
});
|
|
67
|
-
it('should return a command object', () => {
|
|
68
|
-
const command = createMemoryCommand(mockConfig);
|
|
69
|
-
expect(command).toBeDefined();
|
|
70
|
-
expect(typeof command.name).toBe('function');
|
|
71
|
-
expect(typeof command.description).toBe('function');
|
|
72
|
-
});
|
|
73
|
-
});
|
|
74
|
-
describe('Error Scenarios', () => {
|
|
75
|
-
let exitSpy;
|
|
76
|
-
beforeEach(async () => {
|
|
77
|
-
exitSpy = jest
|
|
78
|
-
.spyOn(process, 'exit')
|
|
79
|
-
.mockImplementation(((..._args) => undefined));
|
|
80
|
-
});
|
|
81
|
-
afterEach(() => {
|
|
82
|
-
exitSpy.mockRestore();
|
|
83
|
-
});
|
|
84
|
-
it('deleteSession handles 500 error', async () => {
|
|
85
|
-
const err = new Error('Internal Server Error');
|
|
86
|
-
const fakeClient = {
|
|
87
|
-
deleteSession: jest.fn().mockRejectedValue(err),
|
|
88
|
-
};
|
|
89
|
-
ArkApiProxy.mockImplementation(() => ({
|
|
90
|
-
start: jest.fn().mockResolvedValue(fakeClient),
|
|
91
|
-
stop: jest.fn(),
|
|
92
|
-
}));
|
|
93
|
-
await deleteSession('sess-1', { output: 'text' }).catch(() => { });
|
|
94
|
-
expect(output.error).toHaveBeenCalled();
|
|
95
|
-
expect(process.exit).toHaveBeenCalledWith(1);
|
|
96
|
-
});
|
|
97
|
-
it('deleteQuery handles network timeout', async () => {
|
|
98
|
-
const err = new Error('Network timeout');
|
|
99
|
-
const fakeClient = {
|
|
100
|
-
deleteQueryMessages: jest.fn().mockRejectedValue(err),
|
|
101
|
-
};
|
|
102
|
-
ArkApiProxy.mockImplementation(() => ({
|
|
103
|
-
start: jest.fn().mockResolvedValue(fakeClient),
|
|
104
|
-
stop: jest.fn(),
|
|
105
|
-
}));
|
|
106
|
-
await deleteQuery('sess-2', 'query-9', { output: 'text' }).catch(() => { });
|
|
107
|
-
expect(output.error).toHaveBeenCalled();
|
|
108
|
-
expect(process.exit).toHaveBeenCalledWith(1);
|
|
109
|
-
});
|
|
110
|
-
it('deleteAll handles no memory services reachable', async () => {
|
|
111
|
-
const err = new Error('No memory services reachable');
|
|
112
|
-
const fakeClient = {
|
|
113
|
-
deleteAllSessions: jest.fn().mockRejectedValue(err),
|
|
114
|
-
};
|
|
115
|
-
ArkApiProxy.mockImplementation(() => ({
|
|
116
|
-
start: jest.fn().mockResolvedValue(fakeClient),
|
|
117
|
-
stop: jest.fn(),
|
|
118
|
-
}));
|
|
119
|
-
await deleteAll({ output: 'text' }).catch(() => { });
|
|
120
|
-
expect(output.error).toHaveBeenCalled();
|
|
121
|
-
expect(process.exit).toHaveBeenCalledWith(1);
|
|
122
|
-
});
|
|
123
|
-
});
|
|
124
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
import { jest } from '@jest/globals';
|
|
2
|
-
const mockExeca = jest.fn();
|
|
3
|
-
jest.unstable_mockModule('execa', () => ({
|
|
4
|
-
execa: mockExeca,
|
|
5
|
-
}));
|
|
6
|
-
const mockInquirer = {
|
|
7
|
-
prompt: jest.fn(),
|
|
8
|
-
};
|
|
9
|
-
jest.unstable_mockModule('inquirer', () => ({
|
|
10
|
-
default: mockInquirer,
|
|
11
|
-
}));
|
|
12
|
-
const mockOutput = {
|
|
13
|
-
info: jest.fn(),
|
|
14
|
-
warning: jest.fn(),
|
|
15
|
-
error: jest.fn(),
|
|
16
|
-
success: jest.fn(),
|
|
17
|
-
};
|
|
18
|
-
jest.unstable_mockModule('../../lib/output.js', () => ({
|
|
19
|
-
default: mockOutput,
|
|
20
|
-
}));
|
|
21
|
-
jest.spyOn(console, 'log').mockImplementation(() => { });
|
|
22
|
-
jest.spyOn(console, 'error').mockImplementation(() => { });
|
|
23
|
-
const { createModel } = await import('./create.js');
|
|
24
|
-
describe('createModel', () => {
|
|
25
|
-
beforeEach(() => {
|
|
26
|
-
jest.clearAllMocks();
|
|
27
|
-
});
|
|
28
|
-
it('creates new model for type aws bedrock', async () => {
|
|
29
|
-
mockExeca.mockRejectedValueOnce(new Error('not found')); // model doesn't exist
|
|
30
|
-
mockInquirer.prompt
|
|
31
|
-
.mockResolvedValueOnce({ modelType: 'bedrock' }) // user selects from list
|
|
32
|
-
.mockResolvedValueOnce({ model: 'anthropic.claude-3-sonnet-20240229-v1:0' })
|
|
33
|
-
.mockResolvedValueOnce({ region: 'us-east-1' })
|
|
34
|
-
.mockResolvedValueOnce({ accessKeyId: 'AKIAIOSFODNN7EXAMPLE' })
|
|
35
|
-
.mockResolvedValueOnce({
|
|
36
|
-
secretAccessKey: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
|
|
37
|
-
})
|
|
38
|
-
.mockResolvedValueOnce({ sessionToken: 'optional-session-token' })
|
|
39
|
-
.mockResolvedValueOnce({
|
|
40
|
-
modelArn: 'arn:aws:bedrock:us-east-1:123456789012:model/anthropic.claude-3-sonnet-20240229-v1:0',
|
|
41
|
-
});
|
|
42
|
-
mockExeca.mockResolvedValue({}); // kubectl ops succeed
|
|
43
|
-
await createModel('test-model');
|
|
44
|
-
// Verify that model type prompt was called
|
|
45
|
-
expect(mockInquirer.prompt).toHaveBeenCalledWith([
|
|
46
|
-
expect.objectContaining({
|
|
47
|
-
type: 'list',
|
|
48
|
-
name: 'modelType',
|
|
49
|
-
message: 'select model provider:',
|
|
50
|
-
choices: expect.arrayContaining([
|
|
51
|
-
{ name: 'Azure OpenAI', value: 'azure' },
|
|
52
|
-
{ name: 'OpenAI', value: 'openai' },
|
|
53
|
-
{ name: 'AWS Bedrock', value: 'bedrock' },
|
|
54
|
-
]),
|
|
55
|
-
}),
|
|
56
|
-
]);
|
|
57
|
-
// Verify Bedrock-specific prompts were called
|
|
58
|
-
expect(mockInquirer.prompt).toHaveBeenCalledWith([
|
|
59
|
-
expect.objectContaining({
|
|
60
|
-
name: 'region',
|
|
61
|
-
message: 'AWS region:',
|
|
62
|
-
}),
|
|
63
|
-
]);
|
|
64
|
-
expect(mockInquirer.prompt).toHaveBeenCalledWith([
|
|
65
|
-
expect.objectContaining({
|
|
66
|
-
name: 'accessKeyId',
|
|
67
|
-
message: 'AWS access key ID:',
|
|
68
|
-
}),
|
|
69
|
-
]);
|
|
70
|
-
expect(mockInquirer.prompt).toHaveBeenCalledWith([
|
|
71
|
-
expect.objectContaining({
|
|
72
|
-
name: 'secretAccessKey',
|
|
73
|
-
message: 'AWS secret access key:',
|
|
74
|
-
type: 'password',
|
|
75
|
-
}),
|
|
76
|
-
]);
|
|
77
|
-
expect(mockOutput.success).toHaveBeenCalledWith('model test-model created');
|
|
78
|
-
});
|
|
79
|
-
it('creates new model with provided name', async () => {
|
|
80
|
-
// Model doesn't exist
|
|
81
|
-
mockExeca.mockRejectedValueOnce(new Error('not found'));
|
|
82
|
-
// Prompts for model details
|
|
83
|
-
mockInquirer.prompt
|
|
84
|
-
.mockResolvedValueOnce({ modelType: 'openai' })
|
|
85
|
-
.mockResolvedValueOnce({ model: 'gpt-4' })
|
|
86
|
-
.mockResolvedValueOnce({ baseUrl: 'https://api.openai.com/' })
|
|
87
|
-
.mockResolvedValueOnce({ apiKey: 'secret-key' });
|
|
88
|
-
// Secret operations succeed
|
|
89
|
-
mockExeca.mockResolvedValueOnce({}); // create secret
|
|
90
|
-
mockExeca.mockResolvedValueOnce({}); // apply model
|
|
91
|
-
const result = await createModel('test-model');
|
|
92
|
-
expect(result).toBe(true);
|
|
93
|
-
expect(mockExeca).toHaveBeenCalledWith('kubectl', ['get', 'model', 'test-model'], { stdio: 'pipe' });
|
|
94
|
-
expect(mockOutput.success).toHaveBeenCalledWith('model test-model created');
|
|
95
|
-
});
|
|
96
|
-
it('prompts for name when not provided', async () => {
|
|
97
|
-
mockInquirer.prompt
|
|
98
|
-
.mockResolvedValueOnce({ modelName: 'prompted-model' })
|
|
99
|
-
.mockResolvedValueOnce({ modelType: 'azure' })
|
|
100
|
-
.mockResolvedValueOnce({ model: 'gpt-4' })
|
|
101
|
-
.mockResolvedValueOnce({ baseUrl: 'https://azure.com' })
|
|
102
|
-
.mockResolvedValueOnce({ apiVersion: '2024-12-01' })
|
|
103
|
-
.mockResolvedValueOnce({ apiKey: 'secret' });
|
|
104
|
-
mockExeca.mockRejectedValueOnce(new Error('not found')); // model doesn't exist
|
|
105
|
-
mockExeca.mockResolvedValue({}); // all kubectl ops succeed
|
|
106
|
-
const result = await createModel();
|
|
107
|
-
expect(result).toBe(true);
|
|
108
|
-
expect(mockInquirer.prompt).toHaveBeenCalledWith([
|
|
109
|
-
expect.objectContaining({
|
|
110
|
-
name: 'modelName',
|
|
111
|
-
message: 'model name:',
|
|
112
|
-
}),
|
|
113
|
-
]);
|
|
114
|
-
});
|
|
115
|
-
it('handles overwrite confirmation when model exists', async () => {
|
|
116
|
-
// Model exists
|
|
117
|
-
mockExeca.mockResolvedValueOnce({});
|
|
118
|
-
mockInquirer.prompt
|
|
119
|
-
.mockResolvedValueOnce({ overwrite: true })
|
|
120
|
-
.mockResolvedValueOnce({ modelType: 'openai' })
|
|
121
|
-
.mockResolvedValueOnce({ model: 'gpt-4' })
|
|
122
|
-
.mockResolvedValueOnce({ baseUrl: 'https://api.openai.com' })
|
|
123
|
-
.mockResolvedValueOnce({ apiKey: 'secret' });
|
|
124
|
-
mockExeca.mockResolvedValue({}); // remaining kubectl ops
|
|
125
|
-
const result = await createModel('existing-model');
|
|
126
|
-
expect(result).toBe(true);
|
|
127
|
-
expect(mockOutput.warning).toHaveBeenCalledWith('model existing-model already exists');
|
|
128
|
-
});
|
|
129
|
-
it('cancels when user declines overwrite', async () => {
|
|
130
|
-
mockExeca.mockResolvedValueOnce({}); // model exists
|
|
131
|
-
mockInquirer.prompt.mockResolvedValueOnce({ overwrite: false });
|
|
132
|
-
const result = await createModel('existing-model');
|
|
133
|
-
expect(result).toBe(false);
|
|
134
|
-
expect(mockOutput.info).toHaveBeenCalledWith('model creation cancelled');
|
|
135
|
-
});
|
|
136
|
-
it('handles secret creation failure', async () => {
|
|
137
|
-
mockExeca
|
|
138
|
-
.mockRejectedValueOnce(new Error('not found')); // model doesn't exist
|
|
139
|
-
mockInquirer.prompt
|
|
140
|
-
.mockResolvedValueOnce({ modelType: 'openai' })
|
|
141
|
-
.mockResolvedValueOnce({ model: 'gpt-4' })
|
|
142
|
-
.mockResolvedValueOnce({ baseUrl: 'https://api.openai.com' })
|
|
143
|
-
.mockResolvedValueOnce({ apiKey: 'secret' });
|
|
144
|
-
mockExeca
|
|
145
|
-
.mockRejectedValueOnce(new Error('not found')); // secret doesn't exist check
|
|
146
|
-
mockExeca.mockRejectedValueOnce(new Error('secret creation failed')); // create secret fails
|
|
147
|
-
const result = await createModel('test-model');
|
|
148
|
-
expect(result).toBe(false);
|
|
149
|
-
expect(mockOutput.error).toHaveBeenCalledWith('failed to create secret');
|
|
150
|
-
});
|
|
151
|
-
it('updates existing secret when secret already exists', async () => {
|
|
152
|
-
mockExeca.mockRejectedValueOnce(new Error('not found')); // model doesn't exist
|
|
153
|
-
mockInquirer.prompt
|
|
154
|
-
.mockResolvedValueOnce({ modelType: 'openai' })
|
|
155
|
-
.mockResolvedValueOnce({ model: 'gpt-4' })
|
|
156
|
-
.mockResolvedValueOnce({ baseUrl: 'https://api.openai.com' })
|
|
157
|
-
.mockResolvedValueOnce({ apiKey: 'new-secret-key' });
|
|
158
|
-
mockExeca.mockResolvedValueOnce({}); // secret exists check
|
|
159
|
-
mockExeca.mockResolvedValueOnce({ stdout: 'secret yaml' }); // dry-run output
|
|
160
|
-
mockExeca.mockResolvedValueOnce({}); // kubectl apply
|
|
161
|
-
mockExeca.mockResolvedValueOnce({}); // apply model
|
|
162
|
-
const result = await createModel('test-model');
|
|
163
|
-
expect(result).toBe(true);
|
|
164
|
-
expect(mockOutput.success).toHaveBeenCalledWith('updated secret test-model-model-secret');
|
|
165
|
-
expect(mockOutput.success).toHaveBeenCalledWith('model test-model created');
|
|
166
|
-
});
|
|
167
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import { jest } from '@jest/globals';
|
|
2
|
-
import { Command } from 'commander';
|
|
3
|
-
const mockExeca = jest.fn();
|
|
4
|
-
jest.unstable_mockModule('execa', () => ({
|
|
5
|
-
execa: mockExeca,
|
|
6
|
-
}));
|
|
7
|
-
const mockOutput = {
|
|
8
|
-
info: jest.fn(),
|
|
9
|
-
error: jest.fn(),
|
|
10
|
-
};
|
|
11
|
-
jest.unstable_mockModule('../../lib/output.js', () => ({
|
|
12
|
-
default: mockOutput,
|
|
13
|
-
}));
|
|
14
|
-
const mockCreateModel = jest.fn();
|
|
15
|
-
jest.unstable_mockModule('./create.js', () => ({
|
|
16
|
-
createModel: mockCreateModel,
|
|
17
|
-
}));
|
|
18
|
-
const mockExecuteQuery = jest.fn();
|
|
19
|
-
jest.unstable_mockModule('../../lib/executeQuery.js', () => ({
|
|
20
|
-
executeQuery: mockExecuteQuery,
|
|
21
|
-
parseTarget: jest.fn(),
|
|
22
|
-
}));
|
|
23
|
-
const mockExit = jest.spyOn(process, 'exit').mockImplementation((() => {
|
|
24
|
-
throw new Error('process.exit called');
|
|
25
|
-
}));
|
|
26
|
-
const mockConsoleLog = jest.spyOn(console, 'log').mockImplementation(() => { });
|
|
27
|
-
const { createModelsCommand } = await import('./index.js');
|
|
28
|
-
describe('models command', () => {
|
|
29
|
-
beforeEach(() => {
|
|
30
|
-
jest.clearAllMocks();
|
|
31
|
-
});
|
|
32
|
-
it('creates command with correct structure', () => {
|
|
33
|
-
const command = createModelsCommand({});
|
|
34
|
-
expect(command).toBeInstanceOf(Command);
|
|
35
|
-
expect(command.name()).toBe('models');
|
|
36
|
-
});
|
|
37
|
-
it('lists models in text format', async () => {
|
|
38
|
-
const mockModels = {
|
|
39
|
-
items: [{ metadata: { name: 'gpt-4' } }, { metadata: { name: 'claude-3' } }],
|
|
40
|
-
};
|
|
41
|
-
mockExeca.mockResolvedValue({ stdout: JSON.stringify(mockModels) });
|
|
42
|
-
const command = createModelsCommand({});
|
|
43
|
-
await command.parseAsync(['node', 'test']);
|
|
44
|
-
expect(mockExeca).toHaveBeenCalledWith('kubectl', ['get', 'models', '-o', 'json'], { stdio: 'pipe' });
|
|
45
|
-
expect(mockConsoleLog).toHaveBeenCalledWith('gpt-4');
|
|
46
|
-
expect(mockConsoleLog).toHaveBeenCalledWith('claude-3');
|
|
47
|
-
});
|
|
48
|
-
it('lists models in json format', async () => {
|
|
49
|
-
const mockModels = {
|
|
50
|
-
items: [{ metadata: { name: 'gpt-4' } }],
|
|
51
|
-
};
|
|
52
|
-
mockExeca.mockResolvedValue({ stdout: JSON.stringify(mockModels) });
|
|
53
|
-
const command = createModelsCommand({});
|
|
54
|
-
await command.parseAsync(['node', 'test', '-o', 'json']);
|
|
55
|
-
expect(mockConsoleLog).toHaveBeenCalledWith(JSON.stringify(mockModels.items, null, 2));
|
|
56
|
-
});
|
|
57
|
-
it('shows info when no models', async () => {
|
|
58
|
-
mockExeca.mockResolvedValue({ stdout: JSON.stringify({ items: [] }) });
|
|
59
|
-
const command = createModelsCommand({});
|
|
60
|
-
await command.parseAsync(['node', 'test']);
|
|
61
|
-
expect(mockOutput.info).toHaveBeenCalledWith('No models found');
|
|
62
|
-
});
|
|
63
|
-
it('handles errors', async () => {
|
|
64
|
-
mockExeca.mockRejectedValue(new Error('kubectl failed'));
|
|
65
|
-
const command = createModelsCommand({});
|
|
66
|
-
await expect(command.parseAsync(['node', 'test'])).rejects.toThrow('process.exit called');
|
|
67
|
-
expect(mockOutput.error).toHaveBeenCalledWith('fetching models:', 'kubectl failed');
|
|
68
|
-
expect(mockExit).toHaveBeenCalledWith(1);
|
|
69
|
-
});
|
|
70
|
-
it('list subcommand works', async () => {
|
|
71
|
-
mockExeca.mockResolvedValue({ stdout: JSON.stringify({ items: [] }) });
|
|
72
|
-
const command = createModelsCommand({});
|
|
73
|
-
await command.parseAsync(['node', 'test', 'list']);
|
|
74
|
-
expect(mockExeca).toHaveBeenCalled();
|
|
75
|
-
});
|
|
76
|
-
it('create subcommand works', async () => {
|
|
77
|
-
const command = createModelsCommand({});
|
|
78
|
-
await command.parseAsync(['node', 'test', 'create', 'my-model']);
|
|
79
|
-
expect(mockCreateModel).toHaveBeenCalledWith('my-model', expect.objectContaining({}));
|
|
80
|
-
});
|
|
81
|
-
it('query subcommand works', async () => {
|
|
82
|
-
const command = createModelsCommand({});
|
|
83
|
-
await command.parseAsync([
|
|
84
|
-
'node',
|
|
85
|
-
'test',
|
|
86
|
-
'query',
|
|
87
|
-
'default',
|
|
88
|
-
'Hello world',
|
|
89
|
-
]);
|
|
90
|
-
expect(mockExecuteQuery).toHaveBeenCalledWith({
|
|
91
|
-
targetType: 'model',
|
|
92
|
-
targetName: 'default',
|
|
93
|
-
message: 'Hello world',
|
|
94
|
-
});
|
|
95
|
-
});
|
|
96
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|