@agents-at-scale/ark 0.1.35-rc1 → 0.1.35

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 (207) hide show
  1. package/dist/commands/cluster/index.d.ts +1 -2
  2. package/dist/commands/cluster/index.js +5 -3
  3. package/dist/commands/completion.js +2 -159
  4. package/dist/commands/config.d.ts +3 -0
  5. package/dist/commands/config.js +321 -38
  6. package/dist/commands/generate/config.js +24 -5
  7. package/dist/commands/generate/generators/agent.js +2 -2
  8. package/dist/commands/generate/generators/mcpserver.d.ts +1 -2
  9. package/dist/commands/generate/generators/mcpserver.js +5 -26
  10. package/dist/commands/generate/generators/project.js +41 -22
  11. package/dist/commands/generate/generators/team.js +2 -2
  12. package/dist/commands/generate/index.d.ts +1 -2
  13. package/dist/commands/generate/index.js +1 -1
  14. package/dist/components/statusChecker.d.ts +23 -13
  15. package/dist/components/statusChecker.js +129 -275
  16. package/dist/config.d.ts +22 -3
  17. package/dist/config.js +161 -10
  18. package/dist/index.d.ts +1 -1
  19. package/dist/index.js +42 -40
  20. package/dist/lib/cluster.d.ts +1 -2
  21. package/dist/lib/cluster.js +16 -37
  22. package/dist/lib/config.d.ts +80 -26
  23. package/dist/lib/config.js +205 -70
  24. package/dist/lib/consts.d.ts +1 -0
  25. package/dist/lib/consts.js +2 -0
  26. package/dist/lib/errors.js +1 -1
  27. package/dist/lib/exec.d.ts +4 -0
  28. package/dist/lib/exec.js +11 -0
  29. package/dist/lib/types.d.ts +3 -10
  30. package/dist/ui/MainMenu.d.ts +1 -5
  31. package/dist/ui/MainMenu.js +91 -222
  32. package/dist/ui/statusFormatter.d.ts +7 -22
  33. package/dist/ui/statusFormatter.js +39 -39
  34. package/package.json +5 -17
  35. package/dist/arkServices.d.ts +0 -42
  36. package/dist/arkServices.js +0 -138
  37. package/dist/arkServices.spec.d.ts +0 -1
  38. package/dist/arkServices.spec.js +0 -24
  39. package/dist/charts/charts.d.ts +0 -5
  40. package/dist/charts/charts.js +0 -6
  41. package/dist/charts/dependencies.d.ts +0 -6
  42. package/dist/charts/dependencies.js +0 -50
  43. package/dist/charts/types.d.ts +0 -40
  44. package/dist/charts/types.js +0 -1
  45. package/dist/commands/agents/index.d.ts +0 -3
  46. package/dist/commands/agents/index.js +0 -51
  47. package/dist/commands/agents/index.spec.d.ts +0 -1
  48. package/dist/commands/agents/index.spec.js +0 -67
  49. package/dist/commands/agents/selector.d.ts +0 -8
  50. package/dist/commands/agents/selector.js +0 -53
  51. package/dist/commands/agents.d.ts +0 -2
  52. package/dist/commands/agents.js +0 -53
  53. package/dist/commands/chat/index.d.ts +0 -3
  54. package/dist/commands/chat/index.js +0 -29
  55. package/dist/commands/chat.d.ts +0 -2
  56. package/dist/commands/chat.js +0 -45
  57. package/dist/commands/cluster/get.d.ts +0 -2
  58. package/dist/commands/cluster/get.js +0 -39
  59. package/dist/commands/cluster/get.spec.d.ts +0 -1
  60. package/dist/commands/cluster/get.spec.js +0 -92
  61. package/dist/commands/cluster/index.spec.d.ts +0 -1
  62. package/dist/commands/cluster/index.spec.js +0 -24
  63. package/dist/commands/completion/index.d.ts +0 -3
  64. package/dist/commands/completion/index.js +0 -268
  65. package/dist/commands/completion/index.spec.d.ts +0 -1
  66. package/dist/commands/completion/index.spec.js +0 -34
  67. package/dist/commands/config/index.d.ts +0 -3
  68. package/dist/commands/config/index.js +0 -42
  69. package/dist/commands/config/index.spec.d.ts +0 -1
  70. package/dist/commands/config/index.spec.js +0 -78
  71. package/dist/commands/dashboard/index.d.ts +0 -4
  72. package/dist/commands/dashboard/index.js +0 -39
  73. package/dist/commands/dashboard.d.ts +0 -3
  74. package/dist/commands/dashboard.js +0 -39
  75. package/dist/commands/dev/index.d.ts +0 -3
  76. package/dist/commands/dev/index.js +0 -9
  77. package/dist/commands/dev/tool/check.d.ts +0 -2
  78. package/dist/commands/dev/tool/check.js +0 -142
  79. package/dist/commands/dev/tool/clean.d.ts +0 -2
  80. package/dist/commands/dev/tool/clean.js +0 -153
  81. package/dist/commands/dev/tool/generate.d.ts +0 -2
  82. package/dist/commands/dev/tool/generate.js +0 -28
  83. package/dist/commands/dev/tool/index.d.ts +0 -2
  84. package/dist/commands/dev/tool/index.js +0 -14
  85. package/dist/commands/dev/tool/init.d.ts +0 -2
  86. package/dist/commands/dev/tool/init.js +0 -320
  87. package/dist/commands/dev/tool/shared.d.ts +0 -5
  88. package/dist/commands/dev/tool/shared.js +0 -256
  89. package/dist/commands/dev/tool/status.d.ts +0 -2
  90. package/dist/commands/dev/tool/status.js +0 -136
  91. package/dist/commands/dev/tool-generate.spec.d.ts +0 -1
  92. package/dist/commands/dev/tool-generate.spec.js +0 -163
  93. package/dist/commands/dev/tool.d.ts +0 -2
  94. package/dist/commands/dev/tool.js +0 -559
  95. package/dist/commands/dev/tool.spec.d.ts +0 -1
  96. package/dist/commands/dev/tool.spec.js +0 -48
  97. package/dist/commands/install/index.d.ts +0 -8
  98. package/dist/commands/install/index.js +0 -302
  99. package/dist/commands/install/index.spec.d.ts +0 -1
  100. package/dist/commands/install/index.spec.js +0 -135
  101. package/dist/commands/install.d.ts +0 -3
  102. package/dist/commands/install.js +0 -147
  103. package/dist/commands/models/create.d.ts +0 -1
  104. package/dist/commands/models/create.js +0 -213
  105. package/dist/commands/models/create.spec.d.ts +0 -1
  106. package/dist/commands/models/create.spec.js +0 -125
  107. package/dist/commands/models/index.d.ts +0 -3
  108. package/dist/commands/models/index.js +0 -60
  109. package/dist/commands/models/index.spec.d.ts +0 -1
  110. package/dist/commands/models/index.spec.js +0 -76
  111. package/dist/commands/models/selector.d.ts +0 -8
  112. package/dist/commands/models/selector.js +0 -53
  113. package/dist/commands/routes/index.d.ts +0 -3
  114. package/dist/commands/routes/index.js +0 -93
  115. package/dist/commands/routes.d.ts +0 -2
  116. package/dist/commands/routes.js +0 -101
  117. package/dist/commands/status/index.d.ts +0 -4
  118. package/dist/commands/status/index.js +0 -232
  119. package/dist/commands/status.d.ts +0 -3
  120. package/dist/commands/status.js +0 -33
  121. package/dist/commands/targets/index.d.ts +0 -3
  122. package/dist/commands/targets/index.js +0 -65
  123. package/dist/commands/targets/index.spec.d.ts +0 -1
  124. package/dist/commands/targets/index.spec.js +0 -105
  125. package/dist/commands/targets.d.ts +0 -2
  126. package/dist/commands/targets.js +0 -65
  127. package/dist/commands/teams/index.d.ts +0 -3
  128. package/dist/commands/teams/index.js +0 -49
  129. package/dist/commands/teams/index.spec.d.ts +0 -1
  130. package/dist/commands/teams/index.spec.js +0 -70
  131. package/dist/commands/teams/selector.d.ts +0 -8
  132. package/dist/commands/teams/selector.js +0 -55
  133. package/dist/commands/tools/index.d.ts +0 -3
  134. package/dist/commands/tools/index.js +0 -49
  135. package/dist/commands/tools/index.spec.d.ts +0 -1
  136. package/dist/commands/tools/index.spec.js +0 -70
  137. package/dist/commands/tools/selector.d.ts +0 -8
  138. package/dist/commands/tools/selector.js +0 -53
  139. package/dist/commands/uninstall/index.d.ts +0 -3
  140. package/dist/commands/uninstall/index.js +0 -107
  141. package/dist/commands/uninstall/index.spec.d.ts +0 -1
  142. package/dist/commands/uninstall/index.spec.js +0 -117
  143. package/dist/commands/uninstall.d.ts +0 -2
  144. package/dist/commands/uninstall.js +0 -83
  145. package/dist/components/ChatUI.d.ts +0 -16
  146. package/dist/components/ChatUI.js +0 -801
  147. package/dist/components/StatusView.d.ts +0 -10
  148. package/dist/components/StatusView.js +0 -39
  149. package/dist/lib/arkApiClient.d.ts +0 -53
  150. package/dist/lib/arkApiClient.js +0 -102
  151. package/dist/lib/arkApiProxy.d.ts +0 -9
  152. package/dist/lib/arkApiProxy.js +0 -22
  153. package/dist/lib/arkServiceProxy.d.ts +0 -14
  154. package/dist/lib/arkServiceProxy.js +0 -95
  155. package/dist/lib/arkStatus.d.ts +0 -10
  156. package/dist/lib/arkStatus.js +0 -79
  157. package/dist/lib/arkStatus.spec.d.ts +0 -1
  158. package/dist/lib/arkStatus.spec.js +0 -49
  159. package/dist/lib/chatClient.d.ts +0 -33
  160. package/dist/lib/chatClient.js +0 -99
  161. package/dist/lib/cluster.spec.d.ts +0 -1
  162. package/dist/lib/cluster.spec.js +0 -338
  163. package/dist/lib/commandUtils.d.ts +0 -4
  164. package/dist/lib/commandUtils.js +0 -18
  165. package/dist/lib/commandUtils.test.d.ts +0 -1
  166. package/dist/lib/commandUtils.test.js +0 -44
  167. package/dist/lib/commands.d.ts +0 -16
  168. package/dist/lib/commands.js +0 -29
  169. package/dist/lib/commands.spec.d.ts +0 -1
  170. package/dist/lib/commands.spec.js +0 -146
  171. package/dist/lib/config.spec.d.ts +0 -1
  172. package/dist/lib/config.spec.js +0 -99
  173. package/dist/lib/config.test.d.ts +0 -1
  174. package/dist/lib/config.test.js +0 -93
  175. package/dist/lib/consts.spec.d.ts +0 -1
  176. package/dist/lib/consts.spec.js +0 -15
  177. package/dist/lib/dev/tools/analyzer.d.ts +0 -30
  178. package/dist/lib/dev/tools/analyzer.js +0 -190
  179. package/dist/lib/dev/tools/discover_tools.py +0 -392
  180. package/dist/lib/dev/tools/mcp-types.d.ts +0 -28
  181. package/dist/lib/dev/tools/mcp-types.js +0 -86
  182. package/dist/lib/dev/tools/types.d.ts +0 -50
  183. package/dist/lib/dev/tools/types.js +0 -1
  184. package/dist/lib/errors.spec.d.ts +0 -1
  185. package/dist/lib/errors.spec.js +0 -221
  186. package/dist/lib/output.d.ts +0 -36
  187. package/dist/lib/output.js +0 -89
  188. package/dist/lib/output.spec.d.ts +0 -1
  189. package/dist/lib/output.spec.js +0 -123
  190. package/dist/lib/portUtils.d.ts +0 -8
  191. package/dist/lib/portUtils.js +0 -39
  192. package/dist/lib/startup.d.ts +0 -5
  193. package/dist/lib/startup.js +0 -73
  194. package/dist/lib/startup.spec.d.ts +0 -1
  195. package/dist/lib/startup.spec.js +0 -168
  196. package/dist/types/types.d.ts +0 -40
  197. package/dist/types/types.js +0 -1
  198. package/dist/ui/AgentSelector.d.ts +0 -8
  199. package/dist/ui/AgentSelector.js +0 -53
  200. package/dist/ui/ModelSelector.d.ts +0 -8
  201. package/dist/ui/ModelSelector.js +0 -53
  202. package/dist/ui/TeamSelector.d.ts +0 -8
  203. package/dist/ui/TeamSelector.js +0 -55
  204. package/dist/ui/ToolSelector.d.ts +0 -8
  205. package/dist/ui/ToolSelector.js +0 -53
  206. package/dist/ui/statusFormatter.spec.d.ts +0 -1
  207. package/dist/ui/statusFormatter.spec.js +0 -58
