#!/usr/bin/env node
/**
* DevContainer MCP CLI Tool
* Standalone command-line interface for DevContainer management
*/
import { Command } from 'commander';
import { ConfigGenerator } from './config-generator.js';
import { DevContainerManager } from './devcontainer-manager.js';
import { TemplateManager } from './template-manager.js';
const program = new Command();
// Initialize components
const configGenerator = new ConfigGenerator();
const containerManager = new DevContainerManager();
const templateManager = new TemplateManager();
program
.name('devcontainer-mcp-cli')
.description('CLI tool for DevContainer management with natural language support')
.version('1.0.0');
// Generate command
program
.command('generate')
.description('Generate DevContainer configuration from natural language')
.argument('<prompt>', 'Natural language description of the development environment')
.option('-w, --workspace <path>', 'Workspace root path', '.')
.option('-t, --template <name>', 'Base template to use')
.action(async (prompt: string, options: { workspace: string; template?: string }) => {
try {
console.log('π Generating DevContainer configuration...');
const result = await configGenerator.generateFromPrompt(
prompt,
options.workspace,
options.template
);
console.log('β
DevContainer configuration generated successfully!\n');
console.log(`π Configuration saved to: ${result.path}`);
console.log(`π Template used: ${result.template}`);
console.log(`π Reasoning: ${result.reasoning}\n`);
console.log('π Analysis:');
if (result.analysis.languages.length > 0) {
console.log(` Languages: ${result.analysis.languages.join(', ')}`);
}
if (result.analysis.frameworks.length > 0) {
console.log(` Frameworks: ${result.analysis.frameworks.join(', ')}`);
}
if (result.analysis.databases.length > 0) {
console.log(` Databases: ${result.analysis.databases.join(', ')}`);
}
if (result.analysis.ports.length > 0) {
console.log(` Ports: ${result.analysis.ports.join(', ')}`);
}
console.log('\nπ‘ Next steps:');
console.log(' 1. Review the generated configuration');
console.log(' 2. Run "devcontainer-mcp-cli build" to build the container');
console.log(' 3. Run "devcontainer-mcp-cli test" to verify functionality');
} catch (error) {
console.error('β Error generating configuration:', error instanceof Error ? error.message : String(error));
process.exit(1);
}
});
// Build command
program
.command('build')
.description('Build DevContainer from configuration')
.option('-w, --workspace <path>', 'Workspace root path', '.')
.option('-c, --config <path>', 'Custom configuration file path')
.option('-r, --rebuild', 'Force rebuild without cache', false)
.action(async (options: { workspace: string; config?: string; rebuild: boolean }) => {
try {
console.log('π Building DevContainer...');
const result = await containerManager.buildContainer(
options.workspace,
options.config,
options.rebuild
);
if (result.success) {
console.log(`β
DevContainer built successfully in ${Math.round(result.duration / 1000)}s!`);
if (result.output) {
console.log('\nπ Build output:');
console.log(result.output);
}
console.log('\nπ‘ Next steps:');
console.log(' 1. Run "devcontainer-mcp-cli test" to verify functionality');
console.log(' 2. Open your project in VS Code with the DevContainer extension');
} else {
console.error(`β DevContainer build failed after ${Math.round(result.duration / 1000)}s`);
if (result.error) {
console.error('\nπ Error details:');
console.error(result.error);
}
if (result.output) {
console.error('\nπ Build output:');
console.error(result.output);
}
process.exit(1);
}
} catch (error) {
console.error('β Error building container:', error instanceof Error ? error.message : String(error));
process.exit(1);
}
});
// Test command
program
.command('test')
.description('Test DevContainer functionality')
.option('-w, --workspace <path>', 'Workspace root path', '.')
.option('-c, --command <cmd>', 'Custom test command', [])
.action(async (options: { workspace: string; command: string[] }) => {
try {
console.log('π Testing DevContainer...');
const testCommands = Array.isArray(options.command) ? options.command : [options.command].filter(Boolean);
const result = await containerManager.testContainer(
options.workspace,
testCommands.length > 0 ? testCommands : undefined
);
console.log(`${result.success ? 'β
' : 'β'} Test Summary: ${result.summary}\n`);
console.log('π Test Results:');
for (const test of result.tests) {
const status = test.success ? 'β
' : 'β';
console.log(` ${status} ${test.name}`);
if (test.output) {
console.log(` Output: ${test.output}`);
}
if (test.error) {
console.log(` Error: ${test.error}`);
}
}
if (!result.success) {
console.log('\nπ‘ Some tests failed. Please review the errors and fix any issues.');
process.exit(1);
} else {
console.log('\nπ All tests passed! Your DevContainer is working correctly.');
}
} catch (error) {
console.error('β Error testing container:', error instanceof Error ? error.message : String(error));
process.exit(1);
}
});
// Templates command
program
.command('templates')
.description('List available DevContainer templates')
.option('-c, --category <category>', 'Filter by category')
.action(async (options: { category?: string }) => {
try {
const templates = templateManager.getTemplates(
options.category ? { category: options.category } : undefined
);
const categories = templateManager.getCategories();
console.log('π Available DevContainer Templates\n');
if (options.category) {
console.log(`π·οΈ Category: ${options.category}\n`);
} else {
console.log(`π·οΈ Categories: ${categories.join(', ')}\n`);
}
for (const template of templates) {
const summary = templateManager.getTemplateSummary(template);
console.log(`π§ ${summary.name} (${summary.category})`);
console.log(` ${summary.description}`);
console.log(` Languages: ${(summary.languages as string[]).join(', ')}`);
console.log(` Frameworks: ${(summary.frameworks as string[]).join(', ')}`);
console.log(` Features: ${(summary.features as string[]).join(', ')}\n`);
}
console.log('π‘ Use any template name with the generate command:');
console.log(' devcontainer-mcp-cli generate "your prompt" --template <template-name>');
} catch (error) {
console.error('β Error listing templates:', error instanceof Error ? error.message : String(error));
process.exit(1);
}
});
// Status command
program
.command('status')
.description('Check DevContainer status')
.option('-w, --workspace <path>', 'Workspace root path', '.')
.action(async (options: { workspace: string }) => {
try {
const status = await containerManager.getContainerStatus(options.workspace);
const statusIcon = status.configExists ? (status.isRunning ? 'π’' : 'π‘') : 'π΄';
const statusText = status.configExists
? (status.isRunning ? 'Running' : 'Stopped')
: 'Not configured';
console.log(`${statusIcon} DevContainer Status: ${statusText}\n`);
console.log('π Configuration:');
console.log(` Exists: ${status.configExists ? 'β
' : 'β'}`);
console.log(` Path: ${status.configPath || 'Not found'}\n`);
console.log('π³ Container:');
console.log(` Running: ${status.isRunning ? 'β
' : 'β'}`);
console.log(` Name: ${status.containerName || 'Unknown'}`);
console.log(` Image: ${status.image || 'Unknown'}`);
console.log(` Last Build: ${status.lastBuildTime ? status.lastBuildTime.toLocaleString() : 'Unknown'}\n`);
if (!status.configExists) {
console.log('π‘ Next steps:');
console.log(' 1. Run "devcontainer-mcp-cli generate <description>" to create a configuration');
} else if (!status.isRunning) {
console.log('π‘ Next steps:');
console.log(' 1. Run "devcontainer-mcp-cli build" to build and start the container');
} else {
console.log('π Container is ready for development!');
}
} catch (error) {
console.error('β Error checking status:', error instanceof Error ? error.message : String(error));
process.exit(1);
}
});
// Modify command
program
.command('modify')
.description('Modify existing DevContainer configuration')
.argument('<modifications>', 'Natural language description of desired changes')
.option('-w, --workspace <path>', 'Workspace root path', '.')
.action(async (modifications: string, options: { workspace: string }) => {
try {
console.log('π Modifying DevContainer configuration...');
const result = await configGenerator.modifyConfiguration(
options.workspace,
modifications
);
console.log('β
DevContainer configuration modified successfully!\n');
console.log(`π Configuration updated: ${result.path}`);
console.log(`π Changes: ${result.reasoning}\n`);
console.log('π Modifications applied:');
if (result.analysis.languages.length > 0) {
console.log(` Languages: ${result.analysis.languages.join(', ')}`);
}
if (result.analysis.frameworks.length > 0) {
console.log(` Frameworks: ${result.analysis.frameworks.join(', ')}`);
}
if (result.analysis.databases.length > 0) {
console.log(` Databases: ${result.analysis.databases.join(', ')}`);
}
if (result.analysis.ports.length > 0) {
console.log(` Ports: ${result.analysis.ports.join(', ')}`);
}
console.log('\nπ‘ Next steps:');
console.log(' 1. Review the updated configuration');
console.log(' 2. Run "devcontainer-mcp-cli build --rebuild" to apply changes');
} catch (error) {
console.error('β Error modifying configuration:', error instanceof Error ? error.message : String(error));
process.exit(1);
}
});
// Error handling
program.configureHelp({
sortSubcommands: true,
});
program.parse();