dataweave
Version:
AI-assisted CLI for modern data pipelines with DBT, Dagster, and Supabase integration
568 lines • 24.1 kB
JavaScript
#!/usr/bin/env node
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const commander_1 = require("commander");
const chalk_1 = __importDefault(require("chalk"));
const ora_1 = __importDefault(require("ora"));
const path_1 = require("path");
const fs_1 = require("fs");
const promises_1 = require("fs/promises");
const scaffolding_1 = require("./scaffolding");
const dbt_1 = require("./dbt");
const dagster_1 = require("./dagster");
const ai_1 = require("./ai");
const packageJson = require('../package.json');
const version = packageJson.version;
const program = new commander_1.Command();
async function loadDataweaveConfig() {
const configPath = (0, path_1.join)(process.cwd(), '.dataweave', 'config.json');
if (!(0, fs_1.existsSync)(configPath)) {
throw new Error('No dataweave project found. Run "dataweave init" first.');
}
try {
const configContent = await (0, promises_1.readFile)(configPath, 'utf-8');
return JSON.parse(configContent);
}
catch (error) {
throw new Error(`Failed to load dataweave config: ${error instanceof Error ? error.message : String(error)}`);
}
}
async function createDbtManager() {
await loadDataweaveConfig();
return new dbt_1.DbtManager({
projectPath: process.cwd(),
profilesDir: (0, path_1.join)(process.cwd(), 'config'),
modelsDir: (0, path_1.join)(process.cwd(), 'data', 'dbt', 'models'),
});
}
async function createDagsterManager() {
await loadDataweaveConfig();
return new dagster_1.DagsterManager({
projectPath: process.cwd(),
dagsterPath: (0, path_1.join)(process.cwd(), 'data', 'dagster'),
assetsPath: (0, path_1.join)(process.cwd(), 'data', 'dagster', 'assets'),
jobsPath: (0, path_1.join)(process.cwd(), 'data', 'dagster', 'jobs'),
});
}
async function createAIEngine() {
const config = await loadDataweaveConfig();
return new ai_1.AIEngine({
provider: config.ai?.provider || 'openai',
apiKey: process.env.OPENAI_API_KEY,
model: config.ai?.model || 'gpt-4',
temperature: config.ai?.temperature || 0.7,
maxTokens: config.ai?.maxTokens || 2000,
});
}
const logo = `
${chalk_1.default.cyan('╔═══════════════════════════════════════╗')}
${chalk_1.default.cyan('║')} ${chalk_1.default.bold.white('dataweave')} ${chalk_1.default.gray(`v${version}`)} ${chalk_1.default.cyan('║')}
${chalk_1.default.cyan('║')} ${chalk_1.default.gray('AI-Assisted Data Pipeline CLI')} ${chalk_1.default.cyan('║')}
${chalk_1.default.cyan('╚═══════════════════════════════════════╝')}
`;
program
.name('dataweave')
.description('AI-assisted CLI for modern data pipelines with DBT, Dagster, and Supabase integration')
.version(version);
program
.command('init [name]')
.description('Initialize a new dataweave project')
.option('-t, --template <template>', 'Project template', 'default')
.option('--no-dbt', 'Skip DBT setup')
.option('--no-dagster', 'Skip Dagster setup')
.option('--no-supabase', 'Skip Supabase setup')
.action(async (name, options) => {
console.log(logo);
const projectName = name || 'my-dataweave-project';
const targetDir = (0, path_1.resolve)(process.cwd(), projectName);
if ((0, fs_1.existsSync)(targetDir)) {
console.error(chalk_1.default.red(`\n❌ Directory ${projectName} already exists!`));
process.exit(1);
}
const spinner = (0, ora_1.default)('Initializing dataweave project...').start();
try {
const scaffolder = new scaffolding_1.ProjectScaffolder({
name: projectName,
template: options.template,
targetDir,
includeDbt: options.dbt !== false,
includeDagster: options.dagster !== false,
includeSupabase: options.supabase !== false,
});
await scaffolder.scaffold();
spinner.succeed('Project initialized successfully!');
}
catch (error) {
spinner.fail('Failed to initialize project');
console.error(chalk_1.default.red(`\n❌ Error: ${error instanceof Error ? error.message : String(error)}`));
process.exit(1);
}
});
program
.command('dbt:model:new <name>')
.description('Generate a new DBT model')
.option('-s, --sql <sql>', 'SQL content for the model')
.option('-d, --description <desc>', 'Model description')
.option('-m, --materialized <type>', 'Materialization type (table, view, incremental)', 'view')
.option('--tags <tags>', 'Comma-separated list of tags')
.action(async (name, options) => {
console.log(logo);
const spinner = (0, ora_1.default)('Generating DBT model...').start();
try {
const dbtManager = await createDbtManager();
const modelOptions = {
name,
sql: options.sql,
description: options.description,
materializedAs: options.materialized,
tags: options.tags ? options.tags.split(',').map((t) => t.trim()) : [],
};
await dbtManager.generateModel(modelOptions);
spinner.succeed(`Generated DBT model: ${name}`);
}
catch (error) {
spinner.fail('Failed to generate DBT model');
console.error(chalk_1.default.red(`❌ Error: ${error instanceof Error ? error.message : String(error)}`));
process.exit(1);
}
});
program
.command('dbt:run [model]')
.description('Run DBT models')
.action(async (model) => {
console.log(logo);
const spinner = (0, ora_1.default)('Running DBT models...').start();
try {
const dbtManager = await createDbtManager();
await dbtManager.runModel(model);
spinner.succeed('DBT models executed successfully');
}
catch (error) {
spinner.fail('Failed to run DBT models');
console.error(chalk_1.default.red(`❌ Error: ${error instanceof Error ? error.message : String(error)}`));
process.exit(1);
}
});
program
.command('dbt:test [model]')
.description('Test DBT models')
.action(async (model) => {
console.log(logo);
const spinner = (0, ora_1.default)('Testing DBT models...').start();
try {
const dbtManager = await createDbtManager();
await dbtManager.testModel(model);
spinner.succeed('DBT tests passed');
}
catch (error) {
spinner.fail('DBT tests failed');
console.error(chalk_1.default.red(`❌ Error: ${error instanceof Error ? error.message : String(error)}`));
process.exit(1);
}
});
program
.command('dbt:compile [model]')
.description('Compile DBT models')
.action(async (model) => {
console.log(logo);
const spinner = (0, ora_1.default)('Compiling DBT models...').start();
try {
const dbtManager = await createDbtManager();
await dbtManager.compileModel(model);
spinner.succeed('DBT models compiled successfully');
}
catch (error) {
spinner.fail('Failed to compile DBT models');
console.error(chalk_1.default.red(`❌ Error: ${error instanceof Error ? error.message : String(error)}`));
process.exit(1);
}
});
program
.command('dbt:docs')
.description('Generate and serve DBT documentation')
.action(async () => {
console.log(logo);
const spinner = (0, ora_1.default)('Generating DBT documentation...').start();
try {
const dbtManager = await createDbtManager();
await dbtManager.generateDocs();
spinner.succeed('DBT documentation generated');
}
catch (error) {
spinner.fail('Failed to generate DBT documentation');
console.error(chalk_1.default.red(`❌ Error: ${error instanceof Error ? error.message : String(error)}`));
process.exit(1);
}
});
program
.command('dbt:introspect')
.description('Introspect database schema')
.action(async () => {
console.log(logo);
const spinner = (0, ora_1.default)('Introspecting database schema...').start();
try {
const dbtManager = await createDbtManager();
const result = await dbtManager.introspectDatabase();
spinner.succeed('Database introspection completed');
if (result) {
console.log(chalk_1.default.gray('\nDatabase schema information:'));
console.log(result);
}
}
catch (error) {
spinner.fail('Failed to introspect database');
console.error(chalk_1.default.red(`❌ Error: ${error instanceof Error ? error.message : String(error)}`));
process.exit(1);
}
});
program
.command('dagster:asset:new <name>')
.description('Generate a new Dagster asset')
.option('-d, --description <desc>', 'Asset description')
.option('--deps <dependencies>', 'Comma-separated list of dependencies')
.option('--code <code>', 'Python code for the asset')
.option('--schedule <schedule>', 'Cron schedule for the asset')
.option('--tags <tags>', 'Comma-separated list of tags')
.option('--compute-kind <kind>', 'Compute kind (e.g., pandas, spark)')
.option('--io-manager <manager>', 'IO manager key')
.action(async (name, options) => {
console.log(logo);
const spinner = (0, ora_1.default)('Generating Dagster asset...').start();
try {
const dagsterManager = await createDagsterManager();
const assetOptions = {
name,
description: options.description,
dependencies: options.deps ? options.deps.split(',').map((d) => d.trim()) : [],
code: options.code,
schedule: options.schedule,
tags: options.tags ? options.tags.split(',').map((t) => t.trim()) : [],
compute_kind: options.computeKind,
io_manager: options.ioManager,
};
await dagsterManager.generateAsset(assetOptions);
spinner.succeed(`Generated Dagster asset: ${name}`);
}
catch (error) {
spinner.fail('Failed to generate Dagster asset');
console.error(chalk_1.default.red(`❌ Error: ${error instanceof Error ? error.message : String(error)}`));
process.exit(1);
}
});
program
.command('dagster:job:new <name>')
.description('Generate a new Dagster job')
.option('-d, --description <desc>', 'Job description')
.option('--assets <assets>', 'Comma-separated list of assets')
.option('--schedule <schedule>', 'Cron schedule for the job')
.option('--tags <tags>', 'Comma-separated list of tags')
.action(async (name, options) => {
console.log(logo);
const spinner = (0, ora_1.default)('Generating Dagster job...').start();
try {
const dagsterManager = await createDagsterManager();
const jobOptions = {
name,
description: options.description,
assets: options.assets ? options.assets.split(',').map((a) => a.trim()) : [],
schedule: options.schedule,
tags: options.tags ? options.tags.split(',').map((t) => t.trim()) : [],
};
await dagsterManager.generateJob(jobOptions);
spinner.succeed(`Generated Dagster job: ${name}`);
}
catch (error) {
spinner.fail('Failed to generate Dagster job');
console.error(chalk_1.default.red(`❌ Error: ${error instanceof Error ? error.message : String(error)}`));
process.exit(1);
}
});
program
.command('dagster:dbt:asset <model>')
.description('Generate a Dagster asset for a DBT model')
.action(async (model) => {
console.log(logo);
const spinner = (0, ora_1.default)('Generating Dagster asset for DBT model...').start();
try {
const dagsterManager = await createDagsterManager();
await dagsterManager.generateDbtAsset(model);
spinner.succeed(`Generated Dagster asset for DBT model: ${model}`);
}
catch (error) {
spinner.fail('Failed to generate Dagster asset for DBT model');
console.error(chalk_1.default.red(`❌ Error: ${error instanceof Error ? error.message : String(error)}`));
process.exit(1);
}
});
program
.command('dagster:run:asset <name>')
.description('Run a specific Dagster asset')
.action(async (name) => {
console.log(logo);
const spinner = (0, ora_1.default)(`Running Dagster asset: ${name}...`).start();
try {
const dagsterManager = await createDagsterManager();
await dagsterManager.runAsset(name);
spinner.succeed(`Dagster asset executed: ${name}`);
}
catch (error) {
spinner.fail('Failed to run Dagster asset');
console.error(chalk_1.default.red(`❌ Error: ${error instanceof Error ? error.message : String(error)}`));
process.exit(1);
}
});
program
.command('dagster:run:job <name>')
.description('Run a specific Dagster job')
.action(async (name) => {
console.log(logo);
const spinner = (0, ora_1.default)(`Running Dagster job: ${name}...`).start();
try {
const dagsterManager = await createDagsterManager();
await dagsterManager.runJob(name);
spinner.succeed(`Dagster job executed: ${name}`);
}
catch (error) {
spinner.fail('Failed to run Dagster job');
console.error(chalk_1.default.red(`❌ Error: ${error instanceof Error ? error.message : String(error)}`));
process.exit(1);
}
});
program
.command('dagster:dev')
.description('Start Dagster development server')
.option('-p, --port <port>', 'Port number', '3000')
.action(async (options) => {
console.log(logo);
const spinner = (0, ora_1.default)('Starting Dagster development server...').start();
try {
const dagsterManager = await createDagsterManager();
await dagsterManager.startDagster(parseInt(options.port));
spinner.succeed('Dagster development server started');
}
catch (error) {
spinner.fail('Failed to start Dagster development server');
console.error(chalk_1.default.red(`❌ Error: ${error instanceof Error ? error.message : String(error)}`));
process.exit(1);
}
});
program
.command('dagster:validate')
.description('Validate Dagster pipeline configuration')
.action(async () => {
console.log(logo);
const spinner = (0, ora_1.default)('Validating Dagster pipeline...').start();
try {
const dagsterManager = await createDagsterManager();
await dagsterManager.validatePipeline();
spinner.succeed('Dagster pipeline validation passed');
}
catch (error) {
spinner.fail('Dagster pipeline validation failed');
console.error(chalk_1.default.red(`❌ Error: ${error instanceof Error ? error.message : String(error)}`));
process.exit(1);
}
});
program
.command('scaffold <type>')
.description('Scaffold a new component (model, asset, job, etc.)')
.action(async (type) => {
console.log(logo);
console.log(chalk_1.default.blue(`📦 Scaffolding ${type}...`));
console.log(chalk_1.default.yellow('\n🚧 Coming soon: AI-powered scaffolding for:'));
console.log(chalk_1.default.gray(' • DBT models'));
console.log(chalk_1.default.gray(' • Dagster assets'));
console.log(chalk_1.default.gray(' • Pipeline jobs'));
console.log(chalk_1.default.gray(' • Tests and documentation'));
});
program
.command('ai:generate:dbt <prompt>')
.description('Generate a DBT model using AI')
.option('-n, --name <name>', 'Model name')
.option('--tables <tables>', 'Comma-separated list of available tables')
.action(async (prompt, options) => {
console.log(logo);
const spinner = (0, ora_1.default)('Generating DBT model with AI...').start();
try {
const aiEngine = await createAIEngine();
const dbtManager = await createDbtManager();
const context = {
projectName: 'dataweave',
tables: options.tables ? options.tables.split(',').map((t) => ({
name: t.trim(),
columns: []
})) : [],
};
const result = await aiEngine.generateDbtModel(prompt, context);
if (options.name) {
await dbtManager.generateModel({
name: options.name,
sql: result.sql,
description: result.description,
});
spinner.succeed(`Generated and created DBT model: ${options.name}`);
}
else {
spinner.succeed('DBT model generated');
console.log(chalk_1.default.blue('\n📊 Generated SQL:'));
console.log(result.sql);
console.log(chalk_1.default.blue('\n📝 Description:'));
console.log(result.description);
console.log(chalk_1.default.gray('\nTo create this model, run:'));
console.log(chalk_1.default.gray(`dataweave dbt:model:new <name> --sql "${result.sql.replace(/"/g, '\\"')}"`));
}
}
catch (error) {
spinner.fail('Failed to generate DBT model');
console.error(chalk_1.default.red(`❌ Error: ${error instanceof Error ? error.message : String(error)}`));
process.exit(1);
}
});
program
.command('ai:generate:dagster <prompt>')
.description('Generate a Dagster asset using AI')
.option('-n, --name <name>', 'Asset name')
.option('--tables <tables>', 'Comma-separated list of available tables')
.action(async (prompt, options) => {
console.log(logo);
const spinner = (0, ora_1.default)('Generating Dagster asset with AI...').start();
try {
const aiEngine = await createAIEngine();
const dagsterManager = await createDagsterManager();
const context = {
projectName: 'dataweave',
tables: options.tables ? options.tables.split(',').map((t) => ({
name: t.trim(),
columns: []
})) : [],
};
const result = await aiEngine.generateDagsterAsset(prompt, context);
if (options.name) {
await dagsterManager.generateAsset({
name: options.name,
code: result.code,
description: result.description,
});
spinner.succeed(`Generated and created Dagster asset: ${options.name}`);
}
else {
spinner.succeed('Dagster asset generated');
console.log(chalk_1.default.blue('\n⚡ Generated Python Code:'));
console.log(result.code);
console.log(chalk_1.default.blue('\n📝 Description:'));
console.log(result.description);
console.log(chalk_1.default.gray('\nTo create this asset, run:'));
console.log(chalk_1.default.gray(`dataweave dagster:asset:new <name> --code "${result.code.replace(/"/g, '\\"')}"`));
}
}
catch (error) {
spinner.fail('Failed to generate Dagster asset');
console.error(chalk_1.default.red(`❌ Error: ${error instanceof Error ? error.message : String(error)}`));
process.exit(1);
}
});
program
.command('ai:explain <file>')
.description('Explain code using AI')
.action(async (file) => {
console.log(logo);
const spinner = (0, ora_1.default)('Analyzing code with AI...').start();
try {
const filePath = (0, path_1.resolve)(process.cwd(), file);
if (!(0, fs_1.existsSync)(filePath)) {
throw new Error(`File not found: ${file}`);
}
const code = await (0, promises_1.readFile)(filePath, 'utf-8');
const codeType = file.endsWith('.sql') ? 'sql' : 'python';
const aiEngine = await createAIEngine();
const explanation = await aiEngine.explainCode(code, codeType);
spinner.succeed('Code explanation generated');
console.log(chalk_1.default.blue('\n🤖 AI Explanation:'));
console.log(explanation);
}
catch (error) {
spinner.fail('Failed to explain code');
console.error(chalk_1.default.red(`❌ Error: ${error instanceof Error ? error.message : String(error)}`));
process.exit(1);
}
});
program
.command('ai:optimize <file>')
.description('Get optimization suggestions using AI')
.action(async (file) => {
console.log(logo);
const spinner = (0, ora_1.default)('Analyzing code for optimizations...').start();
try {
const filePath = (0, path_1.resolve)(process.cwd(), file);
if (!(0, fs_1.existsSync)(filePath)) {
throw new Error(`File not found: ${file}`);
}
const code = await (0, promises_1.readFile)(filePath, 'utf-8');
const codeType = file.endsWith('.sql') ? 'sql' : 'python';
const aiEngine = await createAIEngine();
const suggestions = await aiEngine.optimizeCode(code, codeType);
spinner.succeed('Optimization suggestions generated');
console.log(chalk_1.default.blue('\n🚀 AI Optimization Suggestions:'));
console.log(suggestions);
}
catch (error) {
spinner.fail('Failed to generate optimization suggestions');
console.error(chalk_1.default.red(`❌ Error: ${error instanceof Error ? error.message : String(error)}`));
process.exit(1);
}
});
program
.command('ai:document <model>')
.description('Generate documentation for a DBT model using AI')
.action(async (model) => {
console.log(logo);
const spinner = (0, ora_1.default)('Generating documentation with AI...').start();
try {
const stagingPath = (0, path_1.join)(process.cwd(), 'data', 'dbt', 'models', 'staging', `${model}.sql`);
if (!(0, fs_1.existsSync)(stagingPath)) {
throw new Error(`DBT model not found: ${model}`);
}
const sql = await (0, promises_1.readFile)(stagingPath, 'utf-8');
const aiEngine = await createAIEngine();
const documentation = await aiEngine.generateDocumentation(model, sql);
spinner.succeed('Documentation generated');
console.log(chalk_1.default.blue('\n📚 AI-Generated Documentation:'));
console.log(documentation);
console.log(chalk_1.default.gray('\nSave this documentation to your model\'s schema.yml or README.md'));
}
catch (error) {
spinner.fail('Failed to generate documentation');
console.error(chalk_1.default.red(`❌ Error: ${error instanceof Error ? error.message : String(error)}`));
process.exit(1);
}
});
program
.command('info')
.description('Display information about dataweave')
.action(() => {
console.log(logo);
console.log(chalk_1.default.bold('\n📊 About dataweave'));
console.log(chalk_1.default.gray('\nDataweave is an AI-assisted CLI for building modern data pipelines.'));
console.log(chalk_1.default.gray('It seamlessly integrates DBT, Dagster, and Supabase with intelligent'));
console.log(chalk_1.default.gray('code generation and scaffolding capabilities.'));
console.log(chalk_1.default.gray('\nDesigned for data engineers, ML engineers, and indie developers who'));
console.log(chalk_1.default.gray('want to accelerate their data pipeline development with AI assistance.'));
console.log(chalk_1.default.blue('\n🔗 Links:'));
console.log(chalk_1.default.gray(' Documentation: Coming soon'));
console.log(chalk_1.default.gray(' GitHub: https://github.com/yourusername/dataweave'));
console.log(chalk_1.default.gray(' npm: https://www.npmjs.com/package/dataweave'));
});
program.on('command:*', () => {
console.error(chalk_1.default.red('\nInvalid command: %s'), program.args.join(' '));
console.log('See --help for a list of available commands.\n');
process.exit(1);
});
if (!process.argv.slice(2).length) {
console.log(logo);
program.outputHelp();
}
program.parse(process.argv);
//# sourceMappingURL=cli.js.map