@@ -1,256 +0,0 @@
1
- import chalk from 'chalk';
2
- import path from 'path';
3
- import { fileURLToPath } from 'url';
4
- import ora from 'ora';
5
- import fs from 'fs';
6
- import yaml from 'yaml';
7
- import { execSync } from 'child_process';
8
- import output from '../../../lib/output.js';
9
- export async function generateProjectFiles(toolPath, options = {
10
- interactive: true,
11
- dryRun: false,
12
- overwrite: false,
13
- }) {
14
- const absolutePath = path.resolve(toolPath);
15
- const arkConfigPath = path.join(absolutePath, '.ark.yaml');
16
- // Check if .ark.yaml exists
17
- if (!fs.existsSync(arkConfigPath)) {
18
- output.error('.ark.yaml not found. Run "ark dev tool init" first.');
19
- process.exit(1);
20
- }
21
- // Load .ark.yaml
22
- const arkConfig = yaml.parse(fs.readFileSync(arkConfigPath, 'utf-8'));
23
- const generateSpinner = options.dryRun
24
- ? null
25
- : ora('Generating project files...').start();
26
- try {
27
- // Find template directory - templates are in the source tree
28
- const currentFile = fileURLToPath(import.meta.url);
29
- const distDir = path.dirname(path.dirname(path.dirname(path.dirname(currentFile)))); // Goes to dist/
30
- const arkCliDir = path.dirname(distDir); // Goes to ark-cli/
31
- const templateDir = path.join(arkCliDir, 'templates', 'python-mcp-tool');
32
- if (!fs.existsSync(templateDir)) {
33
- if (generateSpinner) {
34
- generateSpinner.fail('Template directory not found');
35
- }
36
- console.log(chalk.yellow('Could not find templates at: ' + templateDir));
37
- return false;
38
- }
39
- // Use a Set to track all generated items (both files and directories)
40
- const generatedItems = new Set();
41
- const skippedItems = new Set();
42
- const errors = [];
43
- // Process all files and directories in the template directory
44
- processTemplateDirectory(templateDir, absolutePath, arkConfig, options, {
45
- generatedItems,
46
- skippedItems,
47
- errors,
48
- });
49
- if (!options.dryRun) {
50
- if (generatedItems.size > 0) {
51
- generateSpinner.succeed(`Generated ${generatedItems.size} file(s)`);
52
- // Show the generated files after stopping the spinner
53
- if (options.interactive && generatedItems.size > 0) {
54
- // Sort items for consistent display
55
- const sortedItems = Array.from(generatedItems).sort();
56
- sortedItems.forEach((item) => {
57
- console.log(chalk.green(` ✓ Generated ${item}`));
58
- });
59
- }
60
- }
61
- else if (skippedItems.size > 0) {
62
- generateSpinner.warn(`No new files generated (${skippedItems.size} already exist)`);
63
- }
64
- else {
65
- generateSpinner.warn('No files to generate');
66
- }
67
- }
68
- if (errors.length > 0 && options.interactive) {
69
- console.log(chalk.red('Errors:'));
70
- errors.forEach((e) => console.log(chalk.red(` - ${e}`)));
71
- }
72
- return generatedItems.size > 0;
73
- }
74
- catch (error) {
75
- if (!options.dryRun && generateSpinner) {
76
- generateSpinner.fail('Failed to generate project files');
77
- }
78
- if (options.interactive) {
79
- console.log(chalk.red(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`));
80
- }
81
- return false;
82
- }
83
- }
84
- function processTemplateDirectory(sourceDir, targetDir, arkConfig, options, stats, rootTargetDir) {
85
- // Track the root target directory for relative path calculations
86
- const actualRootTargetDir = rootTargetDir || targetDir;
87
- // Check if this directory needs to be created
88
- const dirExists = fs.existsSync(targetDir);
89
- // Create target directory if it doesn't exist
90
- if (!options.dryRun && !dirExists) {
91
- fs.mkdirSync(targetDir, { recursive: true });
92
- // Track the directory creation (relative to root)
93
- const relativePath = path.relative(actualRootTargetDir, targetDir);
94
- if (relativePath) {
95
- // Don't add empty string for root directory
96
- stats.generatedItems.add(`${relativePath}/`);
97
- }
98
- }
99
- const entries = fs.readdirSync(sourceDir, { withFileTypes: true });
100
- for (const entry of entries) {
101
- const sourcePath = path.join(sourceDir, entry.name);
102
- if (entry.isDirectory()) {
103
- // Recursively process subdirectories
104
- const targetSubDir = path.join(targetDir, entry.name);
105
- if (options.dryRun) {
106
- const relativePath = path.relative(actualRootTargetDir, targetSubDir);
107
- console.log(chalk.cyan(`\n=== ${relativePath}/ directory ===`));
108
- console.log(`Directory: ${entry.name}`);
109
- console.log(chalk.cyan(`=== END ${relativePath}/ directory ===\n`));
110
- }
111
- processTemplateDirectory(sourcePath, targetSubDir, arkConfig, options, stats, actualRootTargetDir);
112
- }
113
- else {
114
- // Process file - check if it's a template
115
- const isTemplate = entry.name.startsWith('template.');
116
- const targetFileName = isTemplate
117
- ? entry.name.replace('template.', '')
118
- : entry.name;
119
- const targetPath = path.join(targetDir, targetFileName);
120
- // Make target path relative to the original target directory for display
121
- const displayPath = path.relative(actualRootTargetDir, targetPath);
122
- // Check if file already exists
123
- const fileExists = fs.existsSync(targetPath);
124
- if (!options.dryRun && !options.overwrite && fileExists) {
125
- if (options.interactive) {
126
- console.log(chalk.yellow(` Skipping ${displayPath} (already exists)`));
127
- }
128
- stats.skippedItems.add(displayPath);
129
- continue;
130
- }
131
- try {
132
- let content;
133
- if (isTemplate) {
134
- // Process template file with helm - pass the actual root target directory
135
- content = processTemplateFile(sourcePath, targetFileName, arkConfig, options, actualRootTargetDir);
136
- }
137
- else {
138
- // Regular file, just read it
139
- content = fs.readFileSync(sourcePath, 'utf-8');
140
- }
141
- // In dry-run mode, print to stdout; otherwise write the file
142
- if (options.dryRun) {
143
- console.log(chalk.cyan(`\n=== ${displayPath} ===`));
144
- console.log(content);
145
- console.log(chalk.cyan(`=== END ${displayPath} ===\n`));
146
- stats.generatedItems.add(displayPath);
147
- }
148
- else {
149
- fs.writeFileSync(targetPath, content);
150
- stats.generatedItems.add(displayPath);
151
- }
152
- }
153
- catch (err) {
154
- const errorMsg = `${displayPath}: ${err instanceof Error ? err.message : 'Unknown error'}`;
155
- stats.errors.push(errorMsg);
156
- if (options.dryRun) {
157
- console.log(chalk.red(`Error processing ${displayPath}: ${err instanceof Error ? err.message : 'Unknown error'}`));
158
- }
159
- }
160
- }
161
- }
162
- }
163
- function processTemplateFile(templatePath, targetFileName, arkConfig, options, rootTargetDir) {
164
- // Prepare consistent values structure for all templates
165
- const projectName = arkConfig.project?.name ||
166
- path.basename(rootTargetDir || path.dirname(templatePath));
167
- const values = {
168
- project: {
169
- name: projectName,
170
- type: arkConfig.project?.type || 'pyproject',
171
- platform: arkConfig.project?.platform || 'python3',
172
- version: arkConfig.project?.version || '0.1.0',
173
- framework: arkConfig.project?.framework || 'fastmcp',
174
- description: arkConfig.project?.description || `${projectName} MCP tool`,
175
- },
176
- python: {
177
- version: '3.11', // Default Python version
178
- module_name: projectName.replace(/-/g, '_'), // Convert kebab-case to snake_case
179
- },
180
- mcp: {
181
- transport: arkConfig.mcp?.transport || 'sse', // Default to SSE for Kubernetes
182
- port: arkConfig.mcp?.port || 8080,
183
- healthCheck: arkConfig.mcp?.transport !== 'stdio', // No health checks for stdio
184
- },
185
- devspace: {
186
- namespace: 'default',
187
- image: {
188
- repository: projectName, // Default repository name
189
- },
190
- },
191
- };
192
- // Create temp directory for helm processing
193
- const tempDir = path.join('/tmp', `ark-helm-${Date.now()}`);
194
- const tempChartDir = path.join(tempDir, 'chart');
195
- const tempTemplatesDir = path.join(tempChartDir, 'templates');
196
- fs.mkdirSync(tempTemplatesDir, { recursive: true });
197
- try {
198
- // Write minimal Chart.yaml
199
- fs.writeFileSync(path.join(tempChartDir, 'Chart.yaml'), 'apiVersion: v2\nname: temp\nversion: 0.1.0\n');
200
- // Write values file
201
- const tempValuesFile = path.join(tempDir, 'values.yaml');
202
- fs.writeFileSync(tempValuesFile, yaml.stringify(values));
203
- // Determine if this is a YAML file
204
- const isYamlFile = targetFileName.endsWith('.yaml') || targetFileName.endsWith('.yml');
205
- // For dotfiles, replace the leading dot with 'dot' for helm processing
206
- const helmTemplateName = targetFileName.startsWith('.')
207
- ? 'dot' + targetFileName.substring(1)
208
- : targetFileName;
209
- if (isYamlFile) {
210
- // Copy YAML files directly
211
- fs.copyFileSync(templatePath, path.join(tempTemplatesDir, helmTemplateName));
212
- }
213
- else {
214
- // Wrap non-YAML content in a YAML structure for helm
215
- const originalContent = fs.readFileSync(templatePath, 'utf-8');
216
- const wrappedContent = `# Wrapped for helm processing\ncontent: |\n${originalContent
217
- .split('\n')
218
- .map((line) => ' ' + line)
219
- .join('\n')}`;
220
- fs.writeFileSync(path.join(tempTemplatesDir, helmTemplateName + '.yaml'), wrappedContent);
221
- }
222
- // Run helm template to process the file
223
- const actualHelmFile = isYamlFile
224
- ? helmTemplateName
225
- : helmTemplateName + '.yaml';
226
- const helmCommand = `helm template temp ${tempChartDir} --values ${tempValuesFile} -s templates/${actualHelmFile}`;
227
- let content;
228
- try {
229
- content = execSync(helmCommand, {
230
- encoding: 'utf-8',
231
- stdio: ['pipe', 'pipe', 'pipe'],
232
- });
233
- // Remove the YAML document separator that helm adds
234
- content = content.replace(/^---\n/, '');
235
- // Remove helm's source comment
236
- content = content.replace(/^# Source:.*\n/gm, '');
237
- // For non-YAML files, extract the content from the wrapped YAML
238
- if (!isYamlFile) {
239
- // Parse the YAML to extract the content field
240
- const yamlContent = yaml.parse(content);
241
- content = yamlContent.content || '';
242
- }
243
- }
244
- catch (helmError) {
245
- const errorMsg = helmError.stderr || helmError.message || 'Unknown error';
246
- throw new Error(`Failed to template ${targetFileName}: ${errorMsg}`);
247
- }
248
- return content;
249
- }
250
- finally {
251
- // Clean up temp directory
252
- if (fs.existsSync(tempDir)) {
253
- fs.rmSync(tempDir, { recursive: true, force: true });
254
- }
255
- }
256
- }
@@ -1,2 +0,0 @@
1
- import { Command } from 'commander';
2
- export declare function createStatusCommand(): Command;
@@ -1,136 +0,0 @@
1
- import { Command } from 'commander';
2
- import chalk from 'chalk';
3
- import path from 'path';
4
- import ora from 'ora';
5
- import output from '../../../lib/output.js';
6
- import { ArkDevToolAnalyzer } from '../../../lib/dev/tools/analyzer.js';
7
- import { toMCPTool } from '../../../lib/dev/tools/mcp-types.js';
8
- async function statusTool(toolPath, options) {
9
- const absolutePath = path.resolve(toolPath);
10
- const analyzer = new ArkDevToolAnalyzer();
11
- const isJson = options.output === 'json';
12
- // Build up result object as we go
13
- const result = {
14
- path: absolutePath,
15
- projectRoot: null,
16
- error: null,
17
- platform: null,
18
- projectType: null,
19
- projectName: null,
20
- projectVersion: null,
21
- hasFastmcp: false,
22
- fastmcpVersion: null,
23
- tools: [],
24
- toolDiscoveryError: null
25
- };
26
- if (!isJson) {
27
- console.log();
28
- }
29
- // Single spinner for all analysis (skip for JSON output)
30
- const analyzeSpinner = isJson ? null : ora(`analyzing ${absolutePath}`).start();
31
- // Small delay to let user see what's happening (skip for JSON)
32
- if (!isJson) {
33
- await new Promise(resolve => setTimeout(resolve, 500));
34
- }
35
- // Collect all information
36
- const project = await analyzer.discoverProject(absolutePath);
37
- if (!project || !project.exists) {
38
- result.error = 'path not found';
39
- if (isJson) {
40
- console.log(JSON.stringify(result, null, 2));
41
- }
42
- else {
43
- analyzeSpinner.stop();
44
- output.error(`path not found: ${absolutePath}`);
45
- }
46
- process.exit(1);
47
- }
48
- if (!project.is_directory) {
49
- result.error = 'path is not a directory';
50
- if (isJson) {
51
- console.log(JSON.stringify(result, null, 2));
52
- }
53
- else {
54
- analyzeSpinner.stop();
55
- output.error(`path is not a directory: ${absolutePath}`);
56
- }
57
- process.exit(1);
58
- }
59
- if (!project.platform) {
60
- result.error = 'platform unknown - no pyproject.toml or requirements.txt found';
61
- if (isJson) {
62
- console.log(JSON.stringify(result, null, 2));
63
- }
64
- else {
65
- analyzeSpinner.stop();
66
- output.error(`no pyproject.toml or requirements.txt found in: ${absolutePath}`);
67
- }
68
- process.exit(1);
69
- }
70
- // Update result with project info
71
- result.platform = project.platform;
72
- result.projectType = project.project_type;
73
- result.projectName = project.project_name;
74
- result.projectVersion = project.project_version;
75
- result.hasFastmcp = project.has_fastmcp;
76
- result.fastmcpVersion = project.fastmcp_version;
77
- result.projectRoot = absolutePath; // Store the project root
78
- // Discover tools recursively in the project
79
- const rawTools = [];
80
- try {
81
- const projectTools = await analyzer.findProjectTools(absolutePath);
82
- if (projectTools && projectTools.tools) {
83
- rawTools.push(...projectTools.tools);
84
- }
85
- }
86
- catch (error) {
87
- result.toolDiscoveryError = error instanceof Error ? error.message : 'Unknown error';
88
- }
89
- // Store tools in the appropriate format
90
- result.tools = isJson ? rawTools.map(toMCPTool) : rawTools;
91
- if (isJson) {
92
- // Output raw JSON
93
- console.log(JSON.stringify(result, null, 2));
94
- return;
95
- }
96
- analyzeSpinner.succeed('analysis complete');
97
- console.log();
98
- // Display summary in cleaner format
99
- output.section(path.basename(absolutePath));
100
- // Platform
101
- output.statusCheck('found', 'platform', result.platform);
102
- // Project type with name and version in gray
103
- let projectDetails = '';
104
- if (result.projectName) {
105
- projectDetails = result.projectName;
106
- if (result.projectVersion) {
107
- projectDetails += ` v${result.projectVersion}`;
108
- }
109
- }
110
- output.statusCheck('found', 'project', result.projectType, projectDetails);
111
- // Framework with version in gray
112
- if (result.hasFastmcp) {
113
- const fastmcpDetails = result.fastmcpVersion ? `v${result.fastmcpVersion}` : undefined;
114
- output.statusCheck('found', 'framework', 'fastmcp', fastmcpDetails);
115
- }
116
- else {
117
- output.statusCheck('missing', 'framework', 'fastmcp');
118
- }
119
- // Tools with details
120
- output.statusCheck('found', 'tools', result.tools.length.toString());
121
- if (result.tools.length > 0) {
122
- for (const tool of result.tools) {
123
- const description = tool.docstring ? tool.docstring.split('\n')[0] : '';
124
- console.log(chalk.gray(` - ${tool.name}: ${description}`));
125
- }
126
- }
127
- }
128
- export function createStatusCommand() {
129
- const statusCommand = new Command('status');
130
- statusCommand
131
- .description('Check the status of an MCP tool project')
132
- .argument('<path>', 'Path to the tool directory')
133
- .option('-o, --output <format>', 'Output format (json)', 'text')
134
- .action(statusTool);
135
- return statusCommand;
136
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,163 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach } from '@jest/globals';
2
- import { execSync } from 'child_process';
3
- import path from 'path';
4
- import { fileURLToPath } from 'url';
5
- import fs from 'fs';
6
- import os from 'os';
7
- const __filename = fileURLToPath(import.meta.url);
8
- const __dirname = path.dirname(__filename);
9
- describe('ark dev tool generate', () => {
10
- let tempDir;
11
- const cliPath = path.join(__dirname, '../../../dist/index.js');
12
- beforeEach(() => {
13
- // Create a temp directory for testing
14
- tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ark-test-'));
15
- });
16
- afterEach(() => {
17
- // Clean up temp directory
18
- if (tempDir && fs.existsSync(tempDir)) {
19
- fs.rmSync(tempDir, { recursive: true, force: true });
20
- }
21
- });
22
- describe('Dockerfile generation', () => {
23
- it('should generate correct Dockerfile for pyproject type', () => {
24
- // Create a test .ark.yaml
25
- const arkYaml = `version: "1.0"
26
- project:
27
- path: ${tempDir}
28
- platform: python3
29
- type: pyproject
30
- name: test-tool
31
- version: 0.2.0
32
- framework: fastmcp
33
- frameworkVersion: 0.5.0
34
- `;
35
- fs.writeFileSync(path.join(tempDir, '.ark.yaml'), arkYaml);
36
- // Run the generate command
37
- execSync(`node ${cliPath} dev tool generate ${tempDir}`, {
38
- encoding: 'utf8',
39
- });
40
- // Check Dockerfile was generated
41
- const dockerfilePath = path.join(tempDir, 'Dockerfile');
42
- expect(fs.existsSync(dockerfilePath)).toBe(true);
43
- // Check Dockerfile content
44
- const dockerfileContent = fs.readFileSync(dockerfilePath, 'utf-8');
45
- // Should have uv commands for pyproject
46
- expect(dockerfileContent).toContain('RUN pip install uv');
47
- expect(dockerfileContent).toContain('COPY pyproject.toml ./');
48
- expect(dockerfileContent).toContain('COPY uv.lock* ./');
49
- expect(dockerfileContent).toContain('RUN uv sync --frozen');
50
- expect(dockerfileContent).toContain('CMD ["uv", "run", "python", "-m", "test_tool"]');
51
- // Should NOT have requirements.txt commands
52
- expect(dockerfileContent).not.toContain('requirements.txt');
53
- expect(dockerfileContent).not.toContain('pip install --no-cache-dir');
54
- });
55
- it('should generate correct Dockerfile for requirements type', () => {
56
- // Create a test .ark.yaml with requirements type
57
- const arkYaml = `version: "1.0"
58
- project:
59
- path: ${tempDir}
60
- platform: python3
61
- type: requirements
62
- name: test-req-tool
63
- version: 0.1.0
64
- `;
65
- fs.writeFileSync(path.join(tempDir, '.ark.yaml'), arkYaml);
66
- // Run the generate command
67
- execSync(`node ${cliPath} dev tool generate ${tempDir}`, {
68
- encoding: 'utf8',
69
- });
70
- // Check Dockerfile was generated
71
- const dockerfilePath = path.join(tempDir, 'Dockerfile');
72
- expect(fs.existsSync(dockerfilePath)).toBe(true);
73
- // Check Dockerfile content
74
- const dockerfileContent = fs.readFileSync(dockerfilePath, 'utf-8');
75
- // Should have pip commands for requirements.txt
76
- expect(dockerfileContent).toContain('COPY requirements.txt ./');
77
- expect(dockerfileContent).toContain('RUN pip install --no-cache-dir -r requirements.txt');
78
- expect(dockerfileContent).toContain('CMD ["python", "-m", "test_req_tool"]');
79
- // Should NOT have uv commands
80
- expect(dockerfileContent).not.toContain('RUN pip install uv');
81
- expect(dockerfileContent).not.toContain('pyproject.toml');
82
- expect(dockerfileContent).not.toContain('uv.lock');
83
- expect(dockerfileContent).not.toContain('uv sync');
84
- });
85
- });
86
- describe('.dockerignore generation', () => {
87
- it('should generate comprehensive .dockerignore file', () => {
88
- // Create a test .ark.yaml
89
- const arkYaml = `version: "1.0"
90
- project:
91
- platform: python3
92
- type: pyproject
93
- name: test-tool
94
- `;
95
- fs.writeFileSync(path.join(tempDir, '.ark.yaml'), arkYaml);
96
- // Run the generate command
97
- execSync(`node ${cliPath} dev tool generate ${tempDir}`, {
98
- encoding: 'utf8',
99
- });
100
- // Check .dockerignore was generated
101
- const dockerignorePath = path.join(tempDir, '.dockerignore');
102
- expect(fs.existsSync(dockerignorePath)).toBe(true);
103
- // Check .dockerignore content
104
- const dockerignoreContent = fs.readFileSync(dockerignorePath, 'utf-8');
105
- // Should include Python patterns
106
- expect(dockerignoreContent).toContain('__pycache__/');
107
- expect(dockerignoreContent).toContain('*.py[cod]');
108
- expect(dockerignoreContent).toContain('*.egg-info/');
109
- // Should include UV patterns
110
- expect(dockerignoreContent).toContain('.venv/');
111
- // Should include testing patterns
112
- expect(dockerignoreContent).toContain('.pytest_cache/');
113
- expect(dockerignoreContent).toContain('.coverage');
114
- // Should include IDE patterns
115
- expect(dockerignoreContent).toContain('.vscode/');
116
- expect(dockerignoreContent).toContain('.idea/');
117
- // Should include ARK specific patterns
118
- expect(dockerignoreContent).toContain('.ark.yaml');
119
- expect(dockerignoreContent).toContain('devspace.yaml');
120
- });
121
- });
122
- describe('file skip behavior', () => {
123
- it('should skip existing files without overwriting', () => {
124
- // Create a test .ark.yaml
125
- const arkYaml = `version: "1.0"
126
- project:
127
- platform: python3
128
- type: pyproject
129
- name: test-tool
130
- `;
131
- fs.writeFileSync(path.join(tempDir, '.ark.yaml'), arkYaml);
132
- // Create an existing Dockerfile with custom content
133
- const customDockerfile = '# My custom Dockerfile\nFROM alpine\n';
134
- fs.writeFileSync(path.join(tempDir, 'Dockerfile'), customDockerfile);
135
- // Run the generate command
136
- const output = execSync(`node ${cliPath} dev tool generate ${tempDir}`, {
137
- encoding: 'utf8',
138
- });
139
- // Check that existing file was not overwritten
140
- const dockerfileContent = fs.readFileSync(path.join(tempDir, 'Dockerfile'), 'utf-8');
141
- expect(dockerfileContent).toBe(customDockerfile);
142
- // Check that output mentions skipping the existing file
143
- expect(output).toContain('Skipping Dockerfile (already exists)');
144
- });
145
- });
146
- describe('error handling', () => {
147
- it('should fail when .ark.yaml is missing', () => {
148
- // Try to run generate without .ark.yaml
149
- let error = null;
150
- try {
151
- execSync(`node ${cliPath} dev tool generate ${tempDir}`, {
152
- encoding: 'utf8',
153
- stdio: 'pipe',
154
- });
155
- }
156
- catch (e) {
157
- error = e;
158
- }
159
- expect(error).not.toBeNull();
160
- expect(error.message).toContain('.ark.yaml not found');
161
- });
162
- });
163
- });
@@ -1,2 +0,0 @@
1
- import { Command } from 'commander';
2
- export declare function createToolCommand(): Command;