@agents-at-scale/ark 0.1.35 → 0.1.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (167) hide show
  1. package/dist/arkServices.d.ts +42 -0
  2. package/dist/arkServices.js +138 -0
  3. package/dist/arkServices.spec.d.ts +1 -0
  4. package/dist/arkServices.spec.js +24 -0
  5. package/dist/commands/agents/index.d.ts +3 -0
  6. package/dist/commands/agents/index.js +65 -0
  7. package/dist/commands/agents/index.spec.d.ts +1 -0
  8. package/dist/commands/agents/index.spec.js +67 -0
  9. package/dist/commands/chat/index.d.ts +3 -0
  10. package/dist/commands/chat/index.js +29 -0
  11. package/dist/commands/cluster/get.d.ts +2 -0
  12. package/dist/commands/cluster/get.js +39 -0
  13. package/dist/commands/cluster/get.spec.d.ts +1 -0
  14. package/dist/commands/cluster/get.spec.js +92 -0
  15. package/dist/commands/cluster/index.d.ts +2 -1
  16. package/dist/commands/cluster/index.js +3 -5
  17. package/dist/commands/cluster/index.spec.d.ts +1 -0
  18. package/dist/commands/cluster/index.spec.js +24 -0
  19. package/dist/commands/completion/index.d.ts +3 -0
  20. package/dist/commands/completion/index.js +230 -0
  21. package/dist/commands/completion/index.spec.d.ts +1 -0
  22. package/dist/commands/completion/index.spec.js +34 -0
  23. package/dist/commands/config/index.d.ts +3 -0
  24. package/dist/commands/config/index.js +42 -0
  25. package/dist/commands/config/index.spec.d.ts +1 -0
  26. package/dist/commands/config/index.spec.js +78 -0
  27. package/dist/commands/dashboard/index.d.ts +4 -0
  28. package/dist/commands/dashboard/index.js +39 -0
  29. package/dist/commands/docs/index.d.ts +4 -0
  30. package/dist/commands/docs/index.js +18 -0
  31. package/dist/commands/generate/config.js +5 -24
  32. package/dist/commands/generate/generators/mcpserver.d.ts +2 -1
  33. package/dist/commands/generate/generators/mcpserver.js +26 -5
  34. package/dist/commands/generate/generators/project.js +22 -41
  35. package/dist/commands/generate/index.d.ts +2 -1
  36. package/dist/commands/generate/index.js +1 -1
  37. package/dist/commands/install/index.d.ts +8 -0
  38. package/dist/commands/install/index.js +295 -0
  39. package/dist/commands/install/index.spec.d.ts +1 -0
  40. package/dist/commands/install/index.spec.js +143 -0
  41. package/dist/commands/models/create.d.ts +1 -0
  42. package/dist/commands/models/create.js +213 -0
  43. package/dist/commands/models/create.spec.d.ts +1 -0
  44. package/dist/commands/models/create.spec.js +125 -0
  45. package/dist/commands/models/index.d.ts +3 -0
  46. package/dist/commands/models/index.js +75 -0
  47. package/dist/commands/models/index.spec.d.ts +1 -0
  48. package/dist/commands/models/index.spec.js +96 -0
  49. package/dist/commands/query/index.d.ts +3 -0
  50. package/dist/commands/query/index.js +24 -0
  51. package/dist/commands/query/index.spec.d.ts +1 -0
  52. package/dist/commands/query/index.spec.js +53 -0
  53. package/dist/commands/routes/index.d.ts +3 -0
  54. package/dist/commands/routes/index.js +93 -0
  55. package/dist/commands/status/index.d.ts +3 -0
  56. package/dist/commands/status/index.js +281 -0
  57. package/dist/commands/targets/index.d.ts +3 -0
  58. package/dist/commands/targets/index.js +72 -0
  59. package/dist/commands/targets/index.spec.d.ts +1 -0
  60. package/dist/commands/targets/index.spec.js +154 -0
  61. package/dist/commands/teams/index.d.ts +3 -0
  62. package/dist/commands/teams/index.js +64 -0
  63. package/dist/commands/teams/index.spec.d.ts +1 -0
  64. package/dist/commands/teams/index.spec.js +70 -0
  65. package/dist/commands/tools/index.d.ts +3 -0
  66. package/dist/commands/tools/index.js +49 -0
  67. package/dist/commands/tools/index.spec.d.ts +1 -0
  68. package/dist/commands/tools/index.spec.js +70 -0
  69. package/dist/commands/uninstall/index.d.ts +3 -0
  70. package/dist/commands/uninstall/index.js +101 -0
  71. package/dist/commands/uninstall/index.spec.d.ts +1 -0
  72. package/dist/commands/uninstall/index.spec.js +125 -0
  73. package/dist/components/ChatUI.d.ts +16 -0
  74. package/dist/components/ChatUI.js +801 -0
  75. package/dist/components/statusChecker.d.ts +14 -24
  76. package/dist/components/statusChecker.js +295 -129
  77. package/dist/index.d.ts +1 -1
  78. package/dist/index.js +42 -42
  79. package/dist/lib/arkApiClient.d.ts +53 -0
  80. package/dist/lib/arkApiClient.js +102 -0
  81. package/dist/lib/arkApiProxy.d.ts +9 -0
  82. package/dist/lib/arkApiProxy.js +22 -0
  83. package/dist/lib/arkServiceProxy.d.ts +14 -0
  84. package/dist/lib/arkServiceProxy.js +95 -0
  85. package/dist/lib/arkStatus.d.ts +10 -0
  86. package/dist/lib/arkStatus.js +79 -0
  87. package/dist/lib/arkStatus.spec.d.ts +1 -0
  88. package/dist/lib/arkStatus.spec.js +49 -0
  89. package/dist/lib/chatClient.d.ts +33 -0
  90. package/dist/lib/chatClient.js +93 -0
  91. package/dist/lib/cluster.d.ts +2 -1
  92. package/dist/lib/cluster.js +37 -16
  93. package/dist/lib/cluster.spec.d.ts +1 -0
  94. package/dist/lib/cluster.spec.js +338 -0
  95. package/dist/lib/commands.d.ts +16 -0
  96. package/dist/lib/commands.js +29 -0
  97. package/dist/lib/commands.spec.d.ts +1 -0
  98. package/dist/lib/commands.spec.js +146 -0
  99. package/dist/lib/config.d.ts +26 -80
  100. package/dist/lib/config.js +70 -205
  101. package/dist/lib/config.spec.d.ts +1 -0
  102. package/dist/lib/config.spec.js +99 -0
  103. package/dist/lib/errors.js +1 -1
  104. package/dist/lib/errors.spec.d.ts +1 -0
  105. package/dist/lib/errors.spec.js +221 -0
  106. package/dist/lib/executeQuery.d.ts +20 -0
  107. package/dist/lib/executeQuery.js +135 -0
  108. package/dist/lib/executeQuery.spec.d.ts +1 -0
  109. package/dist/lib/executeQuery.spec.js +170 -0
  110. package/dist/lib/nextSteps.d.ts +4 -0
  111. package/dist/lib/nextSteps.js +20 -0
  112. package/dist/lib/nextSteps.spec.d.ts +1 -0
  113. package/dist/lib/nextSteps.spec.js +59 -0
  114. package/dist/lib/output.d.ts +36 -0
  115. package/dist/lib/output.js +89 -0
  116. package/dist/lib/output.spec.d.ts +1 -0
  117. package/dist/lib/output.spec.js +123 -0
  118. package/dist/lib/startup.d.ts +9 -0
  119. package/dist/lib/startup.js +87 -0
  120. package/dist/lib/startup.spec.d.ts +1 -0
  121. package/dist/lib/startup.spec.js +152 -0
  122. package/dist/lib/types.d.ts +87 -3
  123. package/dist/lib/versions.d.ts +23 -0
  124. package/dist/lib/versions.js +51 -0
  125. package/dist/types/types.d.ts +40 -0
  126. package/dist/types/types.js +1 -0
  127. package/dist/ui/AgentSelector.d.ts +8 -0
  128. package/dist/ui/AgentSelector.js +53 -0
  129. package/dist/ui/MainMenu.d.ts +5 -1
  130. package/dist/ui/MainMenu.js +226 -91
  131. package/dist/ui/ModelSelector.d.ts +8 -0
  132. package/dist/ui/ModelSelector.js +53 -0
  133. package/dist/ui/TeamSelector.d.ts +8 -0
  134. package/dist/ui/TeamSelector.js +55 -0
  135. package/dist/ui/ToolSelector.d.ts +8 -0
  136. package/dist/ui/ToolSelector.js +53 -0
  137. package/dist/ui/statusFormatter.d.ts +22 -7
  138. package/dist/ui/statusFormatter.js +39 -39
  139. package/dist/ui/statusFormatter.spec.d.ts +1 -0
  140. package/dist/ui/statusFormatter.spec.js +58 -0
  141. package/package.json +16 -5
  142. package/dist/commands/cluster/get-ip.d.ts +0 -2
  143. package/dist/commands/cluster/get-ip.js +0 -32
  144. package/dist/commands/cluster/get-type.d.ts +0 -2
  145. package/dist/commands/cluster/get-type.js +0 -26
  146. package/dist/commands/completion.d.ts +0 -2
  147. package/dist/commands/completion.js +0 -108
  148. package/dist/commands/config.d.ts +0 -5
  149. package/dist/commands/config.js +0 -327
  150. package/dist/components/DashboardCLI.d.ts +0 -3
  151. package/dist/components/DashboardCLI.js +0 -149
  152. package/dist/config.d.ts +0 -42
  153. package/dist/config.js +0 -243
  154. package/dist/lib/arkClient.d.ts +0 -32
  155. package/dist/lib/arkClient.js +0 -43
  156. package/dist/lib/consts.d.ts +0 -10
  157. package/dist/lib/consts.js +0 -15
  158. package/dist/lib/exec.d.ts +0 -5
  159. package/dist/lib/exec.js +0 -20
  160. package/dist/lib/gatewayManager.d.ts +0 -24
  161. package/dist/lib/gatewayManager.js +0 -85
  162. package/dist/lib/kubernetes.d.ts +0 -28
  163. package/dist/lib/kubernetes.js +0 -122
  164. package/dist/lib/progress.d.ts +0 -128
  165. package/dist/lib/progress.js +0 -273
  166. package/dist/lib/wrappers/git.d.ts +0 -2
  167. package/dist/lib/wrappers/git.js +0 -43
