@agents-at-scale/ark 0.1.35 → 0.1.36-rc1
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.d.ts +42 -0
- package/dist/arkServices.js +138 -0
- package/dist/arkServices.spec.d.ts +1 -0
- package/dist/arkServices.spec.js +24 -0
- package/dist/charts/charts.d.ts +5 -0
- package/dist/charts/charts.js +6 -0
- package/dist/charts/dependencies.d.ts +6 -0
- package/dist/charts/dependencies.js +50 -0
- package/dist/charts/types.d.ts +40 -0
- package/dist/charts/types.js +1 -0
- package/dist/commands/agents/index.d.ts +3 -0
- package/dist/commands/agents/index.js +65 -0
- package/dist/commands/agents/index.spec.d.ts +1 -0
- package/dist/commands/agents/index.spec.js +67 -0
- package/dist/commands/agents/selector.d.ts +8 -0
- package/dist/commands/agents/selector.js +53 -0
- package/dist/commands/agents.d.ts +2 -0
- package/dist/commands/agents.js +53 -0
- package/dist/commands/chat/index.d.ts +3 -0
- package/dist/commands/chat/index.js +29 -0
- package/dist/commands/chat.d.ts +2 -0
- package/dist/commands/chat.js +45 -0
- package/dist/commands/cluster/get.d.ts +2 -0
- package/dist/commands/cluster/get.js +39 -0
- package/dist/commands/cluster/get.spec.d.ts +1 -0
- package/dist/commands/cluster/get.spec.js +92 -0
- package/dist/commands/cluster/index.d.ts +2 -1
- package/dist/commands/cluster/index.js +3 -5
- package/dist/commands/cluster/index.spec.d.ts +1 -0
- package/dist/commands/cluster/index.spec.js +24 -0
- package/dist/commands/completion/index.d.ts +3 -0
- package/dist/commands/completion/index.js +230 -0
- package/dist/commands/completion/index.spec.d.ts +1 -0
- package/dist/commands/completion/index.spec.js +34 -0
- package/dist/commands/completion.js +159 -2
- package/dist/commands/config/index.d.ts +3 -0
- package/dist/commands/config/index.js +42 -0
- package/dist/commands/config/index.spec.d.ts +1 -0
- package/dist/commands/config/index.spec.js +78 -0
- package/dist/commands/config.d.ts +0 -3
- package/dist/commands/config.js +38 -321
- package/dist/commands/dashboard/index.d.ts +4 -0
- package/dist/commands/dashboard/index.js +39 -0
- package/dist/commands/dashboard.d.ts +3 -0
- package/dist/commands/dashboard.js +39 -0
- package/dist/commands/dev/index.d.ts +3 -0
- package/dist/commands/dev/index.js +9 -0
- package/dist/commands/dev/tool/check.d.ts +2 -0
- package/dist/commands/dev/tool/check.js +142 -0
- package/dist/commands/dev/tool/clean.d.ts +2 -0
- package/dist/commands/dev/tool/clean.js +153 -0
- package/dist/commands/dev/tool/generate.d.ts +2 -0
- package/dist/commands/dev/tool/generate.js +28 -0
- package/dist/commands/dev/tool/index.d.ts +2 -0
- package/dist/commands/dev/tool/index.js +14 -0
- package/dist/commands/dev/tool/init.d.ts +2 -0
- package/dist/commands/dev/tool/init.js +320 -0
- package/dist/commands/dev/tool/shared.d.ts +5 -0
- package/dist/commands/dev/tool/shared.js +258 -0
- package/dist/commands/dev/tool/status.d.ts +2 -0
- package/dist/commands/dev/tool/status.js +136 -0
- package/dist/commands/dev/tool-generate.spec.d.ts +1 -0
- package/dist/commands/dev/tool-generate.spec.js +163 -0
- package/dist/commands/dev/tool.d.ts +2 -0
- package/dist/commands/dev/tool.js +559 -0
- package/dist/commands/dev/tool.spec.d.ts +1 -0
- package/dist/commands/dev/tool.spec.js +48 -0
- package/dist/commands/docs/index.d.ts +4 -0
- package/dist/commands/docs/index.js +18 -0
- package/dist/commands/generate/config.js +5 -24
- package/dist/commands/generate/generators/mcpserver.d.ts +2 -1
- package/dist/commands/generate/generators/mcpserver.js +26 -5
- package/dist/commands/generate/generators/project.js +22 -41
- package/dist/commands/generate/index.d.ts +2 -1
- package/dist/commands/generate/index.js +1 -1
- package/dist/commands/install/index.d.ts +8 -0
- package/dist/commands/install/index.js +295 -0
- package/dist/commands/install/index.spec.d.ts +1 -0
- package/dist/commands/install/index.spec.js +143 -0
- package/dist/commands/install.d.ts +3 -0
- package/dist/commands/install.js +147 -0
- package/dist/commands/models/create.d.ts +1 -0
- package/dist/commands/models/create.js +213 -0
- package/dist/commands/models/create.spec.d.ts +1 -0
- package/dist/commands/models/create.spec.js +125 -0
- package/dist/commands/models/index.d.ts +3 -0
- package/dist/commands/models/index.js +75 -0
- package/dist/commands/models/index.spec.d.ts +1 -0
- package/dist/commands/models/index.spec.js +96 -0
- package/dist/commands/models/selector.d.ts +8 -0
- package/dist/commands/models/selector.js +53 -0
- package/dist/commands/query/index.d.ts +3 -0
- package/dist/commands/query/index.js +24 -0
- package/dist/commands/query/index.spec.d.ts +1 -0
- package/dist/commands/query/index.spec.js +53 -0
- package/dist/commands/routes/index.d.ts +3 -0
- package/dist/commands/routes/index.js +93 -0
- package/dist/commands/routes.d.ts +2 -0
- package/dist/commands/routes.js +101 -0
- package/dist/commands/status/index.d.ts +3 -0
- package/dist/commands/status/index.js +281 -0
- package/dist/commands/status.d.ts +3 -0
- package/dist/commands/status.js +33 -0
- package/dist/commands/targets/index.d.ts +3 -0
- package/dist/commands/targets/index.js +72 -0
- package/dist/commands/targets/index.spec.d.ts +1 -0
- package/dist/commands/targets/index.spec.js +154 -0
- package/dist/commands/targets.d.ts +2 -0
- package/dist/commands/targets.js +65 -0
- package/dist/commands/teams/index.d.ts +3 -0
- package/dist/commands/teams/index.js +64 -0
- package/dist/commands/teams/index.spec.d.ts +1 -0
- package/dist/commands/teams/index.spec.js +70 -0
- package/dist/commands/teams/selector.d.ts +8 -0
- package/dist/commands/teams/selector.js +55 -0
- package/dist/commands/tools/index.d.ts +3 -0
- package/dist/commands/tools/index.js +49 -0
- package/dist/commands/tools/index.spec.d.ts +1 -0
- package/dist/commands/tools/index.spec.js +70 -0
- package/dist/commands/tools/selector.d.ts +8 -0
- package/dist/commands/tools/selector.js +53 -0
- package/dist/commands/uninstall/index.d.ts +3 -0
- package/dist/commands/uninstall/index.js +101 -0
- package/dist/commands/uninstall/index.spec.d.ts +1 -0
- package/dist/commands/uninstall/index.spec.js +125 -0
- package/dist/commands/uninstall.d.ts +2 -0
- package/dist/commands/uninstall.js +83 -0
- package/dist/components/ChatUI.d.ts +16 -0
- package/dist/components/ChatUI.js +801 -0
- package/dist/components/StatusView.d.ts +10 -0
- package/dist/components/StatusView.js +39 -0
- package/dist/components/statusChecker.d.ts +14 -24
- package/dist/components/statusChecker.js +295 -129
- package/dist/config.d.ts +3 -22
- package/dist/config.js +10 -161
- package/dist/index.d.ts +1 -1
- package/dist/index.js +42 -42
- package/dist/lib/arkApiClient.d.ts +53 -0
- package/dist/lib/arkApiClient.js +102 -0
- package/dist/lib/arkApiProxy.d.ts +9 -0
- package/dist/lib/arkApiProxy.js +22 -0
- package/dist/lib/arkServiceProxy.d.ts +14 -0
- package/dist/lib/arkServiceProxy.js +95 -0
- package/dist/lib/arkStatus.d.ts +10 -0
- package/dist/lib/arkStatus.js +79 -0
- package/dist/lib/arkStatus.spec.d.ts +1 -0
- package/dist/lib/arkStatus.spec.js +49 -0
- package/dist/lib/chatClient.d.ts +33 -0
- package/dist/lib/chatClient.js +93 -0
- package/dist/lib/cluster.d.ts +2 -1
- package/dist/lib/cluster.js +37 -16
- package/dist/lib/cluster.spec.d.ts +1 -0
- package/dist/lib/cluster.spec.js +338 -0
- package/dist/lib/commandUtils.d.ts +4 -0
- package/dist/lib/commandUtils.js +18 -0
- package/dist/lib/commandUtils.test.d.ts +1 -0
- package/dist/lib/commandUtils.test.js +44 -0
- package/dist/lib/commands.d.ts +16 -0
- package/dist/lib/commands.js +29 -0
- package/dist/lib/commands.spec.d.ts +1 -0
- package/dist/lib/commands.spec.js +146 -0
- package/dist/lib/config.d.ts +26 -80
- package/dist/lib/config.js +70 -205
- package/dist/lib/config.spec.d.ts +1 -0
- package/dist/lib/config.spec.js +99 -0
- package/dist/lib/config.test.d.ts +1 -0
- package/dist/lib/config.test.js +93 -0
- package/dist/lib/consts.d.ts +0 -1
- package/dist/lib/consts.js +0 -2
- package/dist/lib/consts.spec.d.ts +1 -0
- package/dist/lib/consts.spec.js +15 -0
- package/dist/lib/dev/tools/analyzer.d.ts +30 -0
- package/dist/lib/dev/tools/analyzer.js +190 -0
- package/dist/lib/dev/tools/discover_tools.py +392 -0
- package/dist/lib/dev/tools/mcp-types.d.ts +28 -0
- package/dist/lib/dev/tools/mcp-types.js +86 -0
- package/dist/lib/dev/tools/types.d.ts +50 -0
- package/dist/lib/dev/tools/types.js +1 -0
- package/dist/lib/errors.js +1 -1
- package/dist/lib/errors.spec.d.ts +1 -0
- package/dist/lib/errors.spec.js +221 -0
- package/dist/lib/exec.d.ts +0 -4
- package/dist/lib/exec.js +0 -11
- package/dist/lib/executeQuery.d.ts +20 -0
- package/dist/lib/executeQuery.js +135 -0
- package/dist/lib/executeQuery.spec.d.ts +1 -0
- package/dist/lib/executeQuery.spec.js +170 -0
- package/dist/lib/nextSteps.d.ts +4 -0
- package/dist/lib/nextSteps.js +20 -0
- package/dist/lib/nextSteps.spec.d.ts +1 -0
- package/dist/lib/nextSteps.spec.js +59 -0
- package/dist/lib/output.d.ts +36 -0
- package/dist/lib/output.js +89 -0
- package/dist/lib/output.spec.d.ts +1 -0
- package/dist/lib/output.spec.js +123 -0
- package/dist/lib/portUtils.d.ts +8 -0
- package/dist/lib/portUtils.js +39 -0
- package/dist/lib/queryRunner.d.ts +22 -0
- package/dist/lib/queryRunner.js +142 -0
- package/dist/lib/startup.d.ts +9 -0
- package/dist/lib/startup.js +87 -0
- package/dist/lib/startup.spec.d.ts +1 -0
- package/dist/lib/startup.spec.js +152 -0
- package/dist/lib/types.d.ts +87 -3
- package/dist/lib/versions.d.ts +23 -0
- package/dist/lib/versions.js +51 -0
- package/dist/types/types.d.ts +40 -0
- package/dist/types/types.js +1 -0
- package/dist/ui/AgentSelector.d.ts +8 -0
- package/dist/ui/AgentSelector.js +53 -0
- package/dist/ui/MainMenu.d.ts +5 -1
- package/dist/ui/MainMenu.js +226 -91
- package/dist/ui/ModelSelector.d.ts +8 -0
- package/dist/ui/ModelSelector.js +53 -0
- package/dist/ui/TeamSelector.d.ts +8 -0
- package/dist/ui/TeamSelector.js +55 -0
- package/dist/ui/ToolSelector.d.ts +8 -0
- package/dist/ui/ToolSelector.js +53 -0
- package/dist/ui/statusFormatter.d.ts +22 -7
- package/dist/ui/statusFormatter.js +39 -39
- package/dist/ui/statusFormatter.spec.d.ts +1 -0
- package/dist/ui/statusFormatter.spec.js +58 -0
- package/package.json +16 -5
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export interface ToolParameter {
|
|
2
|
+
name: string;
|
|
3
|
+
type?: string;
|
|
4
|
+
}
|
|
5
|
+
export interface DiscoveredTool {
|
|
6
|
+
name: string;
|
|
7
|
+
parameters: ToolParameter[];
|
|
8
|
+
return_type?: string;
|
|
9
|
+
docstring?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface FileDiscoveryResult {
|
|
12
|
+
success: boolean;
|
|
13
|
+
file: string;
|
|
14
|
+
tools: DiscoveredTool[];
|
|
15
|
+
uses_fastmcp: boolean;
|
|
16
|
+
mcp_instance?: string;
|
|
17
|
+
server_name?: string;
|
|
18
|
+
error?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface DirectoryDiscoveryResult {
|
|
21
|
+
directory: string;
|
|
22
|
+
files: FileDiscoveryResult[];
|
|
23
|
+
total_tools: number;
|
|
24
|
+
uses_fastmcp: boolean;
|
|
25
|
+
}
|
|
26
|
+
export type DiscoveryResult = FileDiscoveryResult | DirectoryDiscoveryResult;
|
|
27
|
+
export interface ProjectDiscoveryResult {
|
|
28
|
+
path: string;
|
|
29
|
+
exists: boolean;
|
|
30
|
+
is_directory: boolean;
|
|
31
|
+
platform: 'python3' | null;
|
|
32
|
+
project_type: 'pyproject' | 'requirements' | null;
|
|
33
|
+
project_file: string | null;
|
|
34
|
+
project_name: string | null;
|
|
35
|
+
project_version: string | null;
|
|
36
|
+
has_fastmcp: boolean;
|
|
37
|
+
fastmcp_version: string | null;
|
|
38
|
+
}
|
|
39
|
+
export interface ProjectInfo {
|
|
40
|
+
path: string;
|
|
41
|
+
platform: 'python3';
|
|
42
|
+
projectType: 'pyproject' | 'requirements' | 'unknown';
|
|
43
|
+
hasVenv: boolean;
|
|
44
|
+
fastMCP: boolean;
|
|
45
|
+
fastMCPVersion?: string;
|
|
46
|
+
}
|
|
47
|
+
export interface ArkDevToolStatus extends ProjectInfo {
|
|
48
|
+
discovery?: DiscoveryResult;
|
|
49
|
+
tools: DiscoveredTool[];
|
|
50
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/lib/errors.js
CHANGED
|
@@ -162,9 +162,9 @@ export class InputValidator {
|
|
|
162
162
|
if (!kebabRegex.test(trimmed)) {
|
|
163
163
|
const suggestions = [];
|
|
164
164
|
const normalized = trimmed
|
|
165
|
+
.replace(/([a-z])([A-Z])/g, '$1-$2') // Handle camelCase first
|
|
165
166
|
.toLowerCase()
|
|
166
167
|
.replace(/[\s_]+/g, '-')
|
|
167
|
-
.replace(/([a-z])([A-Z])/g, '$1-$2')
|
|
168
168
|
.replace(/-{2,}/g, '-') // Replace 2+ consecutive hyphens with single hyphen (ReDoS-safe)
|
|
169
169
|
.replace(/^-/, '') // Remove single leading hyphen (ReDoS-safe)
|
|
170
170
|
.replace(/-$/, ''); // Remove single trailing hyphen (ReDoS-safe)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { describe, it, expect, jest, beforeEach, afterEach } from '@jest/globals';
|
|
2
|
+
import { ErrorCode, ArkError, ValidationError, TemplateError, ProjectStructureError, ErrorHandler, InputValidator, } from './errors.js';
|
|
3
|
+
jest.mock('fs');
|
|
4
|
+
describe('Error Classes', () => {
|
|
5
|
+
describe('ArkError', () => {
|
|
6
|
+
it('creates error with default code', () => {
|
|
7
|
+
const error = new ArkError('test message');
|
|
8
|
+
expect(error.message).toBe('test message');
|
|
9
|
+
expect(error.code).toBe(ErrorCode.UNKNOWN_ERROR);
|
|
10
|
+
expect(error.name).toBe('ArkError');
|
|
11
|
+
expect(error.details).toBeUndefined();
|
|
12
|
+
expect(error.suggestions).toBeUndefined();
|
|
13
|
+
});
|
|
14
|
+
it('creates error with all properties', () => {
|
|
15
|
+
const error = new ArkError('test error', ErrorCode.INVALID_INPUT, { field: 'name' }, ['Check the input', 'Try again']);
|
|
16
|
+
expect(error.message).toBe('test error');
|
|
17
|
+
expect(error.code).toBe(ErrorCode.INVALID_INPUT);
|
|
18
|
+
expect(error.details).toEqual({ field: 'name' });
|
|
19
|
+
expect(error.suggestions).toEqual(['Check the input', 'Try again']);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
describe('ValidationError', () => {
|
|
23
|
+
it('creates validation error without field', () => {
|
|
24
|
+
const error = new ValidationError('validation failed');
|
|
25
|
+
expect(error.message).toBe('validation failed');
|
|
26
|
+
expect(error.code).toBe(ErrorCode.VALIDATION_ERROR);
|
|
27
|
+
expect(error.name).toBe('ValidationError');
|
|
28
|
+
expect(error.details).toBeUndefined();
|
|
29
|
+
});
|
|
30
|
+
it('creates validation error with field and suggestions', () => {
|
|
31
|
+
const error = new ValidationError('invalid email', 'email', [
|
|
32
|
+
'Use valid format',
|
|
33
|
+
]);
|
|
34
|
+
expect(error.message).toBe('invalid email');
|
|
35
|
+
expect(error.code).toBe(ErrorCode.VALIDATION_ERROR);
|
|
36
|
+
expect(error.details).toEqual({ field: 'email' });
|
|
37
|
+
expect(error.suggestions).toEqual(['Use valid format']);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
describe('TemplateError', () => {
|
|
41
|
+
it('creates template error', () => {
|
|
42
|
+
const error = new TemplateError('template failed', 'template.yaml');
|
|
43
|
+
expect(error.message).toBe('template failed');
|
|
44
|
+
expect(error.code).toBe(ErrorCode.TEMPLATE_ERROR);
|
|
45
|
+
expect(error.name).toBe('TemplateError');
|
|
46
|
+
expect(error.details).toEqual({ templatePath: 'template.yaml' });
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
describe('ProjectStructureError', () => {
|
|
50
|
+
it('creates project structure error with defaults', () => {
|
|
51
|
+
const error = new ProjectStructureError('project invalid');
|
|
52
|
+
expect(error.message).toBe('project invalid');
|
|
53
|
+
expect(error.code).toBe(ErrorCode.PROJECT_STRUCTURE_INVALID);
|
|
54
|
+
expect(error.name).toBe('ProjectStructureError');
|
|
55
|
+
expect(error.suggestions).toEqual([
|
|
56
|
+
'Ensure you are in a valid ARK project directory',
|
|
57
|
+
'Run "ark generate project" to create a new project',
|
|
58
|
+
'Check that Chart.yaml and agents/ directory exist',
|
|
59
|
+
]);
|
|
60
|
+
});
|
|
61
|
+
it('creates project structure error with path', () => {
|
|
62
|
+
const error = new ProjectStructureError('project invalid', '/path/to/project');
|
|
63
|
+
expect(error.message).toBe('project invalid');
|
|
64
|
+
expect(error.code).toBe(ErrorCode.PROJECT_STRUCTURE_INVALID);
|
|
65
|
+
expect(error.details).toEqual({ projectPath: '/path/to/project' });
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
describe('ErrorHandler', () => {
|
|
69
|
+
it('formats basic error', () => {
|
|
70
|
+
const error = new Error('simple error');
|
|
71
|
+
const formatted = ErrorHandler.formatError(error);
|
|
72
|
+
expect(formatted).toContain('❌ simple error');
|
|
73
|
+
});
|
|
74
|
+
it('formats ArkError with details and suggestions', () => {
|
|
75
|
+
const error = new ArkError('test error', ErrorCode.INVALID_INPUT, { field: 'name', value: 'test' }, ['Fix the input', 'Try again']);
|
|
76
|
+
const formatted = ErrorHandler.formatError(error);
|
|
77
|
+
expect(formatted).toContain('❌ test error');
|
|
78
|
+
expect(formatted).toContain('Details:');
|
|
79
|
+
expect(formatted).toContain('field: name');
|
|
80
|
+
expect(formatted).toContain('value: test');
|
|
81
|
+
expect(formatted).toContain('💡 Suggestions:');
|
|
82
|
+
expect(formatted).toContain('• Fix the input');
|
|
83
|
+
expect(formatted).toContain('• Try again');
|
|
84
|
+
});
|
|
85
|
+
it('includes stack trace in debug mode', () => {
|
|
86
|
+
process.env.DEBUG = 'true';
|
|
87
|
+
const error = new Error('debug error');
|
|
88
|
+
const formatted = ErrorHandler.formatError(error);
|
|
89
|
+
expect(formatted).toContain('Stack trace:');
|
|
90
|
+
delete process.env.DEBUG;
|
|
91
|
+
});
|
|
92
|
+
it('handles missing stack trace', () => {
|
|
93
|
+
process.env.NODE_ENV = 'development';
|
|
94
|
+
const error = new Error('no stack');
|
|
95
|
+
error.stack = undefined;
|
|
96
|
+
const formatted = ErrorHandler.formatError(error);
|
|
97
|
+
expect(formatted).toContain('No stack trace available');
|
|
98
|
+
delete process.env.NODE_ENV;
|
|
99
|
+
});
|
|
100
|
+
describe('handleAndExit', () => {
|
|
101
|
+
let mockExit;
|
|
102
|
+
let mockConsoleError;
|
|
103
|
+
beforeEach(() => {
|
|
104
|
+
mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {
|
|
105
|
+
throw new Error('process.exit');
|
|
106
|
+
});
|
|
107
|
+
mockConsoleError = jest
|
|
108
|
+
.spyOn(console, 'error')
|
|
109
|
+
.mockImplementation(() => { });
|
|
110
|
+
});
|
|
111
|
+
afterEach(() => {
|
|
112
|
+
mockExit.mockRestore();
|
|
113
|
+
mockConsoleError.mockRestore();
|
|
114
|
+
});
|
|
115
|
+
it('exits with code 22 for validation errors', () => {
|
|
116
|
+
const error = new ValidationError('invalid');
|
|
117
|
+
expect(() => ErrorHandler.handleAndExit(error)).toThrow('process.exit');
|
|
118
|
+
expect(mockExit).toHaveBeenCalledWith(22);
|
|
119
|
+
});
|
|
120
|
+
it('exits with code 2 for file not found', () => {
|
|
121
|
+
const error = new ArkError('not found', ErrorCode.FILE_NOT_FOUND);
|
|
122
|
+
expect(() => ErrorHandler.handleAndExit(error)).toThrow('process.exit');
|
|
123
|
+
expect(mockExit).toHaveBeenCalledWith(2);
|
|
124
|
+
});
|
|
125
|
+
it('exits with code 13 for permission denied', () => {
|
|
126
|
+
const error = new ArkError('denied', ErrorCode.PERMISSION_DENIED);
|
|
127
|
+
expect(() => ErrorHandler.handleAndExit(error)).toThrow('process.exit');
|
|
128
|
+
expect(mockExit).toHaveBeenCalledWith(13);
|
|
129
|
+
});
|
|
130
|
+
it('exits with code 127 for missing dependency', () => {
|
|
131
|
+
const error = new ArkError('missing', ErrorCode.DEPENDENCY_MISSING);
|
|
132
|
+
expect(() => ErrorHandler.handleAndExit(error)).toThrow('process.exit');
|
|
133
|
+
expect(mockExit).toHaveBeenCalledWith(127);
|
|
134
|
+
});
|
|
135
|
+
it('exits with code 1 for unknown errors', () => {
|
|
136
|
+
const error = new Error('unknown');
|
|
137
|
+
expect(() => ErrorHandler.handleAndExit(error)).toThrow('process.exit');
|
|
138
|
+
expect(mockExit).toHaveBeenCalledWith(1);
|
|
139
|
+
});
|
|
140
|
+
it('exits with code 1 for default ArkError', () => {
|
|
141
|
+
const error = new ArkError('general', ErrorCode.UNKNOWN_ERROR);
|
|
142
|
+
expect(() => ErrorHandler.handleAndExit(error)).toThrow('process.exit');
|
|
143
|
+
expect(mockExit).toHaveBeenCalledWith(1);
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
describe('catchAndHandle', () => {
|
|
147
|
+
it('returns successful promise result', async () => {
|
|
148
|
+
const result = await ErrorHandler.catchAndHandle(async () => 'success');
|
|
149
|
+
expect(result).toBe('success');
|
|
150
|
+
});
|
|
151
|
+
it('rethrows ArkError unchanged', async () => {
|
|
152
|
+
const arkError = new ValidationError('test');
|
|
153
|
+
await expect(ErrorHandler.catchAndHandle(async () => {
|
|
154
|
+
throw arkError;
|
|
155
|
+
})).rejects.toThrow(arkError);
|
|
156
|
+
});
|
|
157
|
+
it('wraps generic errors with context', async () => {
|
|
158
|
+
const error = new Error('generic');
|
|
159
|
+
await expect(ErrorHandler.catchAndHandle(async () => {
|
|
160
|
+
throw error;
|
|
161
|
+
}, 'context')).rejects.toThrow('context: generic');
|
|
162
|
+
});
|
|
163
|
+
it('wraps non-Error objects', async () => {
|
|
164
|
+
await expect(ErrorHandler.catchAndHandle(async () => {
|
|
165
|
+
throw 'string error';
|
|
166
|
+
})).rejects.toThrow('string error');
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
describe('InputValidator', () => {
|
|
171
|
+
describe('validateName', () => {
|
|
172
|
+
it('accepts valid names', () => {
|
|
173
|
+
expect(() => InputValidator.validateName('valid-name')).not.toThrow();
|
|
174
|
+
expect(() => InputValidator.validateName('test123')).not.toThrow();
|
|
175
|
+
expect(() => InputValidator.validateName('a-b-c-123')).not.toThrow();
|
|
176
|
+
});
|
|
177
|
+
it('rejects empty names', () => {
|
|
178
|
+
expect(() => InputValidator.validateName('')).toThrow('name cannot be empty');
|
|
179
|
+
expect(() => InputValidator.validateName(' ')).toThrow('name cannot be empty');
|
|
180
|
+
});
|
|
181
|
+
it('rejects names over 63 characters', () => {
|
|
182
|
+
const longName = 'a'.repeat(64);
|
|
183
|
+
expect(() => InputValidator.validateName(longName)).toThrow('must be 63 characters or less');
|
|
184
|
+
});
|
|
185
|
+
it('rejects invalid characters', () => {
|
|
186
|
+
expect(() => InputValidator.validateName('Invalid Name')).toThrow('Invalid name');
|
|
187
|
+
expect(() => InputValidator.validateName('test_name')).toThrow('Invalid name');
|
|
188
|
+
expect(() => InputValidator.validateName('-start')).toThrow('Invalid name');
|
|
189
|
+
expect(() => InputValidator.validateName('end-')).toThrow('Invalid name');
|
|
190
|
+
});
|
|
191
|
+
it('suggests normalized names', () => {
|
|
192
|
+
try {
|
|
193
|
+
InputValidator.validateName('TestName');
|
|
194
|
+
}
|
|
195
|
+
catch (e) {
|
|
196
|
+
expect(e.suggestions).toContain('Try: "test-name"');
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
describe('validatePath', () => {
|
|
201
|
+
it('accepts valid paths', () => {
|
|
202
|
+
expect(() => InputValidator.validatePath('/valid/path')).not.toThrow();
|
|
203
|
+
expect(() => InputValidator.validatePath('./relative')).not.toThrow();
|
|
204
|
+
expect(() => InputValidator.validatePath('simple')).not.toThrow();
|
|
205
|
+
});
|
|
206
|
+
it('rejects empty paths', () => {
|
|
207
|
+
expect(() => InputValidator.validatePath('')).toThrow('path cannot be empty');
|
|
208
|
+
});
|
|
209
|
+
it('rejects dangerous paths', () => {
|
|
210
|
+
expect(() => InputValidator.validatePath('../parent')).toThrow('unsafe characters');
|
|
211
|
+
expect(() => InputValidator.validatePath('~/home')).toThrow('unsafe characters');
|
|
212
|
+
expect(() => InputValidator.validatePath('$HOME/test')).toThrow('unsafe characters');
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
describe('validateDirectory', () => {
|
|
216
|
+
it('validates path first', () => {
|
|
217
|
+
expect(() => InputValidator.validateDirectory('')).toThrow('directory cannot be empty');
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
});
|
package/dist/lib/exec.d.ts
CHANGED
package/dist/lib/exec.js
CHANGED
|
@@ -1,15 +1,4 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
|
-
import { execa } from 'execa';
|
|
3
|
-
export async function executeCommand(command, args = []) {
|
|
4
|
-
try {
|
|
5
|
-
const result = await execa(command, args);
|
|
6
|
-
return { stdout: result.stdout, stderr: result.stderr };
|
|
7
|
-
}
|
|
8
|
-
catch (error) {
|
|
9
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
10
|
-
throw new Error(`Command failed: ${command} ${args.join(' ')}\n${errorMessage}`);
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
2
|
export function fileExists(path) {
|
|
14
3
|
try {
|
|
15
4
|
return fs.existsSync(path);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared query execution logic for both universal and resource-specific query commands
|
|
3
|
+
*/
|
|
4
|
+
import type { QueryTarget } from './types.js';
|
|
5
|
+
export interface QueryOptions {
|
|
6
|
+
targetType: string;
|
|
7
|
+
targetName: string;
|
|
8
|
+
message: string;
|
|
9
|
+
verbose?: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Execute a query against any ARK target (model, agent, team)
|
|
13
|
+
* This is the shared implementation used by all query commands
|
|
14
|
+
*/
|
|
15
|
+
export declare function executeQuery(options: QueryOptions): Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* Parse a target string like "model/default" or "agent/weather"
|
|
18
|
+
* Returns QueryTarget or null if invalid
|
|
19
|
+
*/
|
|
20
|
+
export declare function parseTarget(target: string): QueryTarget | null;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared query execution logic for both universal and resource-specific query commands
|
|
3
|
+
*/
|
|
4
|
+
import { execa } from 'execa';
|
|
5
|
+
import ora from 'ora';
|
|
6
|
+
import output from './output.js';
|
|
7
|
+
/**
|
|
8
|
+
* Execute a query against any ARK target (model, agent, team)
|
|
9
|
+
* This is the shared implementation used by all query commands
|
|
10
|
+
*/
|
|
11
|
+
export async function executeQuery(options) {
|
|
12
|
+
const spinner = ora('Creating query...').start();
|
|
13
|
+
// Generate a unique query name
|
|
14
|
+
const timestamp = Date.now();
|
|
15
|
+
const queryName = `cli-query-${timestamp}`;
|
|
16
|
+
// Create the Query resource
|
|
17
|
+
const queryManifest = {
|
|
18
|
+
apiVersion: 'ark.mckinsey.com/v1alpha1',
|
|
19
|
+
kind: 'Query',
|
|
20
|
+
metadata: {
|
|
21
|
+
name: queryName,
|
|
22
|
+
},
|
|
23
|
+
spec: {
|
|
24
|
+
input: options.message,
|
|
25
|
+
targets: [
|
|
26
|
+
{
|
|
27
|
+
type: options.targetType,
|
|
28
|
+
name: options.targetName,
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
try {
|
|
34
|
+
// Apply the query
|
|
35
|
+
spinner.text = 'Submitting query...';
|
|
36
|
+
await execa('kubectl', ['apply', '-f', '-'], {
|
|
37
|
+
input: JSON.stringify(queryManifest),
|
|
38
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
39
|
+
});
|
|
40
|
+
// Watch for query completion
|
|
41
|
+
spinner.text = 'Query status: initializing';
|
|
42
|
+
let queryComplete = false;
|
|
43
|
+
let attempts = 0;
|
|
44
|
+
const maxAttempts = 300; // 5 minutes with 1 second intervals
|
|
45
|
+
while (!queryComplete && attempts < maxAttempts) {
|
|
46
|
+
attempts++;
|
|
47
|
+
try {
|
|
48
|
+
const { stdout } = await execa('kubectl', ['get', 'query', queryName, '-o', 'json'], { stdio: 'pipe' });
|
|
49
|
+
const query = JSON.parse(stdout);
|
|
50
|
+
const phase = query.status?.phase;
|
|
51
|
+
// Update spinner with current phase
|
|
52
|
+
if (phase) {
|
|
53
|
+
spinner.text = `Query status: ${phase}`;
|
|
54
|
+
}
|
|
55
|
+
// Check if query is complete based on phase
|
|
56
|
+
if (phase === 'done') {
|
|
57
|
+
queryComplete = true;
|
|
58
|
+
spinner.succeed('Query completed');
|
|
59
|
+
// Extract and display the response from responses array
|
|
60
|
+
if (query.status?.responses && query.status.responses.length > 0) {
|
|
61
|
+
const response = query.status.responses[0];
|
|
62
|
+
console.log('\n' + (response.content || response));
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
output.warning('No response received');
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
else if (phase === 'error') {
|
|
69
|
+
queryComplete = true;
|
|
70
|
+
spinner.fail('Query failed');
|
|
71
|
+
// Try to get error message from conditions or status
|
|
72
|
+
const errorCondition = query.status?.conditions?.find((c) => {
|
|
73
|
+
return c.type === 'Complete' && c.status === 'False';
|
|
74
|
+
});
|
|
75
|
+
if (errorCondition?.message) {
|
|
76
|
+
output.error(errorCondition.message);
|
|
77
|
+
}
|
|
78
|
+
else if (query.status?.error) {
|
|
79
|
+
output.error(query.status.error);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
output.error('Query failed with unknown error');
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
else if (phase === 'canceled') {
|
|
86
|
+
queryComplete = true;
|
|
87
|
+
spinner.warn('Query canceled');
|
|
88
|
+
// Try to get cancellation reason if available
|
|
89
|
+
if (query.status?.message) {
|
|
90
|
+
output.warning(query.status.message);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
// Query might not exist yet, continue waiting
|
|
96
|
+
spinner.text = 'Query status: waiting for query to be created';
|
|
97
|
+
}
|
|
98
|
+
if (!queryComplete) {
|
|
99
|
+
await new Promise((resolve) => setTimeout(resolve, 1000)); // Wait 1 second
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (!queryComplete) {
|
|
103
|
+
spinner.fail('Query timed out');
|
|
104
|
+
output.error('Query did not complete within 5 minutes');
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
spinner.fail('Query failed');
|
|
109
|
+
output.error(error instanceof Error ? error.message : 'Unknown error');
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
finally {
|
|
113
|
+
// Clean up the query resource
|
|
114
|
+
try {
|
|
115
|
+
await execa('kubectl', ['delete', 'query', queryName], { stdio: 'pipe' });
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
// Ignore cleanup errors
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Parse a target string like "model/default" or "agent/weather"
|
|
124
|
+
* Returns QueryTarget or null if invalid
|
|
125
|
+
*/
|
|
126
|
+
export function parseTarget(target) {
|
|
127
|
+
const parts = target.split('/');
|
|
128
|
+
if (parts.length !== 2) {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
type: parts[0],
|
|
133
|
+
name: parts[1],
|
|
134
|
+
};
|
|
135
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,170 @@
|
|
|
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
|
+
text: '',
|
|
12
|
+
};
|
|
13
|
+
const mockOra = jest.fn(() => mockSpinner);
|
|
14
|
+
jest.unstable_mockModule('ora', () => ({
|
|
15
|
+
default: mockOra,
|
|
16
|
+
}));
|
|
17
|
+
const mockOutput = {
|
|
18
|
+
warning: jest.fn(),
|
|
19
|
+
error: jest.fn(),
|
|
20
|
+
};
|
|
21
|
+
jest.unstable_mockModule('./output.js', () => ({
|
|
22
|
+
default: mockOutput,
|
|
23
|
+
}));
|
|
24
|
+
const mockExit = jest.spyOn(process, 'exit').mockImplementation((() => {
|
|
25
|
+
throw new Error('process.exit called');
|
|
26
|
+
}));
|
|
27
|
+
const mockConsoleLog = jest.spyOn(console, 'log').mockImplementation(() => { });
|
|
28
|
+
const { executeQuery, parseTarget } = await import('./executeQuery.js');
|
|
29
|
+
describe('executeQuery', () => {
|
|
30
|
+
beforeEach(() => {
|
|
31
|
+
jest.clearAllMocks();
|
|
32
|
+
mockSpinner.start.mockReturnValue(mockSpinner);
|
|
33
|
+
});
|
|
34
|
+
describe('parseTarget', () => {
|
|
35
|
+
it('should parse valid target strings', () => {
|
|
36
|
+
expect(parseTarget('model/default')).toEqual({
|
|
37
|
+
type: 'model',
|
|
38
|
+
name: 'default',
|
|
39
|
+
});
|
|
40
|
+
expect(parseTarget('agent/weather-agent')).toEqual({
|
|
41
|
+
type: 'agent',
|
|
42
|
+
name: 'weather-agent',
|
|
43
|
+
});
|
|
44
|
+
expect(parseTarget('team/my-team')).toEqual({
|
|
45
|
+
type: 'team',
|
|
46
|
+
name: 'my-team',
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
it('should return null for invalid target strings', () => {
|
|
50
|
+
expect(parseTarget('invalid')).toBeNull();
|
|
51
|
+
expect(parseTarget('')).toBeNull();
|
|
52
|
+
expect(parseTarget('model/default/extra')).toBeNull();
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
describe('executeQuery', () => {
|
|
56
|
+
it('should create and apply a query manifest', async () => {
|
|
57
|
+
const mockQueryResponse = {
|
|
58
|
+
status: {
|
|
59
|
+
phase: 'done',
|
|
60
|
+
responses: [{ content: 'Test response' }],
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
mockExeca.mockImplementation(async (command, args) => {
|
|
64
|
+
if (args.includes('apply')) {
|
|
65
|
+
return { stdout: '', stderr: '', exitCode: 0 };
|
|
66
|
+
}
|
|
67
|
+
if (args.includes('get') && args.includes('query')) {
|
|
68
|
+
return {
|
|
69
|
+
stdout: JSON.stringify(mockQueryResponse),
|
|
70
|
+
stderr: '',
|
|
71
|
+
exitCode: 0,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
if (args.includes('delete')) {
|
|
75
|
+
return { stdout: '', stderr: '', exitCode: 0 };
|
|
76
|
+
}
|
|
77
|
+
return { stdout: '', stderr: '', exitCode: 0 };
|
|
78
|
+
});
|
|
79
|
+
await executeQuery({
|
|
80
|
+
targetType: 'model',
|
|
81
|
+
targetName: 'default',
|
|
82
|
+
message: 'Hello',
|
|
83
|
+
});
|
|
84
|
+
expect(mockSpinner.start).toHaveBeenCalled();
|
|
85
|
+
expect(mockSpinner.succeed).toHaveBeenCalledWith('Query completed');
|
|
86
|
+
expect(mockConsoleLog).toHaveBeenCalledWith('\nTest response');
|
|
87
|
+
});
|
|
88
|
+
it('should handle query error phase', async () => {
|
|
89
|
+
const mockQueryResponse = {
|
|
90
|
+
status: {
|
|
91
|
+
phase: 'error',
|
|
92
|
+
error: 'Query failed with test error',
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
mockExeca.mockImplementation(async (command, args) => {
|
|
96
|
+
if (args.includes('apply')) {
|
|
97
|
+
return { stdout: '', stderr: '', exitCode: 0 };
|
|
98
|
+
}
|
|
99
|
+
if (args.includes('get') && args.includes('query')) {
|
|
100
|
+
return {
|
|
101
|
+
stdout: JSON.stringify(mockQueryResponse),
|
|
102
|
+
stderr: '',
|
|
103
|
+
exitCode: 0,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
if (args.includes('delete')) {
|
|
107
|
+
return { stdout: '', stderr: '', exitCode: 0 };
|
|
108
|
+
}
|
|
109
|
+
return { stdout: '', stderr: '', exitCode: 0 };
|
|
110
|
+
});
|
|
111
|
+
await executeQuery({
|
|
112
|
+
targetType: 'model',
|
|
113
|
+
targetName: 'default',
|
|
114
|
+
message: 'Hello',
|
|
115
|
+
});
|
|
116
|
+
expect(mockSpinner.fail).toHaveBeenCalledWith('Query failed');
|
|
117
|
+
expect(mockOutput.error).toHaveBeenCalledWith('Query failed with test error');
|
|
118
|
+
});
|
|
119
|
+
it('should handle query canceled phase', async () => {
|
|
120
|
+
const mockQueryResponse = {
|
|
121
|
+
status: {
|
|
122
|
+
phase: 'canceled',
|
|
123
|
+
message: 'Query was canceled',
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
mockExeca.mockImplementation(async (command, args) => {
|
|
127
|
+
if (args.includes('apply')) {
|
|
128
|
+
return { stdout: '', stderr: '', exitCode: 0 };
|
|
129
|
+
}
|
|
130
|
+
if (args.includes('get') && args.includes('query')) {
|
|
131
|
+
return {
|
|
132
|
+
stdout: JSON.stringify(mockQueryResponse),
|
|
133
|
+
stderr: '',
|
|
134
|
+
exitCode: 0,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
if (args.includes('delete')) {
|
|
138
|
+
return { stdout: '', stderr: '', exitCode: 0 };
|
|
139
|
+
}
|
|
140
|
+
return { stdout: '', stderr: '', exitCode: 0 };
|
|
141
|
+
});
|
|
142
|
+
await executeQuery({
|
|
143
|
+
targetType: 'agent',
|
|
144
|
+
targetName: 'test-agent',
|
|
145
|
+
message: 'Hello',
|
|
146
|
+
});
|
|
147
|
+
expect(mockSpinner.warn).toHaveBeenCalledWith('Query canceled');
|
|
148
|
+
expect(mockOutput.warning).toHaveBeenCalledWith('Query was canceled');
|
|
149
|
+
});
|
|
150
|
+
it('should clean up query resource even on failure', async () => {
|
|
151
|
+
mockExeca.mockImplementation(async (command, args) => {
|
|
152
|
+
if (args.includes('apply')) {
|
|
153
|
+
throw new Error('Failed to apply');
|
|
154
|
+
}
|
|
155
|
+
if (args.includes('delete')) {
|
|
156
|
+
return { stdout: '', stderr: '', exitCode: 0 };
|
|
157
|
+
}
|
|
158
|
+
return { stdout: '', stderr: '', exitCode: 0 };
|
|
159
|
+
});
|
|
160
|
+
await expect(executeQuery({
|
|
161
|
+
targetType: 'model',
|
|
162
|
+
targetName: 'default',
|
|
163
|
+
message: 'Hello',
|
|
164
|
+
})).rejects.toThrow('process.exit called');
|
|
165
|
+
expect(mockSpinner.fail).toHaveBeenCalledWith('Query failed');
|
|
166
|
+
expect(mockOutput.error).toHaveBeenCalledWith('Failed to apply');
|
|
167
|
+
expect(mockExit).toHaveBeenCalledWith(1);
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
/**
|
|
3
|
+
* Print helpful next steps after successful ARK installation
|
|
4
|
+
*/
|
|
5
|
+
export function printNextSteps() {
|
|
6
|
+
console.log();
|
|
7
|
+
console.log(chalk.green.bold('✓ ARK installed successfully!'));
|
|
8
|
+
console.log();
|
|
9
|
+
console.log(chalk.gray('Next steps:'));
|
|
10
|
+
console.log();
|
|
11
|
+
console.log(` ${chalk.gray('docs:')} ${chalk.blue('https://mckinsey.github.io/agents-at-scale-ark/')}`);
|
|
12
|
+
console.log(` ${chalk.gray('create model:')} ${chalk.white.bold('ark models create default')}`);
|
|
13
|
+
console.log(` ${chalk.gray('open dashboard:')} ${chalk.white.bold('ark dashboard')}`);
|
|
14
|
+
console.log(` ${chalk.gray('show agents:')} ${chalk.white.bold('kubectl get agents')}`);
|
|
15
|
+
console.log(` ${chalk.gray('run a query:')} ${chalk.white.bold('ark query model/default "What are large language models?"')}`);
|
|
16
|
+
console.log(` ${chalk.gray('interactive chat:')} ${chalk.white.bold('ark')} ${chalk.gray("# then choose 'Chat'")}`);
|
|
17
|
+
console.log(` ${chalk.gray('new project:')} ${chalk.white.bold('ark generate project my-agents')}`);
|
|
18
|
+
console.log(` ${chalk.gray('install fark:')} ${chalk.blue('https://mckinsey.github.io/agents-at-scale-ark/developer-guide/cli-tools/')}`);
|
|
19
|
+
console.log();
|
|
20
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|