@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,304 @@
1
+ import chalk from 'chalk';
2
+ import inquirer from 'inquirer';
3
+ import path from 'path';
4
+ import fs from 'fs';
5
+ import { TemplateDiscovery } from '../templateDiscovery.js';
6
+ import { TemplateEngine } from '../templateEngine.js';
7
+ import { ArkError, ErrorCode } from '../../../lib/errors.js';
8
+ export function createMarketplaceGenerator() {
9
+ const generator = new MarketplaceGenerator();
10
+ return {
11
+ name: 'marketplace',
12
+ description: 'Central repository for sharing reusable ARK components',
13
+ templatePath: 'marketplace',
14
+ generate: async (name, destination, options) => {
15
+ await generator.generate(name, destination, options);
16
+ },
17
+ };
18
+ }
19
+ class MarketplaceGenerator {
20
+ constructor() {
21
+ this.templateDiscovery = new TemplateDiscovery();
22
+ this.templateEngine = new TemplateEngine();
23
+ }
24
+ /**
25
+ * Get marketplace configuration from user input and validation
26
+ */
27
+ async getMarketplaceConfig(destination, options) {
28
+ // Always use "ark-marketplace" as the name
29
+ const normalizedName = 'ark-marketplace';
30
+ const targetDir = path.resolve(destination, normalizedName);
31
+ // Check if directory already exists
32
+ if (fs.existsSync(targetDir)) {
33
+ throw new ArkError(`Directory ${targetDir} already exists. Please choose a different name or location.`, ErrorCode.VALIDATION_ERROR);
34
+ }
35
+ const config = {
36
+ name: normalizedName,
37
+ destination: targetDir,
38
+ description: 'Ark marketplace for sharing ARK components',
39
+ initGit: true,
40
+ };
41
+ // Get current git configuration
42
+ const gitConfig = await this.getGitUserConfig();
43
+ // Use command line options if provided, otherwise use current git config, fallback to defaults
44
+ config.initGit = !options.skipGit;
45
+ config.gitUserName =
46
+ options.gitUserName || gitConfig.name || 'Marketplace Team';
47
+ config.gitUserEmail =
48
+ options.gitUserEmail || gitConfig.email || 'marketplace@example.com';
49
+ return config;
50
+ }
51
+ /**
52
+ * Get current git user configuration (secure implementation)
53
+ */
54
+ async getGitUserConfig() {
55
+ try {
56
+ const { execa } = await import('execa');
57
+ // Use secure PATH and argument arrays to prevent injection
58
+ const gitPath = process.env.GIT_PATH || '/usr/bin/git';
59
+ const secureEnv = {
60
+ PATH: '/usr/local/bin:/usr/bin:/bin',
61
+ ...process.env,
62
+ };
63
+ const nameResult = await execa(gitPath, ['config', 'user.name'], {
64
+ env: secureEnv,
65
+ stdio: 'pipe',
66
+ timeout: 5000, // 5 second timeout
67
+ });
68
+ const emailResult = await execa(gitPath, ['config', 'user.email'], {
69
+ env: secureEnv,
70
+ stdio: 'pipe',
71
+ timeout: 5000,
72
+ });
73
+ return {
74
+ name: nameResult.stdout.trim(),
75
+ email: emailResult.stdout.trim(),
76
+ };
77
+ }
78
+ catch {
79
+ return {};
80
+ }
81
+ }
82
+ /**
83
+ * Get marketplace configuration with interactive prompts
84
+ */
85
+ async getInteractiveConfig(config) {
86
+ console.log(chalk.cyan('\nšŸŖ Marketplace Configuration\n'));
87
+ const answers = await inquirer.prompt([
88
+ {
89
+ type: 'input',
90
+ name: 'destination',
91
+ message: 'Where would you like to create the marketplace?',
92
+ default: path.dirname(config.destination),
93
+ validate: (input) => {
94
+ if (!input.trim()) {
95
+ return 'Destination path is required';
96
+ }
97
+ return true;
98
+ },
99
+ },
100
+ {
101
+ type: 'confirm',
102
+ name: 'initGit',
103
+ message: `Initialize Git repository with ${config.gitUserName} <${config.gitUserEmail}>?`,
104
+ default: config.initGit,
105
+ },
106
+ ]);
107
+ // Update config with answers
108
+ const updatedConfig = {
109
+ ...config,
110
+ destination: path.resolve(answers.destination, config.name),
111
+ initGit: answers.initGit,
112
+ };
113
+ // Check if the updated destination already exists
114
+ if (fs.existsSync(updatedConfig.destination)) {
115
+ throw new ArkError(`Directory ${updatedConfig.destination} already exists. Please choose a different location.`, ErrorCode.VALIDATION_ERROR);
116
+ }
117
+ return updatedConfig;
118
+ }
119
+ /**
120
+ * Show configuration summary and ask for confirmation
121
+ */
122
+ async confirmGeneration(config) {
123
+ console.log(chalk.cyan('\nšŸ“‹ Marketplace Generation Summary\n'));
124
+ console.log(`Name: ${chalk.green(config.name)}`);
125
+ console.log(`Description: ${config.description}`);
126
+ console.log(`Destination: ${chalk.yellow(config.destination)}`);
127
+ console.log(`Git Repository: ${config.initGit ? chalk.green('Yes') : 'No'}`);
128
+ if (config.initGit) {
129
+ console.log(`Git User: ${config.gitUserName} <${config.gitUserEmail}>`);
130
+ }
131
+ const confirm = await inquirer.prompt([
132
+ {
133
+ type: 'confirm',
134
+ name: 'proceed',
135
+ message: 'Create marketplace with this configuration?',
136
+ default: true,
137
+ },
138
+ ]);
139
+ if (!confirm.proceed) {
140
+ console.log(chalk.yellow('Marketplace generation cancelled.'));
141
+ process.exit(0);
142
+ }
143
+ }
144
+ /**
145
+ * Validate git configuration values to prevent injection
146
+ */
147
+ validateGitConfig(value, type) {
148
+ if (!value || typeof value !== 'string') {
149
+ throw new ArkError(`Invalid git ${type}: must be a non-empty string`, ErrorCode.VALIDATION_ERROR);
150
+ }
151
+ // Prevent command injection by checking for dangerous characters
152
+ const dangerousChars = /[\\`$;|&<>(){}[\]]/;
153
+ if (dangerousChars.test(value)) {
154
+ throw new ArkError(`Invalid git ${type}: contains dangerous characters`, ErrorCode.VALIDATION_ERROR, undefined, ['Remove special characters and shell metacharacters']);
155
+ }
156
+ // Additional validation for email format
157
+ if (type === 'email') {
158
+ const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
159
+ if (!emailRegex.test(value)) {
160
+ throw new ArkError(`Invalid git email format: ${value}`, ErrorCode.VALIDATION_ERROR);
161
+ }
162
+ }
163
+ // Length validation
164
+ if (value.length > 100) {
165
+ throw new ArkError(`Git ${type} too long (max 100 characters)`, ErrorCode.VALIDATION_ERROR);
166
+ }
167
+ }
168
+ /**
169
+ * Setup git repository with initial commit (secure implementation)
170
+ */
171
+ async setupGit(config) {
172
+ try {
173
+ const { execa } = await import('execa');
174
+ // Use secure PATH and git path
175
+ const gitPath = process.env.GIT_PATH || '/usr/bin/git';
176
+ const secureEnv = {
177
+ PATH: '/usr/local/bin:/usr/bin:/bin',
178
+ ...process.env,
179
+ };
180
+ const execOptions = {
181
+ cwd: config.destination,
182
+ env: secureEnv,
183
+ stdio: 'pipe',
184
+ timeout: 10000, // 10 second timeout
185
+ };
186
+ // Initialize git repository
187
+ await execa(gitPath, ['init'], execOptions);
188
+ // Configure git user if provided (with validation)
189
+ if (config.gitUserName) {
190
+ this.validateGitConfig(config.gitUserName, 'name');
191
+ await execa(gitPath, ['config', 'user.name', config.gitUserName], execOptions);
192
+ }
193
+ if (config.gitUserEmail) {
194
+ this.validateGitConfig(config.gitUserEmail, 'email');
195
+ await execa(gitPath, ['config', 'user.email', config.gitUserEmail], execOptions);
196
+ }
197
+ // Add all files and create initial commit
198
+ await execa(gitPath, ['add', '.'], execOptions);
199
+ await execa(gitPath, ['commit', '-m', 'Initial marketplace structure'], execOptions);
200
+ console.log(chalk.green('āœ… Git repository initialized'));
201
+ }
202
+ catch (error) {
203
+ console.warn(chalk.yellow('āš ļø Git initialization failed:'), error instanceof Error ? error.message : String(error));
204
+ }
205
+ }
206
+ /**
207
+ * Generate marketplace structure
208
+ */
209
+ async generateMarketplace(config) {
210
+ console.log(chalk.cyan('\nšŸ—ļø Creating marketplace structure...'));
211
+ // Set template variables
212
+ const variables = {
213
+ projectName: config.name,
214
+ description: config.description,
215
+ PROJECT_NAME: config.name,
216
+ authorName: config.gitUserName || 'Marketplace Team',
217
+ authorEmail: config.gitUserEmail || 'marketplace@example.com',
218
+ };
219
+ this.templateEngine.setVariables(variables);
220
+ // Get template path
221
+ const templatePath = this.templateDiscovery.getTemplatePath('marketplace');
222
+ // Verify template exists
223
+ if (!this.templateDiscovery.templateExists('marketplace')) {
224
+ throw new ArkError('Marketplace template not found. Please ensure the template is available in the templates directory.', ErrorCode.TEMPLATE_ERROR);
225
+ }
226
+ // Configure exclude patterns
227
+ const excludePatterns = ['.git', 'node_modules', '.DS_Store'];
228
+ // Process template
229
+ await this.templateEngine.processTemplate(templatePath, config.destination, {
230
+ createDirectories: true,
231
+ exclude: excludePatterns,
232
+ });
233
+ console.log(chalk.green('āœ… Marketplace structure created'));
234
+ }
235
+ /**
236
+ * Show completion message with next steps
237
+ */
238
+ showCompletionMessage(config) {
239
+ const relativePath = path.relative(process.cwd(), config.destination);
240
+ const displayPath = relativePath || config.destination;
241
+ console.log(chalk.green('\nšŸŽ‰ Marketplace created successfully!'));
242
+ console.log(chalk.cyan('\nšŸ“ Location:'), displayPath);
243
+ console.log(chalk.cyan('šŸ“ Description:'), config.description);
244
+ console.log(chalk.cyan('\nšŸš€ Next steps:'));
245
+ console.log(' 1. ' + chalk.yellow('cd ' + displayPath));
246
+ console.log(' 2. ' + chalk.yellow('# Create remote repository on GitHub/GitLab'));
247
+ console.log(' 3. ' + chalk.yellow('git remote add origin <YOUR_REPO_URL>'));
248
+ console.log(' 4. ' + chalk.yellow('git push -u origin main'));
249
+ console.log(' 5. ' +
250
+ chalk.yellow('# Add your first component to the appropriate directory'));
251
+ console.log(' 6. ' +
252
+ chalk.yellow('# Update the README.md with marketplace-specific information'));
253
+ console.log(' 7. ' + chalk.yellow('# Set up CI/CD workflows in .github/workflows/'));
254
+ console.log(' 8. ' +
255
+ chalk.yellow('# Configure contribution guidelines and review process'));
256
+ console.log(chalk.cyan('\nšŸ“‚ Directory structure:'));
257
+ console.log(' • agents/ - Reusable agent definitions');
258
+ console.log(' • teams/ - Multi-agent workflow configurations');
259
+ console.log(' • models/ - Model configurations by provider');
260
+ console.log(' • queries/ - Query templates and patterns');
261
+ console.log(' • tools/ - Tool definitions and implementations');
262
+ console.log(' • mcp-servers/ - MCP server configurations');
263
+ console.log(' • projects/ - Complete Ark project templates and solutions');
264
+ console.log(' • docs/ - Documentation and guides');
265
+ console.log(chalk.cyan('\nšŸ’” Tips:'));
266
+ console.log(' • Each .keep file contains guidelines for that directory');
267
+ console.log(' • Use the templates/ directory to create component templates');
268
+ console.log(' • Set up automated validation in CI/CD pipelines');
269
+ console.log(' • Encourage comprehensive documentation for all components');
270
+ if (config.initGit) {
271
+ console.log(chalk.cyan('\nšŸ”— Git repository:'));
272
+ console.log(' • Repository initialized with initial commit');
273
+ console.log(' • Ready to add remote origin and push to GitHub/GitLab');
274
+ console.log(' • Consider setting up branch protection rules');
275
+ }
276
+ }
277
+ /**
278
+ * Main generation method
279
+ */
280
+ async generate(_name, destination, options) {
281
+ try {
282
+ // Get initial configuration
283
+ let config = await this.getMarketplaceConfig(destination, options);
284
+ // Get interactive configuration (allows editing destination and git settings)
285
+ config = await this.getInteractiveConfig(config);
286
+ // Show summary and confirm
287
+ await this.confirmGeneration(config);
288
+ // Generate marketplace
289
+ await this.generateMarketplace(config);
290
+ // Setup git if requested
291
+ if (config.initGit) {
292
+ await this.setupGit(config);
293
+ }
294
+ // Show completion message
295
+ this.showCompletionMessage(config);
296
+ }
297
+ catch (error) {
298
+ if (error instanceof ArkError) {
299
+ throw error;
300
+ }
301
+ throw new ArkError(`Failed to generate marketplace: ${error instanceof Error ? error.message : String(error)}`, ErrorCode.UNKNOWN_ERROR);
302
+ }
303
+ }
304
+ }
@@ -0,0 +1,25 @@
1
+ export interface McpServerConfig {
2
+ mcpServerName: string;
3
+ description: string;
4
+ technology: 'node' | 'deno' | 'go' | 'python';
5
+ packageSource: 'local' | 'npm' | 'jsr' | 'go-install' | 'pip';
6
+ packageName?: string;
7
+ destination: string;
8
+ requiresAuth: boolean;
9
+ hasCustomConfig: boolean;
10
+ maintainerName: string;
11
+ homeUrl?: string;
12
+ tools: Array<{
13
+ name: string;
14
+ description: string;
15
+ }>;
16
+ packageManager: string;
17
+ sourceUrls: string[];
18
+ sampleQuery: string;
19
+ }
20
+ export declare function createMcpServerGenerator(): {
21
+ name: string;
22
+ description: string;
23
+ templatePath: string;
24
+ generate: (name: string, destination: string, options: any) => Promise<void>;
25
+ };
@@ -0,0 +1,350 @@
1
+ import chalk from 'chalk';
2
+ import inquirer from 'inquirer';
3
+ import path from 'path';
4
+ import fs from 'fs';
5
+ import { TemplateEngine } from '../templateEngine.js';
6
+ import { TemplateDiscovery } from '../templateDiscovery.js';
7
+ export function createMcpServerGenerator() {
8
+ return {
9
+ name: 'mcp-server',
10
+ description: 'Generate a new MCP server with Kubernetes deployment from template',
11
+ templatePath: 'templates/mcp-server',
12
+ generate: async (name, destination, options) => {
13
+ const generator = new McpServerGenerator();
14
+ await generator.generate(name, destination, options);
15
+ },
16
+ };
17
+ }
18
+ class McpServerGenerator {
19
+ constructor() {
20
+ this.templateDiscovery = new TemplateDiscovery();
21
+ this.templateEngine = new TemplateEngine();
22
+ }
23
+ async generate(name, destination, _options) {
24
+ console.log(chalk.blue('šŸš€ ARK MCP Server Generator\n'));
25
+ // Get MCP server configuration
26
+ const config = await this.getMcpServerConfig(name, destination);
27
+ // Show summary and confirm
28
+ await this.showSummaryAndConfirm(config);
29
+ // Generate the MCP server
30
+ await this.generateMcpServer(config);
31
+ // Show next steps
32
+ this.showNextSteps(config);
33
+ }
34
+ async getMcpServerConfig(name, destination) {
35
+ console.log(chalk.cyan('šŸ“‹ MCP Server Configuration\n'));
36
+ // Determine if we're in a project context
37
+ const isInProject = this.isInProjectContext(destination);
38
+ const defaultDestination = isInProject
39
+ ? path.join(destination, 'mcp-servers', name)
40
+ : path.join(destination, name);
41
+ const answers = await inquirer.prompt([
42
+ {
43
+ type: 'input',
44
+ name: 'mcpServerName',
45
+ message: 'MCP server name:',
46
+ default: name,
47
+ validate: (input) => {
48
+ if (!/^[a-zA-Z0-9_-]+$/.test(input)) {
49
+ return 'MCP server name can only contain letters, numbers, hyphens, and underscores';
50
+ }
51
+ return true;
52
+ },
53
+ },
54
+ {
55
+ type: 'input',
56
+ name: 'description',
57
+ message: 'MCP server description:',
58
+ default: `A custom MCP server named ${name} with Kubernetes deployment`,
59
+ },
60
+ {
61
+ type: 'list',
62
+ name: 'technology',
63
+ message: 'Choose the technology stack:',
64
+ choices: [
65
+ { name: 'Node.js (JavaScript/TypeScript)', value: 'node' },
66
+ { name: 'Deno (TypeScript)', value: 'deno' },
67
+ { name: 'Go', value: 'go' },
68
+ { name: 'Python', value: 'python' },
69
+ ],
70
+ default: 'node',
71
+ },
72
+ {
73
+ type: 'list',
74
+ name: 'packageSource',
75
+ message: 'Package source:',
76
+ choices: (answers) => {
77
+ switch (answers.technology) {
78
+ case 'node':
79
+ return [
80
+ {
81
+ name: 'Local development (custom implementation)',
82
+ value: 'local',
83
+ },
84
+ { name: 'NPM package', value: 'npm' },
85
+ ];
86
+ case 'deno':
87
+ return [
88
+ {
89
+ name: 'Local development (custom implementation)',
90
+ value: 'local',
91
+ },
92
+ { name: 'JSR package', value: 'jsr' },
93
+ ];
94
+ case 'go':
95
+ return [
96
+ {
97
+ name: 'Local development (custom implementation)',
98
+ value: 'local',
99
+ },
100
+ { name: 'Go install package', value: 'go-install' },
101
+ ];
102
+ case 'python':
103
+ return [
104
+ {
105
+ name: 'Local development (custom implementation)',
106
+ value: 'local',
107
+ },
108
+ { name: 'Pip package', value: 'pip' },
109
+ ];
110
+ default:
111
+ return [{ name: 'Local development', value: 'local' }];
112
+ }
113
+ },
114
+ default: 'local',
115
+ },
116
+ {
117
+ type: 'input',
118
+ name: 'packageName',
119
+ message: 'Package name (if using external package):',
120
+ when: (answers) => answers.packageSource !== 'local',
121
+ validate: (input, answers) => {
122
+ if (answers.packageSource !== 'local' && !input.trim()) {
123
+ return 'Package name is required when using external packages';
124
+ }
125
+ return true;
126
+ },
127
+ },
128
+ {
129
+ type: 'input',
130
+ name: 'destination',
131
+ message: 'Destination directory:',
132
+ default: defaultDestination,
133
+ },
134
+ {
135
+ type: 'confirm',
136
+ name: 'requiresAuth',
137
+ message: 'Does this MCP server require authentication?',
138
+ default: false,
139
+ },
140
+ {
141
+ type: 'confirm',
142
+ name: 'hasCustomConfig',
143
+ message: 'Does this MCP server need custom configuration?',
144
+ default: false,
145
+ },
146
+ {
147
+ type: 'input',
148
+ name: 'maintainerName',
149
+ message: 'Maintainer name:',
150
+ default: 'QBAF Team',
151
+ },
152
+ {
153
+ type: 'input',
154
+ name: 'homeUrl',
155
+ message: 'Home URL (optional):',
156
+ default: '',
157
+ },
158
+ ]);
159
+ // Get tool definitions
160
+ const tools = await this.getToolDefinitions();
161
+ // Check if destination exists
162
+ if (fs.existsSync(answers.destination)) {
163
+ const overwrite = await inquirer.prompt([
164
+ {
165
+ type: 'confirm',
166
+ name: 'overwrite',
167
+ message: `Directory ${answers.destination} already exists. Overwrite?`,
168
+ default: false,
169
+ },
170
+ ]);
171
+ if (!overwrite.overwrite) {
172
+ console.log(chalk.yellow('Operation cancelled.'));
173
+ process.exit(0);
174
+ }
175
+ }
176
+ return {
177
+ ...answers,
178
+ tools,
179
+ packageManager: this.getPackageManager(answers.technology),
180
+ sourceUrls: answers.homeUrl ? [answers.homeUrl] : [],
181
+ sampleQuery: this.generateSampleQuery(tools),
182
+ };
183
+ }
184
+ async getToolDefinitions() {
185
+ console.log(chalk.cyan('\nšŸ”§ Tool Definitions\n'));
186
+ console.log('Define the tools this MCP server will provide:');
187
+ const tools = [];
188
+ const addMore = await inquirer.prompt([
189
+ {
190
+ type: 'confirm',
191
+ name: 'addTools',
192
+ message: 'Add tool definitions?',
193
+ default: true,
194
+ },
195
+ ]);
196
+ if (addMore.addTools) {
197
+ let addingTools = true;
198
+ while (addingTools) {
199
+ const toolInfo = await inquirer.prompt([
200
+ {
201
+ type: 'input',
202
+ name: 'name',
203
+ message: 'Tool name:',
204
+ validate: (input) => {
205
+ if (!input.trim()) {
206
+ return 'Tool name is required';
207
+ }
208
+ return true;
209
+ },
210
+ },
211
+ {
212
+ type: 'input',
213
+ name: 'description',
214
+ message: 'Tool description:',
215
+ validate: (input) => {
216
+ if (!input.trim()) {
217
+ return 'Tool description is required';
218
+ }
219
+ return true;
220
+ },
221
+ },
222
+ ]);
223
+ tools.push(toolInfo);
224
+ const continueAdding = await inquirer.prompt([
225
+ {
226
+ type: 'confirm',
227
+ name: 'continue',
228
+ message: 'Add another tool?',
229
+ default: false,
230
+ },
231
+ ]);
232
+ addingTools = continueAdding.continue;
233
+ }
234
+ }
235
+ // Add default tool if none were added
236
+ if (tools.length === 0) {
237
+ tools.push({
238
+ name: 'example_tool',
239
+ description: 'An example tool provided by this MCP server',
240
+ });
241
+ }
242
+ return tools;
243
+ }
244
+ getPackageManager(technology) {
245
+ switch (technology) {
246
+ case 'node':
247
+ return 'npm';
248
+ case 'deno':
249
+ return 'deno';
250
+ case 'python':
251
+ return 'pip';
252
+ case 'go':
253
+ return 'go';
254
+ default:
255
+ return 'npm';
256
+ }
257
+ }
258
+ generateSampleQuery(tools) {
259
+ if (tools.length === 0)
260
+ return 'Test the MCP server functionality.';
261
+ const toolNames = tools.map((t) => t.name).join(', ');
262
+ return `Test the MCP server by using the available tools: ${toolNames}. Please demonstrate how each tool works.`;
263
+ }
264
+ isInProjectContext(destination) {
265
+ // Check if we're in an ARK project by looking for common project files
266
+ const projectMarkers = [
267
+ 'Makefile',
268
+ 'Chart.yaml',
269
+ 'agents/',
270
+ 'models/',
271
+ 'mcp-servers/',
272
+ ];
273
+ return projectMarkers.some((marker) => fs.existsSync(path.join(destination, marker)));
274
+ }
275
+ async showSummaryAndConfirm(config) {
276
+ console.log(chalk.cyan('\nšŸ“‹ Configuration Summary\n'));
277
+ console.log(`MCP Server Name: ${chalk.green(config.mcpServerName)}`);
278
+ console.log(`Description: ${config.description}`);
279
+ console.log(`Technology: ${chalk.blue(config.technology)}`);
280
+ console.log(`Package Source: ${config.packageSource}`);
281
+ if (config.packageName) {
282
+ console.log(`Package Name: ${config.packageName}`);
283
+ }
284
+ console.log(`Destination: ${config.destination}`);
285
+ console.log(`Authentication: ${config.requiresAuth ? chalk.red('Required') : chalk.green('Not required')}`);
286
+ console.log(`Custom Config: ${config.hasCustomConfig ? chalk.yellow('Yes') : 'No'}`);
287
+ console.log(`Tools: ${config.tools.map((t) => t.name).join(', ')}`);
288
+ const confirm = await inquirer.prompt([
289
+ {
290
+ type: 'confirm',
291
+ name: 'proceed',
292
+ message: 'Generate MCP server with this configuration?',
293
+ default: true,
294
+ },
295
+ ]);
296
+ if (!confirm.proceed) {
297
+ console.log(chalk.yellow('Operation cancelled.'));
298
+ process.exit(0);
299
+ }
300
+ }
301
+ async generateMcpServer(config) {
302
+ console.log(chalk.blue('\nšŸš€ Generating MCP Server...\n'));
303
+ try {
304
+ const templatePath = this.templateDiscovery.getTemplatePath('mcp-server');
305
+ if (!templatePath) {
306
+ throw new Error('MCP server template not found');
307
+ }
308
+ // Generate from template
309
+ // Set template variables using the same structure expected by templates
310
+ this.templateEngine.setVariables(config);
311
+ await this.templateEngine.processTemplate(templatePath, config.destination);
312
+ // Make build script executable (owner only for security)
313
+ const buildScriptPath = path.join(config.destination, 'build.sh');
314
+ if (fs.existsSync(buildScriptPath)) {
315
+ fs.chmodSync(buildScriptPath, '700'); // rwx------ (owner only)
316
+ }
317
+ console.log(chalk.green(`āœ… MCP server generated successfully at ${config.destination}`));
318
+ }
319
+ catch (error) {
320
+ console.error(chalk.red('Failed to generate MCP server:'), error.message);
321
+ process.exit(1);
322
+ }
323
+ }
324
+ showNextSteps(config) {
325
+ console.log(chalk.cyan('\nšŸŽÆ Next Steps:\n'));
326
+ console.log(`1. Navigate to your MCP server directory:`);
327
+ console.log(chalk.yellow(` cd ${config.destination}`));
328
+ console.log(``);
329
+ console.log(`2. Build the Docker image:`);
330
+ console.log(chalk.yellow(` make build`));
331
+ console.log(``);
332
+ console.log(`3. Install to Kubernetes:`);
333
+ if (config.requiresAuth) {
334
+ console.log(chalk.yellow(` make install AUTH_TOKEN=your-auth-token`));
335
+ }
336
+ else {
337
+ console.log(chalk.yellow(` make install`));
338
+ }
339
+ console.log(``);
340
+ console.log(`4. Check deployment status:`);
341
+ console.log(chalk.yellow(` make status`));
342
+ console.log(``);
343
+ console.log(`5. Deploy example agent and query:`);
344
+ console.log(chalk.yellow(` make deploy-examples`));
345
+ console.log(``);
346
+ console.log(chalk.green('šŸŽ‰ Your MCP server is ready to use!'));
347
+ console.log(``);
348
+ console.log('For more information, see the README.md file in your server directory.');
349
+ }
350
+ }
@@ -0,0 +1,2 @@
1
+ import { Generator } from '../index.js';
2
+ export declare function createProjectGenerator(): Generator;