@@ -0,0 +1,36 @@
1
+ export type StatusType = 'success' | 'warning' | 'info' | 'error';
2
+ declare const output: {
3
+ /**
4
+ * Display a status message with flexible formatting
5
+ */
6
+ statusMessage(type: StatusType, title: string, message?: string, ...args: unknown[]): void;
7
+ /**
8
+ * Display an error message with consistent formatting
9
+ */
10
+ error(message: string, ...args: unknown[]): void;
11
+ /**
12
+ * Display a success message with consistent formatting
13
+ */
14
+ success(message: string, ...args: unknown[]): void;
15
+ /**
16
+ * Display an info message (indented gray text)
17
+ */
18
+ info(message: string, ...args: unknown[]): void;
19
+ /**
20
+ * Display a warning message with consistent formatting
21
+ */
22
+ warning(message: string, ...args: unknown[]): void;
23
+ /**
24
+ * Display a status check item (like ark status format)
25
+ * @param status - 'found', 'missing', 'warning', 'error'
26
+ * @param label - The label to show (e.g., 'platform')
27
+ * @param value - The value in bright white (e.g., 'python3')
28
+ * @param details - Optional grey details
29
+ */
30
+ statusCheck(status: "found" | "missing" | "warning" | "error", label: string, value?: string, details?: string): void;
31
+ /**
32
+ * Display a section header (like 'ark services:')
33
+ */
34
+ section(title: string): void;
35
+ };
36
+ export default output;
@@ -0,0 +1,89 @@
1
+ import chalk from 'chalk';
2
+ const output = {
3
+ /**
4
+ * Display a status message with flexible formatting
5
+ */
6
+ statusMessage(type, title, message, ...args) {
7
+ const icons = {
8
+ success: chalk.green('✓'),
9
+ warning: chalk.yellow.bold('!'),
10
+ info: chalk.blue('ℹ'),
11
+ error: chalk.red('✗'),
12
+ };
13
+ const colors = {
14
+ success: chalk.green,
15
+ warning: chalk.yellow,
16
+ info: chalk.blue,
17
+ error: chalk.red,
18
+ };
19
+ const icon = icons[type];
20
+ const color = colors[type];
21
+ const logFn = type === 'error' ? console.error : console.log;
22
+ if (message) {
23
+ logFn(icon, color(`${title}:`), message, ...args);
24
+ }
25
+ else {
26
+ logFn(icon, title, ...args);
27
+ }
28
+ },
29
+ /**
30
+ * Display an error message with consistent formatting
31
+ */
32
+ error(message, ...args) {
33
+ this.statusMessage('error', 'error', message, ...args);
34
+ },
35
+ /**
36
+ * Display a success message with consistent formatting
37
+ */
38
+ success(message, ...args) {
39
+ this.statusMessage('success', message, undefined, ...args);
40
+ },
41
+ /**
42
+ * Display an info message (indented gray text)
43
+ */
44
+ info(message, ...args) {
45
+ console.log(chalk.gray(message), ...args);
46
+ },
47
+ /**
48
+ * Display a warning message with consistent formatting
49
+ */
50
+ warning(message, ...args) {
51
+ this.statusMessage('warning', 'warning', message, ...args);
52
+ },
53
+ /**
54
+ * Display a status check item (like ark status format)
55
+ * @param status - 'found', 'missing', 'warning', 'error'
56
+ * @param label - The label to show (e.g., 'platform')
57
+ * @param value - The value in bright white (e.g., 'python3')
58
+ * @param details - Optional grey details
59
+ */
60
+ statusCheck(status, label, value, details) {
61
+ const icons = {
62
+ found: chalk.green('✓'),
63
+ missing: chalk.yellow('?'),
64
+ warning: chalk.yellow('!'),
65
+ error: chalk.red('✗'),
66
+ };
67
+ const statusText = {
68
+ found: chalk.green(label),
69
+ missing: chalk.yellow(label),
70
+ warning: chalk.yellow(label),
71
+ error: chalk.red(label),
72
+ };
73
+ let output = ` ${icons[status]} ${statusText[status]}`;
74
+ if (value) {
75
+ output += ` ${chalk.bold.white(value)}`;
76
+ }
77
+ if (details) {
78
+ output += chalk.gray(` ${details}`);
79
+ }
80
+ console.log(output);
81
+ },
82
+ /**
83
+ * Display a section header (like 'ark services:')
84
+ */
85
+ section(title) {
86
+ console.log(chalk.cyan.bold(`${title}:`));
87
+ },
88
+ };
89
+ export default output;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,123 @@
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
+ });
@@ -0,0 +1,9 @@
1
+ import type { ArkConfig } from './config.js';
2
+ /**
3
+ * Show error message when no cluster is detected
4
+ */
5
+ export declare function showNoClusterError(): void;
6
+ /**
7
+ * Initialize the CLI with minimal checks for fast startup
8
+ */
9
+ export declare function startup(): Promise<ArkConfig>;
@@ -0,0 +1,87 @@
1
+ import chalk from 'chalk';
2
+ import { execa } from 'execa';
3
+ import { checkCommandExists } from './commands.js';
4
+ import { loadConfig } from './config.js';
5
+ const REQUIRED_COMMANDS = [
6
+ {
7
+ name: 'kubectl',
8
+ command: 'kubectl',
9
+ args: ['version', '--client'],
10
+ installUrl: 'https://kubernetes.io/docs/tasks/tools/',
11
+ },
12
+ {
13
+ name: 'helm',
14
+ command: 'helm',
15
+ args: ['version', '--short'],
16
+ installUrl: 'https://helm.sh/docs/intro/install/',
17
+ },
18
+ ];
19
+ async function checkRequirements() {
20
+ const missing = [];
21
+ for (const cmd of REQUIRED_COMMANDS) {
22
+ const exists = await checkCommandExists(cmd.command, cmd.args);
23
+ if (!exists) {
24
+ missing.push(cmd);
25
+ }
26
+ }
27
+ if (missing.length > 0) {
28
+ for (const cmd of missing) {
29
+ console.error(chalk.red('error:') + ` ${cmd.name} is required`);
30
+ console.error(' ' + chalk.blue(cmd.installUrl));
31
+ }
32
+ process.exit(1);
33
+ }
34
+ }
35
+ /**
36
+ * Show error message when no cluster is detected
37
+ */
38
+ export function showNoClusterError() {
39
+ console.log(chalk.red.bold('\n✗ No Kubernetes cluster detected\n'));
40
+ console.log('Please ensure you have configured a connection to a Kubernetes cluster.');
41
+ console.log('For local development, you can use:');
42
+ console.log(` • Minikube: ${chalk.blue('https://minikube.sigs.k8s.io/docs/start')}`);
43
+ console.log(` • Docker Desktop: ${chalk.blue('https://docs.docker.com/desktop/kubernetes/')}`);
44
+ console.log(` • Kind: ${chalk.blue('https://kind.sigs.k8s.io/docs/user/quick-start/')}`);
45
+ console.log('');
46
+ console.log('And more. For help, check the Quickstart guide:');
47
+ console.log(chalk.blue(' https://mckinsey.github.io/agents-at-scale-ark/quickstart/'));
48
+ }
49
+ /**
50
+ * Check if a Kubernetes context is configured
51
+ * This is a fast local check that doesn't hit the cluster
52
+ */
53
+ async function hasKubernetesContext() {
54
+ try {
55
+ const { stdout } = await execa('kubectl', ['config', 'current-context']);
56
+ return stdout.trim().length > 0;
57
+ }
58
+ catch {
59
+ return false;
60
+ }
61
+ }
62
+ /**
63
+ * Initialize the CLI with minimal checks for fast startup
64
+ */
65
+ export async function startup() {
66
+ // Check required commands (kubectl, helm) - fast local checks
67
+ await checkRequirements();
68
+ // Load config from disk (fast - just file I/O)
69
+ const config = loadConfig();
70
+ // Check if we have a kubernetes context configured (fast local check)
71
+ // We don't check cluster connectivity here - that's expensive
72
+ const hasContext = await hasKubernetesContext();
73
+ if (hasContext) {
74
+ try {
75
+ const { stdout } = await execa('kubectl', ['config', 'current-context']);
76
+ config.clusterInfo = {
77
+ type: 'unknown', // We don't detect cluster type here - too slow
78
+ context: stdout.trim(),
79
+ // We don't fetch namespace or cluster details here - too slow
80
+ };
81
+ }
82
+ catch {
83
+ // Ignore - no context
84
+ }
85
+ }
86
+ return config;
87
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,152 @@
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']);
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
+ });
@@ -13,25 +13,109 @@ export interface KubernetesConfig {
13
13
  namespace?: string;
14
14
  inCluster: boolean;
15
15
  }
