@agents-at-scale/ark 0.1.31

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 (76) hide show
  1. package/README.md +95 -0
  2. package/dist/commands/cluster/get-ip.d.ts +2 -0
  3. package/dist/commands/cluster/get-ip.js +32 -0
  4. package/dist/commands/cluster/get-type.d.ts +2 -0
  5. package/dist/commands/cluster/get-type.js +26 -0
  6. package/dist/commands/cluster/index.d.ts +2 -0
  7. package/dist/commands/cluster/index.js +10 -0
  8. package/dist/commands/completion.d.ts +2 -0
  9. package/dist/commands/completion.js +108 -0
  10. package/dist/commands/config.d.ts +5 -0
  11. package/dist/commands/config.js +327 -0
  12. package/dist/commands/generate/config.d.ts +145 -0
  13. package/dist/commands/generate/config.js +253 -0
  14. package/dist/commands/generate/generators/agent.d.ts +2 -0
  15. package/dist/commands/generate/generators/agent.js +156 -0
  16. package/dist/commands/generate/generators/index.d.ts +6 -0
  17. package/dist/commands/generate/generators/index.js +6 -0
  18. package/dist/commands/generate/generators/marketplace.d.ts +2 -0
  19. package/dist/commands/generate/generators/marketplace.js +304 -0
  20. package/dist/commands/generate/generators/mcpserver.d.ts +25 -0
  21. package/dist/commands/generate/generators/mcpserver.js +350 -0
  22. package/dist/commands/generate/generators/project.d.ts +2 -0
  23. package/dist/commands/generate/generators/project.js +784 -0
  24. package/dist/commands/generate/generators/query.d.ts +2 -0
  25. package/dist/commands/generate/generators/query.js +213 -0
  26. package/dist/commands/generate/generators/team.d.ts +2 -0
  27. package/dist/commands/generate/generators/team.js +407 -0
  28. package/dist/commands/generate/index.d.ts +24 -0
  29. package/dist/commands/generate/index.js +357 -0
  30. package/dist/commands/generate/templateDiscovery.d.ts +30 -0
  31. package/dist/commands/generate/templateDiscovery.js +94 -0
  32. package/dist/commands/generate/templateEngine.d.ts +78 -0
  33. package/dist/commands/generate/templateEngine.js +368 -0
  34. package/dist/commands/generate/utils/nameUtils.d.ts +35 -0
  35. package/dist/commands/generate/utils/nameUtils.js +110 -0
  36. package/dist/commands/generate/utils/projectUtils.d.ts +28 -0
  37. package/dist/commands/generate/utils/projectUtils.js +133 -0
  38. package/dist/components/DashboardCLI.d.ts +3 -0
  39. package/dist/components/DashboardCLI.js +149 -0
  40. package/dist/components/GeneratorUI.d.ts +3 -0
  41. package/dist/components/GeneratorUI.js +167 -0
  42. package/dist/components/statusChecker.d.ts +48 -0
  43. package/dist/components/statusChecker.js +251 -0
  44. package/dist/config.d.ts +42 -0
  45. package/dist/config.js +243 -0
  46. package/dist/index.d.ts +2 -0
  47. package/dist/index.js +67 -0
  48. package/dist/lib/arkClient.d.ts +32 -0
  49. package/dist/lib/arkClient.js +43 -0
  50. package/dist/lib/cluster.d.ts +8 -0
  51. package/dist/lib/cluster.js +134 -0
  52. package/dist/lib/config.d.ts +82 -0
  53. package/dist/lib/config.js +223 -0
  54. package/dist/lib/consts.d.ts +10 -0
  55. package/dist/lib/consts.js +15 -0
  56. package/dist/lib/errors.d.ts +56 -0
  57. package/dist/lib/errors.js +208 -0
  58. package/dist/lib/exec.d.ts +5 -0
  59. package/dist/lib/exec.js +20 -0
  60. package/dist/lib/gatewayManager.d.ts +24 -0
  61. package/dist/lib/gatewayManager.js +85 -0
  62. package/dist/lib/kubernetes.d.ts +28 -0
  63. package/dist/lib/kubernetes.js +122 -0
  64. package/dist/lib/progress.d.ts +128 -0
  65. package/dist/lib/progress.js +273 -0
  66. package/dist/lib/security.d.ts +37 -0
  67. package/dist/lib/security.js +295 -0
  68. package/dist/lib/types.d.ts +37 -0
  69. package/dist/lib/types.js +1 -0
  70. package/dist/lib/wrappers/git.d.ts +2 -0
  71. package/dist/lib/wrappers/git.js +43 -0
  72. package/dist/ui/MainMenu.d.ts +3 -0
  73. package/dist/ui/MainMenu.js +116 -0
  74. package/dist/ui/statusFormatter.d.ts +9 -0
  75. package/dist/ui/statusFormatter.js +47 -0
  76. package/package.json +62 -0
