@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.
Files changed (223) 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/charts/charts.d.ts +5 -0
  6. package/dist/charts/charts.js +6 -0
  7. package/dist/charts/dependencies.d.ts +6 -0
  8. package/dist/charts/dependencies.js +50 -0
  9. package/dist/charts/types.d.ts +40 -0
  10. package/dist/charts/types.js +1 -0
  11. package/dist/commands/agents/index.d.ts +3 -0
  12. package/dist/commands/agents/index.js +65 -0
  13. package/dist/commands/agents/index.spec.d.ts +1 -0
  14. package/dist/commands/agents/index.spec.js +67 -0
  15. package/dist/commands/agents/selector.d.ts +8 -0
  16. package/dist/commands/agents/selector.js +53 -0
  17. package/dist/commands/agents.d.ts +2 -0
  18. package/dist/commands/agents.js +53 -0
  19. package/dist/commands/chat/index.d.ts +3 -0
  20. package/dist/commands/chat/index.js +29 -0
  21. package/dist/commands/chat.d.ts +2 -0
  22. package/dist/commands/chat.js +45 -0
  23. package/dist/commands/cluster/get.d.ts +2 -0
  24. package/dist/commands/cluster/get.js +39 -0
  25. package/dist/commands/cluster/get.spec.d.ts +1 -0
  26. package/dist/commands/cluster/get.spec.js +92 -0
  27. package/dist/commands/cluster/index.d.ts +2 -1
  28. package/dist/commands/cluster/index.js +3 -5
  29. package/dist/commands/cluster/index.spec.d.ts +1 -0
  30. package/dist/commands/cluster/index.spec.js +24 -0
  31. package/dist/commands/completion/index.d.ts +3 -0
  32. package/dist/commands/completion/index.js +230 -0
  33. package/dist/commands/completion/index.spec.d.ts +1 -0
  34. package/dist/commands/completion/index.spec.js +34 -0
  35. package/dist/commands/completion.js +159 -2
  36. package/dist/commands/config/index.d.ts +3 -0
  37. package/dist/commands/config/index.js +42 -0
  38. package/dist/commands/config/index.spec.d.ts +1 -0
  39. package/dist/commands/config/index.spec.js +78 -0
  40. package/dist/commands/config.d.ts +0 -3
  41. package/dist/commands/config.js +38 -321
  42. package/dist/commands/dashboard/index.d.ts +4 -0
  43. package/dist/commands/dashboard/index.js +39 -0
  44. package/dist/commands/dashboard.d.ts +3 -0
  45. package/dist/commands/dashboard.js +39 -0
  46. package/dist/commands/dev/index.d.ts +3 -0
  47. package/dist/commands/dev/index.js +9 -0
  48. package/dist/commands/dev/tool/check.d.ts +2 -0
  49. package/dist/commands/dev/tool/check.js +142 -0
  50. package/dist/commands/dev/tool/clean.d.ts +2 -0
  51. package/dist/commands/dev/tool/clean.js +153 -0
  52. package/dist/commands/dev/tool/generate.d.ts +2 -0
  53. package/dist/commands/dev/tool/generate.js +28 -0
  54. package/dist/commands/dev/tool/index.d.ts +2 -0
  55. package/dist/commands/dev/tool/index.js +14 -0
  56. package/dist/commands/dev/tool/init.d.ts +2 -0
  57. package/dist/commands/dev/tool/init.js +320 -0
  58. package/dist/commands/dev/tool/shared.d.ts +5 -0
  59. package/dist/commands/dev/tool/shared.js +258 -0
  60. package/dist/commands/dev/tool/status.d.ts +2 -0
  61. package/dist/commands/dev/tool/status.js +136 -0
  62. package/dist/commands/dev/tool-generate.spec.d.ts +1 -0
  63. package/dist/commands/dev/tool-generate.spec.js +163 -0
  64. package/dist/commands/dev/tool.d.ts +2 -0
  65. package/dist/commands/dev/tool.js +559 -0
  66. package/dist/commands/dev/tool.spec.d.ts +1 -0
  67. package/dist/commands/dev/tool.spec.js +48 -0
  68. package/dist/commands/docs/index.d.ts +4 -0
  69. package/dist/commands/docs/index.js +18 -0
  70. package/dist/commands/generate/config.js +5 -24
  71. package/dist/commands/generate/generators/mcpserver.d.ts +2 -1
  72. package/dist/commands/generate/generators/mcpserver.js +26 -5
  73. package/dist/commands/generate/generators/project.js +22 -41
  74. package/dist/commands/generate/index.d.ts +2 -1
  75. package/dist/commands/generate/index.js +1 -1
  76. package/dist/commands/install/index.d.ts +8 -0
  77. package/dist/commands/install/index.js +295 -0
  78. package/dist/commands/install/index.spec.d.ts +1 -0
  79. package/dist/commands/install/index.spec.js +143 -0
  80. package/dist/commands/install.d.ts +3 -0
  81. package/dist/commands/install.js +147 -0
  82. package/dist/commands/models/create.d.ts +1 -0
  83. package/dist/commands/models/create.js +213 -0
  84. package/dist/commands/models/create.spec.d.ts +1 -0
  85. package/dist/commands/models/create.spec.js +125 -0
  86. package/dist/commands/models/index.d.ts +3 -0
  87. package/dist/commands/models/index.js +75 -0
  88. package/dist/commands/models/index.spec.d.ts +1 -0
  89. package/dist/commands/models/index.spec.js +96 -0
  90. package/dist/commands/models/selector.d.ts +8 -0
  91. package/dist/commands/models/selector.js +53 -0
  92. package/dist/commands/query/index.d.ts +3 -0
  93. package/dist/commands/query/index.js +24 -0
  94. package/dist/commands/query/index.spec.d.ts +1 -0
  95. package/dist/commands/query/index.spec.js +53 -0
  96. package/dist/commands/routes/index.d.ts +3 -0
  97. package/dist/commands/routes/index.js +93 -0
  98. package/dist/commands/routes.d.ts +2 -0
  99. package/dist/commands/routes.js +101 -0
  100. package/dist/commands/status/index.d.ts +3 -0
  101. package/dist/commands/status/index.js +281 -0
  102. package/dist/commands/status.d.ts +3 -0
  103. package/dist/commands/status.js +33 -0
  104. package/dist/commands/targets/index.d.ts +3 -0
  105. package/dist/commands/targets/index.js +72 -0
  106. package/dist/commands/targets/index.spec.d.ts +1 -0
  107. package/dist/commands/targets/index.spec.js +154 -0
  108. package/dist/commands/targets.d.ts +2 -0
  109. package/dist/commands/targets.js +65 -0
  110. package/dist/commands/teams/index.d.ts +3 -0
  111. package/dist/commands/teams/index.js +64 -0
  112. package/dist/commands/teams/index.spec.d.ts +1 -0
  113. package/dist/commands/teams/index.spec.js +70 -0
  114. package/dist/commands/teams/selector.d.ts +8 -0
  115. package/dist/commands/teams/selector.js +55 -0
  116. package/dist/commands/tools/index.d.ts +3 -0
  117. package/dist/commands/tools/index.js +49 -0
  118. package/dist/commands/tools/index.spec.d.ts +1 -0
  119. package/dist/commands/tools/index.spec.js +70 -0
  120. package/dist/commands/tools/selector.d.ts +8 -0
  121. package/dist/commands/tools/selector.js +53 -0
  122. package/dist/commands/uninstall/index.d.ts +3 -0
  123. package/dist/commands/uninstall/index.js +101 -0
  124. package/dist/commands/uninstall/index.spec.d.ts +1 -0
  125. package/dist/commands/uninstall/index.spec.js +125 -0
  126. package/dist/commands/uninstall.d.ts +2 -0
  127. package/dist/commands/uninstall.js +83 -0
  128. package/dist/components/ChatUI.d.ts +16 -0
  129. package/dist/components/ChatUI.js +801 -0
  130. package/dist/components/StatusView.d.ts +10 -0
  131. package/dist/components/StatusView.js +39 -0
  132. package/dist/components/statusChecker.d.ts +14 -24
  133. package/dist/components/statusChecker.js +295 -129
  134. package/dist/config.d.ts +3 -22
  135. package/dist/config.js +10 -161
  136. package/dist/index.d.ts +1 -1
  137. package/dist/index.js +42 -42
  138. package/dist/lib/arkApiClient.d.ts +53 -0
  139. package/dist/lib/arkApiClient.js +102 -0
  140. package/dist/lib/arkApiProxy.d.ts +9 -0
  141. package/dist/lib/arkApiProxy.js +22 -0
  142. package/dist/lib/arkServiceProxy.d.ts +14 -0
  143. package/dist/lib/arkServiceProxy.js +95 -0
  144. package/dist/lib/arkStatus.d.ts +10 -0
  145. package/dist/lib/arkStatus.js +79 -0
  146. package/dist/lib/arkStatus.spec.d.ts +1 -0
  147. package/dist/lib/arkStatus.spec.js +49 -0
  148. package/dist/lib/chatClient.d.ts +33 -0
  149. package/dist/lib/chatClient.js +93 -0
  150. package/dist/lib/cluster.d.ts +2 -1
  151. package/dist/lib/cluster.js +37 -16
  152. package/dist/lib/cluster.spec.d.ts +1 -0
  153. package/dist/lib/cluster.spec.js +338 -0
  154. package/dist/lib/commandUtils.d.ts +4 -0
  155. package/dist/lib/commandUtils.js +18 -0
  156. package/dist/lib/commandUtils.test.d.ts +1 -0
  157. package/dist/lib/commandUtils.test.js +44 -0
  158. package/dist/lib/commands.d.ts +16 -0
  159. package/dist/lib/commands.js +29 -0
  160. package/dist/lib/commands.spec.d.ts +1 -0
  161. package/dist/lib/commands.spec.js +146 -0
  162. package/dist/lib/config.d.ts +26 -80
  163. package/dist/lib/config.js +70 -205
  164. package/dist/lib/config.spec.d.ts +1 -0
  165. package/dist/lib/config.spec.js +99 -0
  166. package/dist/lib/config.test.d.ts +1 -0
  167. package/dist/lib/config.test.js +93 -0
  168. package/dist/lib/consts.d.ts +0 -1
  169. package/dist/lib/consts.js +0 -2
  170. package/dist/lib/consts.spec.d.ts +1 -0
  171. package/dist/lib/consts.spec.js +15 -0
  172. package/dist/lib/dev/tools/analyzer.d.ts +30 -0
  173. package/dist/lib/dev/tools/analyzer.js +190 -0
  174. package/dist/lib/dev/tools/discover_tools.py +392 -0
  175. package/dist/lib/dev/tools/mcp-types.d.ts +28 -0
  176. package/dist/lib/dev/tools/mcp-types.js +86 -0
  177. package/dist/lib/dev/tools/types.d.ts +50 -0
  178. package/dist/lib/dev/tools/types.js +1 -0
  179. package/dist/lib/errors.js +1 -1
  180. package/dist/lib/errors.spec.d.ts +1 -0
  181. package/dist/lib/errors.spec.js +221 -0
  182. package/dist/lib/exec.d.ts +0 -4
  183. package/dist/lib/exec.js +0 -11
  184. package/dist/lib/executeQuery.d.ts +20 -0
  185. package/dist/lib/executeQuery.js +135 -0
  186. package/dist/lib/executeQuery.spec.d.ts +1 -0
  187. package/dist/lib/executeQuery.spec.js +170 -0
  188. package/dist/lib/nextSteps.d.ts +4 -0
  189. package/dist/lib/nextSteps.js +20 -0
  190. package/dist/lib/nextSteps.spec.d.ts +1 -0
  191. package/dist/lib/nextSteps.spec.js +59 -0
  192. package/dist/lib/output.d.ts +36 -0
  193. package/dist/lib/output.js +89 -0
  194. package/dist/lib/output.spec.d.ts +1 -0
  195. package/dist/lib/output.spec.js +123 -0
  196. package/dist/lib/portUtils.d.ts +8 -0
  197. package/dist/lib/portUtils.js +39 -0
  198. package/dist/lib/queryRunner.d.ts +22 -0
  199. package/dist/lib/queryRunner.js +142 -0
  200. package/dist/lib/startup.d.ts +9 -0
  201. package/dist/lib/startup.js +87 -0
  202. package/dist/lib/startup.spec.d.ts +1 -0
  203. package/dist/lib/startup.spec.js +152 -0
  204. package/dist/lib/types.d.ts +87 -3
  205. package/dist/lib/versions.d.ts +23 -0
  206. package/dist/lib/versions.js +51 -0
  207. package/dist/types/types.d.ts +40 -0
  208. package/dist/types/types.js +1 -0
  209. package/dist/ui/AgentSelector.d.ts +8 -0
  210. package/dist/ui/AgentSelector.js +53 -0
  211. package/dist/ui/MainMenu.d.ts +5 -1
  212. package/dist/ui/MainMenu.js +226 -91
  213. package/dist/ui/ModelSelector.d.ts +8 -0
  214. package/dist/ui/ModelSelector.js +53 -0
  215. package/dist/ui/TeamSelector.d.ts +8 -0
  216. package/dist/ui/TeamSelector.js +55 -0
  217. package/dist/ui/ToolSelector.d.ts +8 -0
  218. package/dist/ui/ToolSelector.js +53 -0
  219. package/dist/ui/statusFormatter.d.ts +22 -7
  220. package/dist/ui/statusFormatter.js +39 -39
  221. package/dist/ui/statusFormatter.spec.d.ts +1 -0
  222. package/dist/ui/statusFormatter.spec.js +58 -0
  223. package/package.json +16 -5