16
- export interface ServiceStatus {
16
+ export type DeploymentStatus = 'available' | 'progressing' | 'replicafailure' | 'failed' | 'not found' | 'unknown';
17
+ export type ServiceStatus = {
17
18
  name: string;
18
- status: 'healthy' | 'unhealthy' | 'not installed';
19
+ status: 'healthy' | 'warning' | 'unhealthy' | 'not installed' | 'not ready';
20
+ deploymentStatus?: DeploymentStatus;
19
21
  url?: string;
20
22
  version?: string;
23
+ revision?: string;
21
24
  details?: string;
22
- }
25
+ isDev?: boolean;
26
+ namespace?: string;
27
+ };
23
28
  export interface DependencyStatus {
24
29
  name: string;
25
30
  installed: boolean;
26
31
  version?: string;
27
32
  details?: string;
28
33
  }
34
+ export interface ModelStatus {
35
+ exists: boolean;
36
+ available?: boolean;
37
+ provider?: string;
38
+ details?: string;
39
+ }
29
40
  export interface StatusData {
30
41
  services: ServiceStatus[];
31
42
  dependencies: DependencyStatus[];
43
+ arkReady?: boolean;
44
+ defaultModelExists?: boolean;
45
+ defaultModel?: ModelStatus;
32
46
  }