@@ -0,0 +1,295 @@
1
+ /**
2
+ * Security utilities for ARK CLI
3
+ */
4
+ import path from 'path';
5
+ import fs from 'fs';
6
+ import { ValidationError } from './errors.js';
7
+ export class SecurityUtils {
8
+ /**
9
+ * Validate that a path is safe and doesn't contain directory traversal attempts
10
+ */
11
+ static validatePath(filePath, context = 'path') {
12
+ if (!filePath || typeof filePath !== 'string') {
13
+ throw new ValidationError(`Invalid ${context}: path must be a non-empty string`, 'path', ['Provide a valid file path']);
14
+ }
15
+ // Normalize the path to resolve any relative components
16
+ const normalizedPath = path.normalize(filePath);
17
+ // Check for directory traversal attempts
18
+ if (normalizedPath.includes('..') || normalizedPath.includes('~')) {
19
+ throw new ValidationError(`Unsafe ${context}: contains directory traversal sequences`, 'path', [
20
+ 'Use absolute paths or simple relative paths',
21
+ 'Remove parent directory references (..)',
22
+ 'Remove home directory references (~)',
23
+ ]);
24
+ }
25
+ // Check for absolute paths that go outside expected directories
26
+ if (path.isAbsolute(normalizedPath)) {
27
+ const dangerous = ['/etc', '/var', '/usr', '/bin', '/sbin', '/root'];
28
+ if (dangerous.some((dangerousPath) => normalizedPath.startsWith(dangerousPath))) {
29
+ throw new ValidationError(`Unsafe ${context}: attempts to access system directory`, 'path', [
30
+ 'Use project-relative paths',
31
+ 'Avoid system directories',
32
+ 'Use a safe working directory',
33
+ ]);
34
+ }
35
+ }
36
+ // Check for null bytes and other dangerous characters
37
+ if (normalizedPath.includes('\0') || normalizedPath.includes('\u0000')) {
38
+ throw new ValidationError(`Invalid ${context}: contains null bytes`, 'path', ['Remove null bytes from the path']);
39
+ }
40
+ }
41
+ /**
42
+ * Ensure a directory path is safe to create/write to
43
+ */
44
+ static validateOutputPath(outputPath, baseDir) {
45
+ this.validatePath(outputPath, 'output path');
46
+ this.validatePath(baseDir, 'base directory');
47
+ const resolvedOutput = path.resolve(outputPath);
48
+ const resolvedBase = path.resolve(baseDir);
49
+ // Ensure the output path is within the base directory
50
+ if (!resolvedOutput.startsWith(resolvedBase)) {
51
+ throw new ValidationError('Output path is outside the allowed directory', 'outputPath', [
52
+ `Ensure output path is within: ${resolvedBase}`,
53
+ 'Use relative paths within the project',
54
+ 'Check for directory traversal in the path',
55
+ ]);
56
+ }
57
+ }
58
+ /**
59
+ * Sanitize file names to prevent issues
60
+ */
61
+ static sanitizeFileName(fileName) {
62
+ if (!fileName || typeof fileName !== 'string') {
63
+ throw new ValidationError('Invalid file name: must be a non-empty string', 'fileName');
64
+ }
65
+ // Standard dotfiles that should be preserved
66
+ const allowedDotfiles = [
67
+ '.gitignore',
68
+ '.gitattributes',
69
+ '.github',
70
+ '.gitmodules',
71
+ '.helmignore',
72
+ '.dockerignore',
73
+ '.eslintrc',
74
+ '.prettierrc',
75
+ '.editorconfig',
76
+ '.nvmrc',
77
+ '.yamllint.yml',
78
+ '.yamllint.yaml',
79
+ '.env',
80
+ '.env.example',
81
+ '.env.local',
82
+ '.env.production',
83
+ '.vscode',
84
+ '.idea',
85
+ '.vimrc',
86
+ '.bashrc',
87
+ '.zshrc',
88
+ '.keep',
89
+ ];
90
+ // Check if this is an allowed dotfile
91
+ const isAllowedDotfile = allowedDotfiles.some((allowed) => fileName === allowed || fileName.startsWith(allowed + '.'));
92
+ // Remove dangerous characters
93
+ let sanitized = fileName
94
+ .replace(/[<>:"/\\|?*]/g, '') // Windows forbidden chars
95
+ .replace(/\s+/g, '-') // Replace spaces with hyphens
96
+ .replace(/-{2,}/g, '-') // Replace 2+ consecutive hyphens with single hyphen (ReDoS-safe)
97
+ .replace(/^-/, '') // Remove single leading hyphen (ReDoS-safe)
98
+ .replace(/-$/, ''); // Remove single trailing hyphen (ReDoS-safe)
99
+ // Remove leading dots only if not an allowed dotfile
100
+ if (!isAllowedDotfile) {
101
+ sanitized = sanitized.replace(/^\\./, ''); // Remove single leading dot (ReDoS-safe)
102
+ }
103
+ // Ensure it's not empty after sanitization
104
+ if (!sanitized) {
105
+ throw new ValidationError('File name becomes empty after sanitization', 'fileName', ['Use alphanumeric characters and hyphens only']);
106
+ }
107
+ // Ensure it's not too long
108
+ if (sanitized.length > 255) {
109
+ sanitized = sanitized.substring(0, 255);
110
+ }
111
+ // Check for reserved names (Windows)
112
+ const reservedNames = [
113
+ 'CON',
114
+ 'PRN',
115
+ 'AUX',
116
+ 'NUL',
117
+ 'COM1',
118
+ 'COM2',
119
+ 'COM3',
120
+ 'COM4',
121
+ 'COM5',
122
+ 'COM6',
123
+ 'COM7',
124
+ 'COM8',
125
+ 'COM9',
126
+ 'LPT1',
127
+ 'LPT2',
128
+ 'LPT3',
129
+ 'LPT4',
130
+ 'LPT5',
131
+ 'LPT6',
132
+ 'LPT7',
133
+ 'LPT8',
134
+ 'LPT9',
135
+ ];
136
+ if (reservedNames.includes(sanitized.toUpperCase())) {
137
+ sanitized = `_${sanitized}`;
138
+ }
139
+ return sanitized;
140
+ }
141
+ /**
142
+ * Validate template content to prevent code injection
143
+ */
144
+ static validateTemplateContent(content, templatePath) {
145
+ if (!content || typeof content !== 'string') {
146
+ return; // Empty content is fine
147
+ }
148
+ // File types that legitimately need shell/script syntax and should skip validation
149
+ const exemptFileTypes = [
150
+ '.sh',
151
+ '.bash',
152
+ '.zsh',
153
+ '.fish', // Shell scripts
154
+ 'Makefile',
155
+ 'makefile',
156
+ '.mk', // Makefiles
157
+ '.ps1',
158
+ '.cmd',
159
+ '.bat', // Windows scripts
160
+ '.py',
161
+ '.js',
162
+ '.ts',
163
+ '.rb',
164
+ '.pl', // Programming languages
165
+ '.dockerfile',
166
+ 'Dockerfile', // Docker files
167
+ '.yml',
168
+ '.yaml', // YAML files (may contain scripts in CI/CD)
169
+ '.md',
170
+ '.markdown',
171
+ '.rst',
172
+ '.txt', // Documentation files (may contain code examples)
173
+ ];
174
+ const fileName = path.basename(templatePath).toLowerCase();
175
+ const fileExt = path.extname(templatePath).toLowerCase();
176
+ // Skip validation for exempt file types
177
+ if (exemptFileTypes.some((exempt) => fileName === exempt.toLowerCase() ||
178
+ fileName.includes(exempt.toLowerCase()) ||
179
+ fileExt === exempt.toLowerCase())) {
180
+ return;
181
+ }
182
+ // Check for potentially dangerous patterns
183
+ const dangerousPatterns = [
184
+ /\$\{[\w.]{0,100}?\([a-zA-Z0-9_.,\s]{0,100}?\)/, // Function calls in template variables (ReDoS-safe)
185
+ /\$\([a-zA-Z0-9\s._-]{0,100}?\)/, // Command substitution (ReDoS-safe)
186
+ /`[a-zA-Z0-9\s._${}()-]{0,500}?`/, // Backticks (ReDoS-safe)
187
+ /eval\s*\(/, // Eval statements
188
+ /exec\s*\(/, // Exec statements
189
+ /require\s*\(/, // Require statements
190
+ /\bimport\s/, // Import statements (ReDoS-safe - simple detection)
191
+ ];
192
+ for (const pattern of dangerousPatterns) {
193
+ if (pattern.test(content)) {
194
+ throw new ValidationError(`Template contains potentially dangerous code: ${templatePath}`, 'templateContent', [
195
+ 'Remove code execution patterns from templates',
196
+ 'Use only variable substitution',
197
+ 'Check template for malicious content',
198
+ ]);
199
+ }
200
+ }
201
+ }
202
+ /**
203
+ * Safely create directories with proper permissions
204
+ */
205
+ static async createDirectorySafe(dirPath, baseDir) {
206
+ this.validateOutputPath(dirPath, baseDir);
207
+ try {
208
+ await fs.promises.mkdir(dirPath, {
209
+ recursive: true,
210
+ mode: 0o755, // Read/write/execute for owner, read/execute for group and others
211
+ });
212
+ }
213
+ catch (error) {
214
+ throw new ValidationError(`Failed to create directory: ${dirPath}: ${error instanceof Error ? error.message : String(error)}`, 'directory', [
215
+ 'Check file permissions',
216
+ 'Ensure parent directory exists',
217
+ 'Verify disk space availability',
218
+ ]);
219
+ }
220
+ }
221
+ /**
222
+ * Safely write files with proper permissions
223
+ */
224
+ static async writeFileSafe(filePath, content, baseDir) {
225
+ this.validateOutputPath(filePath, baseDir);
226
+ this.validateTemplateContent(content, filePath);
227
+ const fileName = path.basename(filePath);
228
+ const sanitizedFileName = this.sanitizeFileName(fileName);
229
+ if (sanitizedFileName !== fileName) {
230
+ throw new ValidationError(`File name requires sanitization: "${fileName}" → "${sanitizedFileName}"`, 'fileName', [`Use the sanitized name: "${sanitizedFileName}"`]);
231
+ }
232
+ try {
233
+ await fs.promises.writeFile(filePath, content, {
234
+ mode: 0o644, // Read/write for owner, read for group and others
235
+ flag: 'w', // Overwrite if exists
236
+ });
237
+ }
238
+ catch (error) {
239
+ throw new ValidationError(`Failed to write file: ${filePath}: ${error instanceof Error ? error.message : String(error)}`, 'file', [
240
+ 'Check file permissions',
241
+ 'Ensure directory exists',
242
+ 'Verify disk space availability',
243
+ ]);
244
+ }
245
+ }
246
+ /**
247
+ * Validate environment variables for safety
248
+ */
249
+ static sanitizeEnvironmentValue(value, varName) {
250
+ if (!value || typeof value !== 'string') {
251
+ return '';
252
+ }
253
+ // Remove potentially dangerous characters
254
+ const sanitized = value
255
+ .replace(/[`$\\]/g, '') // Command injection chars
256
+ .trim();
257
+ // Warn if significant changes were made
258
+ if (sanitized !== value && sanitized.length < value.length * 0.8) {
259
+ console.warn(`Warning: Environment variable ${varName} was heavily sanitized`);
260
+ }
261
+ return sanitized;
262
+ }
263
+ /**
264
+ * Validate API keys and secrets
265
+ */
266
+ static validateSecret(secret, secretType) {
267
+ if (!secret || typeof secret !== 'string') {
268
+ throw new ValidationError(`Invalid ${secretType}: must be a non-empty string`, 'secret');
269
+ }
270
+ // Check for common patterns that suggest it's not a real secret
271
+ const testPatterns = [
272
+ /^(test|dummy|fake|placeholder|example)/i,
273
+ /^(xxx|000|123)/,
274
+ /^your[_-]?key/i,
275
+ /^replace[_-]?me/i,
276
+ ];
277
+ for (const pattern of testPatterns) {
278
+ if (pattern.test(secret)) {
279
+ throw new ValidationError(`${secretType} appears to be a placeholder value`, 'secret', [
280
+ `Replace with a real ${secretType}`,
281
+ 'Check your configuration',
282
+ 'Ensure secrets are properly set',
283
+ ]);
284
+ }
285
+ }
286
+ // Basic length validation (most API keys are at least 16 chars)
287
+ if (secret.length < 16) {
288
+ throw new ValidationError(`${secretType} appears too short (${secret.length} characters)`, 'secret', [
289
+ 'Ensure you have the complete key',
290
+ 'Check for truncation',
291
+ 'Verify with your provider',
292
+ ]);
293
+ }
294
+ }
295
+ }
@@ -0,0 +1,37 @@
1
+ export interface ArkConfig {
2
+ defaultModel?: string;
3
+ defaultAgent?: string;
4
+ defaultNamespace?: string;
5
+ apiBaseUrl?: string;
6
+ kubeconfig?: string;
7
+ currentContext?: string;
8
+ kubeNamespace?: string;
9
+ }
10
+ export interface KubernetesConfig {
11
+ kubeconfig: string;
12
+ currentContext?: string;
13
+ namespace?: string;
14
+ inCluster: boolean;
15
+ }
16
+ export interface ServiceStatus {
17
+ name: string;
18
+ status: 'healthy' | 'unhealthy' | 'not installed';
19
+ url?: string;
20
+ version?: string;
21
+ details?: string;
22
+ }
23
+ export interface DependencyStatus {
24
+ name: string;
25
+ installed: boolean;
26
+ version?: string;
27
+ details?: string;
28
+ }
29
+ export interface StatusData {
30
+ services: ServiceStatus[];
31
+ dependencies: DependencyStatus[];
32
+ }
33
+ export interface CommandVersionConfig {
34
+ command: string;
35
+ versionArgs: string;
36
+ versionExtract: (_output: string) => string;
37
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export declare function ensureInArkRepo(expectedRepoName: string, expectedRemoteSubstring?: string): Promise<void>;
2
+ export declare function getRepoProjectRoot(): Promise<string>;
@@ -0,0 +1,43 @@
1
+ import * as path from 'path';
2
+ import chalk from 'chalk';
3
+ import { simpleGit } from 'simple-git';
4
+ import { ARK_REPO_ERROR_MESSAGE } from '../consts.js';
5
+ // Initialize simple-git instance
6
+ const git = simpleGit();
7
+ export async function ensureInArkRepo(expectedRepoName, expectedRemoteSubstring) {
8
+ try {
9
+ // Get repository root
10
+ const gitRoot = await git.revparse(['--show-toplevel']);
11
+ if (path.basename(gitRoot) !== expectedRepoName) {
12
+ console.error(chalk.red(ARK_REPO_ERROR_MESSAGE));
13
+ process.exit(1);
14
+ }
15
+ if (expectedRemoteSubstring) {
16
+ try {
17
+ // Get remote URL
18
+ const remoteUrl = await git.remote(['get-url', 'origin']);
19
+ if (!remoteUrl || !remoteUrl.includes(expectedRemoteSubstring)) {
20
+ console.error(chalk.red(ARK_REPO_ERROR_MESSAGE));
21
+ process.exit(1);
22
+ }
23
+ }
24
+ catch (_error) {
25
+ console.error(chalk.red(ARK_REPO_ERROR_MESSAGE));
26
+ process.exit(1);
27
+ }
28
+ }
29
+ }
30
+ catch (_error) {
31
+ console.error(chalk.red(ARK_REPO_ERROR_MESSAGE));
32
+ process.exit(1);
33
+ }
34
+ }
35
+ export async function getRepoProjectRoot() {
36
+ try {
37
+ return await git.revparse(['--show-toplevel']);
38
+ }
39
+ catch (_error) {
40
+ console.error(chalk.red('Failed to determine git repository root path'));
41
+ process.exit(1);
42
+ }
43
+ }
@@ -0,0 +1,3 @@
1
+ import * as React from 'react';
2
+ declare const MainMenu: React.FC;
3
+ export default MainMenu;
@@ -0,0 +1,116 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { Text, Box, useInput } from 'ink';
3
+ import SelectInput from 'ink-select-input';
4
+ import * as React from 'react';
5
+ import DashboardCLI from '../components/DashboardCLI.js';
6
+ import GeneratorUI from '../components/GeneratorUI.js';
7
+ import { StatusChecker } from '../components/statusChecker.js';
8
+ import { ConfigManager } from '../config.js';
9
+ import { ArkClient } from '../lib/arkClient.js';
10
+ const EXIT_TIMEOUT_MS = 1000;
11
+ const MainMenu = () => {
12
+ const [selectedChoice, setSelectedChoice] = React.useState(null);
13
+ const [statusData, setStatusData] = React.useState(null);
14
+ const [isLoading, setIsLoading] = React.useState(false);
15
+ const [error, setError] = React.useState(null);
16
+ const choices = [
17
+ { label: 'šŸ·ļø Dashboard', value: 'dashboard' },
18
+ { label: 'šŸ” Status Check', value: 'status' },
19
+ { label: 'šŸŽÆ Generate', value: 'generate' },
20
+ { label: 'šŸ‘‹ Exit', value: 'exit' },
21
+ ];
22
+ React.useEffect(() => {
23
+ if (selectedChoice === 'exit') {
24
+ const timer = setTimeout(() => {
25
+ process.exit(0);
26
+ }, EXIT_TIMEOUT_MS);
27
+ return () => clearTimeout(timer);
28
+ }
29
+ }, [selectedChoice]);
30
+ React.useEffect(() => {
31
+ if (selectedChoice === 'status' && !statusData && !isLoading) {
32
+ checkStatus();
33
+ }
34
+ }, [selectedChoice, statusData, isLoading]);
35
+ const checkStatus = async () => {
36
+ setIsLoading(true);
37
+ setError(null);
38
+ try {
39
+ const configManager = new ConfigManager();
40
+ const apiBaseUrl = await configManager.getApiBaseUrl();
41
+ const serviceUrls = await configManager.getServiceUrls();
42
+ const arkClient = new ArkClient(apiBaseUrl);
43
+ const statusChecker = new StatusChecker(arkClient);
44
+ const status = await statusChecker.checkAll(serviceUrls, apiBaseUrl);
45
+ setStatusData(status);
46
+ }
47
+ catch (err) {
48
+ setError(err instanceof Error ? err.message : 'Unknown error occurred');
49
+ }
50
+ finally {
51
+ setIsLoading(false);
52
+ }
53
+ };
54
+ useInput((input, key) => {
55
+ if (selectedChoice && selectedChoice !== 'exit') {
56
+ if (key.escape || input === 'q' || key.return) {
57
+ // For generate, only reset on specific key combinations to avoid conflicts
58
+ if (selectedChoice === 'generate' && !(key.escape || input === 'q')) {
59
+ return;
60
+ }
61
+ setSelectedChoice(null);
62
+ setStatusData(null);
63
+ setError(null);
64
+ }
65
+ }
66
+ });
67
+ const renderBanner = () => (_jsxs(Box, { flexDirection: "column", alignItems: "center", marginBottom: 1, children: [_jsx(Text, { color: "cyan", bold: true, children: `
68
+ ╔═══════════════════════════════════════╗
69
+ ā•‘ ā•‘
70
+ ā•‘ ā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā•— ā–ˆā–ˆā•— ā•‘
71
+ ā•‘ ā–ˆā–ˆā•”ā•ā•ā–ˆā–ˆā•—ā–ˆā–ˆā•”ā•ā•ā–ˆā–ˆā•—ā–ˆā–ˆā•‘ ā–ˆā–ˆā•”ā• ā•‘
72
+ ā•‘ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•‘ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•”ā•ā–ˆā–ˆā–ˆā–ˆā–ˆā•”ā• ā•‘
73
+ ā•‘ ā–ˆā–ˆā•”ā•ā•ā–ˆā–ˆā•‘ā–ˆā–ˆā•”ā•ā•ā–ˆā–ˆā•—ā–ˆā–ˆā•”ā•ā–ˆā–ˆā•— ā•‘
74
+ ā•‘ ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā–ˆā–ˆā•‘ ā–ˆā–ˆā•— ā•‘
75
+ ā•‘ ā•šā•ā• ā•šā•ā•ā•šā•ā• ā•šā•ā•ā•šā•ā• ā•šā•ā• ā•‘
76
+ ā•‘ ā•‘
77
+ ā•‘ Agents at Scale Platform ā•‘
78
+ ā•‘ ā•‘
79
+ ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•
80
+ ` }), _jsx(Text, { color: "green", bold: true, children: "Welcome to ARK! \uD83D\uDE80" }), _jsx(Text, { color: "gray", children: "Interactive terminal interface for ARK agents" })] }));
81
+ const renderServiceStatus = (service) => {
82
+ const statusColor = service.status === 'healthy'
83
+ ? 'green'
84
+ : service.status === 'unhealthy'
85
+ ? 'red'
86
+ : 'yellow';
87
+ const statusIcon = service.status === 'healthy'
88
+ ? 'āœ“'
89
+ : service.status === 'unhealthy'
90
+ ? 'āœ—'
91
+ : '?';
92
+ return (_jsxs(Box, { flexDirection: "column", marginLeft: 2, children: [_jsxs(Box, { children: [_jsxs(Text, { color: statusColor, children: [statusIcon, " "] }), _jsxs(Text, { bold: true, children: [service.name, ": "] }), _jsx(Text, { color: statusColor, children: service.status })] }), service.url && (_jsx(Box, { marginLeft: 2, children: _jsxs(Text, { color: "gray", children: ["URL: ", service.url] }) })), service.details && (_jsx(Box, { marginLeft: 2, children: _jsx(Text, { color: "gray", children: service.details }) }))] }, service.name));
93
+ };
94
+ const renderDependencyStatus = (dep) => {
95
+ const statusColor = dep.installed ? 'green' : 'red';
96
+ const statusIcon = dep.installed ? 'āœ“' : 'āœ—';
97
+ const statusText = dep.installed ? 'installed' : 'missing';
98
+ return (_jsxs(Box, { flexDirection: "column", marginLeft: 2, children: [_jsxs(Box, { children: [_jsxs(Text, { color: statusColor, children: [statusIcon, " "] }), _jsxs(Text, { bold: true, children: [dep.name, ": "] }), _jsx(Text, { color: statusColor, children: statusText })] }), dep.version && (_jsx(Box, { marginLeft: 2, children: _jsxs(Text, { color: "gray", children: ["Version: ", dep.version] }) })), dep.details && (_jsx(Box, { marginLeft: 2, children: _jsx(Text, { color: "gray", children: dep.details }) }))] }, dep.name));
99
+ };
100
+ const renderStatus = () => {
101
+ if (isLoading) {
102
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "yellow", children: "\uD83D\uDD0D Checking ARK system status..." }), _jsx(Text, { color: "gray", children: "Please wait while we verify services and dependencies." })] }));
103
+ }
104
+ if (error) {
105
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "red", children: "\u274C Error checking status:" }), _jsx(Text, { color: "red", children: error }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "gray", children: "Press ESC, 'q', or Enter to return to menu..." }) })] }));
106
+ }
107
+ if (!statusData) {
108
+ return null;
109
+ }
110
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "cyan", bold: true, children: "\uD83D\uDD0D ARK System Status" }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "cyan", bold: true, children: "\uD83D\uDCE1 ARK Services:" }) }), statusData.services.map(renderServiceStatus), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "cyan", bold: true, children: "\uD83D\uDEE0\uFE0F System Dependencies:" }) }), statusData.dependencies.map(renderDependencyStatus), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "gray", children: "Press ESC, 'q', or Enter to return to menu..." }) })] }));
111
+ };
112
+ return (_jsxs(_Fragment, { children: [renderBanner(), !selectedChoice && (_jsx(SelectInput, { items: choices, onSelect: (choice) => {
113
+ setSelectedChoice(choice.value);
114
+ } })), selectedChoice === 'status' && renderStatus(), selectedChoice === 'dashboard' && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "green", children: "\uD83C\uDFF7\uFE0F Dashboard feature selected" }), _jsx(DashboardCLI, {})] })), selectedChoice === 'generate' && _jsx(GeneratorUI, {}), selectedChoice === 'exit' && _jsx(Text, { color: "yellow", children: "\uD83D\uDC4B Goodbye!" })] }));
115
+ };
116
+ export default MainMenu;
@@ -0,0 +1,9 @@
1
+ import { StatusData } from '../lib/types.js';
2
+ export declare class StatusFormatter {
3
+ /**
4
+ * Print status check results to console
5
+ */
6
+ static printStatus(statusData: StatusData): void;
7
+ private static printService;
8
+ private static printDependency;
9
+ }
@@ -0,0 +1,47 @@
1
+ import chalk from 'chalk';
2
+ export class StatusFormatter {
3
+ /**
4
+ * Print status check results to console
5
+ */
6
+ static printStatus(statusData) {
7
+ console.log(chalk.cyan.bold('\nšŸ” ARK System Status Check'));
8
+ console.log(chalk.gray('Checking ARK services and dependencies...\n'));
9
+ // Print services status
10
+ console.log(chalk.cyan.bold('šŸ“” ARK Services:'));
11
+ for (const service of statusData.services) {
12
+ StatusFormatter.printService(service);
13
+ }
14
+ // Print dependencies status
15
+ console.log(chalk.cyan.bold('\nšŸ› ļø System Dependencies:'));
16
+ for (const dep of statusData.dependencies) {
17
+ StatusFormatter.printDependency(dep);
18
+ }
19
+ console.log();
20
+ }
21
+ static printService(service) {
22
+ const statusColor = service.status === 'healthy'
23
+ ? chalk.green('āœ“ healthy')
24
+ : service.status === 'unhealthy'
25
+ ? chalk.red('āœ— unhealthy')
26
+ : chalk.yellow('? not installed');
27
+ console.log(` • ${chalk.bold(service.name)}: ${statusColor}`);
28
+ if (service.url) {
29
+ console.log(` ${chalk.gray(`URL: ${service.url}`)}`);
30
+ }
31
+ if (service.details) {
32
+ console.log(` ${chalk.gray(service.details)}`);
33
+ }
34
+ }
35
+ static printDependency(dep) {
36
+ const statusColor = dep.installed
37
+ ? chalk.green('āœ“ installed')
38
+ : chalk.red('āœ— missing');
39
+ console.log(` • ${chalk.bold(dep.name)}: ${statusColor}`);
40
+ if (dep.version) {
41
+ console.log(` ${chalk.gray(`Version: ${dep.version}`)}`);
42
+ }
43
+ if (dep.details) {
44
+ console.log(` ${chalk.gray(dep.details)}`);
45
+ }
46
+ }
47
+ }
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@agents-at-scale/ark",
3
+ "version": "0.1.31",
4
+ "description": "ARK CLI - Interactive terminal interface for ARK agents",
5
+ "main": "dist/index.js",
6
+ "type": "module",
7
+ "bin": {
8
+ "ark": "dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsc && chmod +x dist/index.js",
15
+ "dev": "node --loader ts-node/esm src/index.tsx",
16
+ "start": "node dist/index.js",
17
+ "clean": "rm -rf dist",
18
+ "lint": "eslint src/ --fix && prettier --write src/",
19
+ "lint:check": "eslint src/ && prettier --check src/",
20
+ "postinstall": "echo \"ARK CLI installed! Run 'ark' to try it out.\""
21
+ },
22
+ "keywords": [
23
+ "ark",
24
+ "cli",
25
+ "terminal",
26
+ "ai",
27
+ "agents"
28
+ ],
29
+ "author": "",
30
+ "dependencies": {
31
+ "@kubernetes/client-node": "^1.3.0",
32
+ "@types/react": "^19.1.8",
33
+ "axios": "^1.7.7",
34
+ "chalk": "^4.1.2",
35
+ "commander": "^12.1.0",
36
+ "debug": "^4.4.1",
37
+ "execa": "^9.6.0",
38
+ "ink": "^6.0.1",
39
+ "ink-select-input": "^6.2.0",
40
+ "ink-text-input": "^6.0.0",
41
+ "inquirer": "^12.1.0",
42
+ "open": "^10.2.0",
43
+ "react": "^19.1.0",
44
+ "simple-git": "^3.28.0",
45
+ "yaml": "^2.6.1"
46
+ },
47
+ "devDependencies": {
48
+ "@eslint/js": "^9.17.0",
49
+ "@types/debug": "^4.1.12",
50
+ "@types/inquirer": "^9.0.7",
51
+ "@types/node": "^22.10.2",
52
+ "@typescript-eslint/eslint-plugin": "^8.20.0",
53
+ "@typescript-eslint/parser": "^8.20.0",
54
+ "eslint": "^9.17.0",
55
+ "prettier": "^3.6.2",
56
+ "ts-node": "^10.9.2",
57
+ "typescript": "^5.7.2"
58
+ },
59
+ "engines": {
60
+ "node": ">=18.0.0"
61
+ }
62
+ }