@@ -0,0 +1,59 @@
1
+ import { jest } from '@jest/globals';
2
+ import { printNextSteps } from './nextSteps.js';
3
+ describe('printNextSteps', () => {
4
+ let consoleLogSpy;
5
+ let output = [];
6
+ beforeEach(() => {
7
+ output = [];
8
+ consoleLogSpy = jest.spyOn(console, 'log').mockImplementation((...args) => {
9
+ output.push(args.join(' '));
10
+ });
11
+ });
12
+ afterEach(() => {
13
+ consoleLogSpy.mockRestore();
14
+ });
15
+ it('prints successful installation message', () => {
16
+ printNextSteps();
17
+ const fullOutput = output.join('\n');
18
+ expect(fullOutput).toContain('ARK installed successfully!');
19
+ });
20
+ it('includes all required commands', () => {
21
+ printNextSteps();
22
+ const fullOutput = output.join('\n');
23
+ // Check for each command
24
+ expect(fullOutput).toContain('ark models create default');
25
+ expect(fullOutput).toContain('ark dashboard');
26
+ expect(fullOutput).toContain('kubectl get agents');
27
+ expect(fullOutput).toContain('ark query model/default "What are large language models?"');
28
+ expect(fullOutput).toContain('ark');
29
+ expect(fullOutput).toContain("# then choose 'Chat'");
30
+ expect(fullOutput).toContain('ark generate project my-agents');
31
+ });
32
+ it('includes all required links', () => {
33
+ printNextSteps();
34
+ const fullOutput = output.join('\n');
35
+ // Check for documentation links
36
+ expect(fullOutput).toContain('https://mckinsey.github.io/agents-at-scale-ark/');
37
+ expect(fullOutput).toContain('https://mckinsey.github.io/agents-at-scale-ark/developer-guide/cli-tools/');
38
+ });
39
+ it('includes all section labels', () => {
40
+ printNextSteps();
41
+ const fullOutput = output.join('\n');
42
+ // Check for labels
43
+ expect(fullOutput).toContain('Next steps:');
44
+ expect(fullOutput).toContain('docs:');
45
+ expect(fullOutput).toContain('create model:');
46
+ expect(fullOutput).toContain('open dashboard:');
47
+ expect(fullOutput).toContain('show agents:');
48
+ expect(fullOutput).toContain('run a query:');
49
+ expect(fullOutput).toContain('interactive chat:');
50
+ expect(fullOutput).toContain('new project:');
51
+ expect(fullOutput).toContain('install fark:');
52
+ });
53
+ it('has correct structure with empty lines', () => {
54
+ printNextSteps();
55
+ // Should have empty lines for formatting
56
+ expect(output[0]).toBe('');
57
+ expect(output[output.length - 1]).toBe('');
58
+ });
59
+ });
@@ -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,8 @@
1
+ /**
2
+ * Check if a port is available
3
+ */
4
+ export declare function isPortAvailable(port: number): Promise<boolean>;
5
+ /**
6
+ * Find an available port, starting from the preferred port
7
+ */
8
+ export declare function findAvailablePort(preferredPort: number, maxAttempts?: number): Promise<number>;
@@ -0,0 +1,39 @@
1
+ import net from 'net';
2
+ /**
3
+ * Check if a port is available
4
+ */
5
+ export async function isPortAvailable(port) {
6
+ return new Promise((resolve) => {
7
+ const server = net.createServer();
8
+ server.once('error', (err) => {
9
+ if (err.code === 'EADDRINUSE') {
10
+ resolve(false);
11
+ }
12
+ else {
13
+ resolve(false);
14
+ }
15
+ });
16
+ server.once('listening', () => {
17
+ server.close();
18
+ resolve(true);
19
+ });
20
+ server.listen(port, '127.0.0.1');
21
+ });
22
+ }
23
+ /**
24
+ * Find an available port, starting from the preferred port
25
+ */
26
+ export async function findAvailablePort(preferredPort, maxAttempts = 10) {
27
+ // First try the preferred port
28
+ if (await isPortAvailable(preferredPort)) {
29
+ return preferredPort;
30
+ }
31
+ // Try random ports
32
+ for (let i = 0; i < maxAttempts; i++) {
33
+ const randomPort = Math.floor(Math.random() * (65535 - 1024) + 1024);
34
+ if (await isPortAvailable(randomPort)) {
35
+ return randomPort;
36
+ }
37
+ }
38
+ throw new Error(`Could not find an available port after ${maxAttempts} attempts`);
39
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Shared query execution logic for both universal and resource-specific query commands
3
+ */
4
+ export interface QueryOptions {
5
+ targetType: string;
6
+ targetName: string;
7
+ message: string;
8
+ verbose?: boolean;
9
+ }
10
+ /**
11
+ * Execute a query against any ARK target (model, agent, team)
12
+ * This is the shared implementation used by all query commands
13
+ */
14
+ export declare function executeQuery(options: QueryOptions): Promise<void>;
15
+ /**
16
+ * Parse a target string like "model/default" or "agent/weather"
17
+ * Returns { targetType, targetName } or null if invalid
18
+ */
19
+ export declare function parseTarget(target: string): {
20
+ targetType: string;
21
+ targetName: string;
22
+ } | null;
@@ -0,0 +1,142 @@
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', [
49
+ 'get',
50
+ 'query',
51
+ queryName,
52
+ '-o',
53
+ 'json',
54
+ ], { stdio: 'pipe' });
55
+ const query = JSON.parse(stdout);
56
+ const phase = query.status?.phase;
57
+ // Update spinner with current phase
58
+ if (phase) {
59
+ spinner.text = `Query status: ${phase}`;
60
+ }
61
+ // Check if query is complete based on phase
62
+ if (phase === 'done') {
63
+ queryComplete = true;
64
+ spinner.succeed('Query completed');
65
+ // Extract and display the response from responses array
66
+ if (query.status?.responses && query.status.responses.length > 0) {
67
+ const response = query.status.responses[0];
68
+ console.log('\n' + (response.content || response));
69
+ }
70
+ else {
71
+ output.warning('No response received');
72
+ }
73
+ }
74
+ else if (phase === 'error') {
75
+ queryComplete = true;
76
+ spinner.fail('Query failed');
77
+ // Try to get error message from conditions or status
78
+ const errorCondition = query.status?.conditions?.find((c) => {
79
+ const condition = c;
80
+ return condition.type === 'Complete' && condition.status === 'False';
81
+ });
82
+ if (errorCondition?.message) {
83
+ output.error(errorCondition.message);
84
+ }
85
+ else if (query.status?.error) {
86
+ output.error(query.status.error);
87
+ }
88
+ else {
89
+ output.error('Query failed with unknown error');
90
+ }
91
+ }
92
+ else if (phase === 'canceled') {
93
+ queryComplete = true;
94
+ spinner.warn('Query canceled');
95
+ // Try to get cancellation reason if available
96
+ if (query.status?.message) {
97
+ output.warning(query.status.message);
98
+ }
99
+ }
100
+ }
101
+ catch {
102
+ // Query might not exist yet, continue waiting
103
+ spinner.text = 'Query status: waiting for query to be created';
104
+ }
105
+ if (!queryComplete) {
106
+ await new Promise(resolve => setTimeout(resolve, 1000)); // Wait 1 second
107
+ }
108
+ }
109
+ if (!queryComplete) {
110
+ spinner.fail('Query timed out');
111
+ output.error('Query did not complete within 5 minutes');
112
+ }
113
+ }
114
+ catch (error) {
115
+ spinner.fail('Query failed');
116
+ output.error(error instanceof Error ? error.message : 'Unknown error');
117
+ process.exit(1);
118
+ }
119
+ finally {
120
+ // Clean up the query resource
121
+ try {
122
+ await execa('kubectl', ['delete', 'query', queryName], { stdio: 'pipe' });
123
+ }
124
+ catch {
125
+ // Ignore cleanup errors
126
+ }
127
+ }
128
+ }
129
+ /**
130
+ * Parse a target string like "model/default" or "agent/weather"
131
+ * Returns { targetType, targetName } or null if invalid
132
+ */
133
+ export function parseTarget(target) {
134
+ const parts = target.split('/');
135
+ if (parts.length !== 2) {
136
+ return null;
137
+ }
138
+ return {
139
+ targetType: parts[0],
140
+ targetName: parts[1],
141
+ };
142
+ }
@@ -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 {};