33
47
  export interface CommandVersionConfig {
34
48
  command: string;
35
49
  versionArgs: string;
36
50
  versionExtract: (_output: string) => string;
37
51
  }
52
+ export interface K8sMetadata {
53
+ name: string;
54
+ namespace?: string;
55
+ }
56
+ export interface K8sCondition {
57
+ type: string;
58
+ status: string;
59
+ message?: string;
60
+ }
61
+ export interface K8sListResource<T> {
62
+ items: T[];
63
+ }
64
+ export interface HelmRelease {
65
+ name: string;
66
+ app_version?: string;
67
+ revision?: string;
68
+ }
69
+ export interface K8sDeployment {
70
+ metadata: K8sMetadata;
71
+ spec?: {
72
+ replicas?: number;
73
+ };
74
+ status?: {
75
+ readyReplicas?: number;
76
+ availableReplicas?: number;
77
+ conditions?: K8sCondition[];
78
+ };
79
+ }
80
+ export interface Model {
81
+ metadata: K8sMetadata;
82
+ status?: ModelStatus;
83
+ }
84
+ export interface Agent {
85
+ metadata: K8sMetadata;
86
+ }
87
+ export interface Team {
88
+ metadata: K8sMetadata;
89
+ }
90
+ export interface QueryTarget {
91
+ type: string;
92
+ name: string;
93
+ }
94
+ export interface QueryResponse {
95
+ content?: string;
96
+ }
97
+ export interface Query {
98
+ apiVersion: string;
99
+ kind: 'Query';
100
+ metadata: K8sMetadata;
101
+ spec?: {
102
+ input: string;
103
+ targets: QueryTarget[];
104
+ };
105
+ status?: {
106
+ phase?: 'initializing' | 'running' | 'done' | 'error' | 'canceled';
107
+ conditions?: K8sCondition[];
108
+ responses?: QueryResponse[];
109
+ message?: string;
110
+ error?: string;
111
+ };
112
+ }
113
+ export interface Tool {
114
+ metadata: K8sMetadata;
115
+ }
116
+ export interface ClusterInfo {
117
+ context?: string;
118
+ cluster?: string;
119
+ user?: string;
120
+ namespace?: string;
121
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Version information for ARK
3
+ */
4
+ export interface ArkVersionInfo {
5
+ current?: string;
6
+ latest?: string;
7
+ updateAvailable?: boolean;
8
+ }
9
+ /**
10
+ * Fetch the latest ARK version from GitHub releases
11
+ * @returns Latest version string or undefined if fetch fails
12
+ */
13
+ export declare function fetchLatestVersion(): Promise<string | undefined>;
14
+ /**
15
+ * Get current installed ARK version from Helm
16
+ * @returns Current version string or undefined if not found
17
+ */
18
+ export declare function fetchCurrentVersion(): Promise<string | undefined>;
19
+ /**
20
+ * Fetch both current and latest versions in parallel
21
+ * @returns Version information
22
+ */
23
+ export declare function fetchVersionInfo(): Promise<ArkVersionInfo>;