shipdeck
Version:
Ship MVPs in 48 hours. Fix bugs in 30 seconds. The command deck for developers who ship.
456 lines (386 loc) ⢠13.6 kB
JavaScript
/**
* DAG Workflow Engine Integration for Shipdeck Ultimate
* Integrates the workflow engine with the existing Shipdeck infrastructure
*/
const { ShipdeckWorkflowEngine } = require('./workflow');
const path = require('path');
/**
* Workflow Engine Factory
* Creates and configures workflow engine instances for Shipdeck Ultimate
*/
class WorkflowEngineFactory {
/**
* Create a production-ready workflow engine
*/
static createProductionEngine(config = {}) {
const defaultConfig = {
// State management
stateDir: path.join(process.cwd(), '.shipdeck', 'workflows'),
autoSave: true,
saveInterval: 30000, // 30 seconds
// Execution limits
maxConcurrentWorkflows: 5,
defaultTimeout: 14400000, // 4 hours for complex workflows
// Performance settings
progressTracking: true,
maxConcurrency: 8, // Allow high parallelization
// Integration with existing Anthropic setup
anthropic: {
apiKey: process.env.ANTHROPIC_API_KEY,
model: 'claude-3-sonnet-20240229',
// Use existing token manager if available
tokenManager: config.tokenManager,
// Use existing config manager if available
configManager: config.configManager
}
};
const finalConfig = { ...defaultConfig, ...config };
return new ShipdeckWorkflowEngine(finalConfig);
}
/**
* Create a development/testing engine
*/
static createDevelopmentEngine(config = {}) {
return this.createProductionEngine({
...config,
stateDir: path.join(process.cwd(), '.shipdeck', 'dev-workflows'),
maxConcurrentWorkflows: 2,
saveInterval: 10000, // More frequent saves for development
anthropic: {
...config.anthropic,
// Allow mock mode for development
skipInit: config.mockMode || false
}
});
}
/**
* Create engine with Shipdeck integration
*/
static createIntegratedEngine(shipdeckInstance) {
return this.createProductionEngine({
// Integrate with existing Shipdeck components
anthropic: {
apiKey: shipdeckInstance.anthropicClient?.apiKey,
tokenManager: shipdeckInstance.tokenManager,
configManager: shipdeckInstance.configManager
},
// Use Shipdeck's state directory
stateDir: path.join(shipdeckInstance.configDir || '.shipdeck', 'workflows'),
// Match Shipdeck's performance settings
maxConcurrentWorkflows: shipdeckInstance.maxConcurrency || 5
});
}
}
/**
* Shipdeck Workflow Extension
* Extends the main Shipdeck class with workflow capabilities
*/
class ShipdeckWorkflowExtension {
constructor(shipdeckInstance) {
this.shipdeck = shipdeckInstance;
this.workflowEngine = WorkflowEngineFactory.createIntegratedEngine(shipdeckInstance);
// Setup event forwarding
this.setupIntegration();
}
/**
* Setup integration between Shipdeck and workflow engine
*/
setupIntegration() {
// Forward workflow events to main Shipdeck instance
this.workflowEngine.progressManager.on('workflow:started', (data) => {
this.shipdeck.emit?.('workflow:started', data);
});
this.workflowEngine.progressManager.on('workflow:completed', (data) => {
this.shipdeck.emit?.('workflow:completed', data);
});
this.workflowEngine.progressManager.on('progress:update', (data) => {
this.shipdeck.emit?.('workflow:progress', data);
});
// Add workflow methods to main Shipdeck instance
this.extendShipdeckInstance();
}
/**
* Extend Shipdeck instance with workflow methods
*/
extendShipdeckInstance() {
// Add workflow generation methods
this.shipdeck.generateMVP = this.generateMVP.bind(this);
this.shipdeck.createWorkflow = this.createWorkflow.bind(this);
this.shipdeck.executeWorkflow = this.executeWorkflow.bind(this);
this.shipdeck.getWorkflowStatus = this.getWorkflowStatus.bind(this);
this.shipdeck.listWorkflows = this.listWorkflows.bind(this);
this.shipdeck.getWorkflowMetrics = this.getWorkflowMetrics.bind(this);
}
/**
* Generate complete MVP using workflow engine
*/
async generateMVP(projectConfig = {}) {
console.log(`š Starting 48-hour MVP generation: ${projectConfig.name || 'Unnamed Project'}`);
const mvpConfig = {
name: projectConfig.name || 'MVP Project',
context: {
projectName: projectConfig.name || 'MVP',
techStack: projectConfig.stack || 'Next.js 14, TypeScript, Supabase',
features: projectConfig.features || ['auth', 'dashboard'],
...projectConfig.context
},
maxConcurrency: projectConfig.maxConcurrency || 5,
...projectConfig
};
try {
const result = await this.workflowEngine.generateMVP(mvpConfig);
// Integrate with Shipdeck's result tracking
if (this.shipdeck.trackResult) {
this.shipdeck.trackResult('mvp-generation', result);
}
return result;
} catch (error) {
console.error('ā MVP Generation failed:', error.message);
// Integrate with Shipdeck's error tracking
if (this.shipdeck.trackError) {
this.shipdeck.trackError('mvp-generation', error);
}
throw error;
}
}
/**
* Create workflow from template or custom config
*/
async createWorkflow(config) {
if (typeof config === 'string') {
// Template ID provided
return await this.workflowEngine.createFromTemplate(config);
} else if (config.template) {
// Template with customization
return await this.workflowEngine.createFromTemplate(config.template, config);
} else {
// Custom workflow
return await this.workflowEngine.createCustomWorkflow(config);
}
}
/**
* Execute workflow with Shipdeck integration
*/
async executeWorkflow(workflowId, options = {}) {
console.log(`ā” Executing workflow: ${workflowId}`);
try {
const result = await this.workflowEngine.executeWorkflow(workflowId, options);
// Track successful execution
if (this.shipdeck.trackResult) {
this.shipdeck.trackResult('workflow-execution', {
workflowId,
...result
});
}
return result;
} catch (error) {
// Track failed execution
if (this.shipdeck.trackError) {
this.shipdeck.trackError('workflow-execution', error, { workflowId });
}
throw error;
}
}
/**
* Get workflow status with enhanced information
*/
async getWorkflowStatus(workflowId) {
const status = await this.workflowEngine.getWorkflowStatus(workflowId);
// Enhance with Shipdeck-specific information
if (status && this.shipdeck.enhanceStatus) {
return this.shipdeck.enhanceStatus(status);
}
return status;
}
/**
* List workflows with Shipdeck integration
*/
async listWorkflows() {
const workflows = await this.workflowEngine.listWorkflows();
// Add Shipdeck-specific metadata if available
if (this.shipdeck.enhanceWorkflowList) {
return this.shipdeck.enhanceWorkflowList(workflows);
}
return workflows;
}
/**
* Get comprehensive workflow metrics
*/
async getWorkflowMetrics() {
const metrics = await this.workflowEngine.getMetrics();
// Add Shipdeck-specific metrics
const enhancedMetrics = {
...metrics,
integration: {
shipdeckVersion: this.shipdeck.version || 'unknown',
totalUsage: this.shipdeck.usage || {},
uptime: this.shipdeck.uptime || 0
}
};
return enhancedMetrics;
}
/**
* Cleanup workflows and shutdown
*/
async shutdown() {
console.log('š Shutting down workflow integration...');
try {
// Cleanup old workflows
await this.workflowEngine.cleanup();
// Shutdown workflow engine
await this.workflowEngine.shutdown();
console.log('ā
Workflow integration shutdown complete');
} catch (error) {
console.error('ā Workflow shutdown error:', error.message);
}
}
}
/**
* Workflow CLI Commands
* Command-line interface for workflow operations
*/
class WorkflowCLI {
constructor(workflowEngine) {
this.engine = workflowEngine;
}
/**
* Register CLI commands
*/
registerCommands(program) {
// MVP generation command
program
.command('generate-mvp')
.description('Generate a complete MVP in 48 hours')
.option('-n, --name <name>', 'Project name')
.option('-s, --stack <stack>', 'Technology stack')
.option('-f, --features <features>', 'Comma-separated features')
.option('-c, --concurrency <num>', 'Max concurrency', parseInt, 5)
.action(async (options) => {
try {
const result = await this.engine.generateMVP({
name: options.name,
stack: options.stack,
features: options.features?.split(','),
maxConcurrency: options.concurrency
});
console.log('ā
MVP Generation Complete!');
console.log(`Duration: ${result.mvpStats.hoursUsed} hours`);
console.log(`Efficiency: ${result.mvpStats.efficiency}%`);
} catch (error) {
console.error('ā MVP Generation failed:', error.message);
process.exit(1);
}
});
// Workflow execution command
program
.command('execute-workflow <workflow-id>')
.description('Execute a specific workflow')
.option('-c, --concurrency <num>', 'Max concurrency', parseInt)
.option('-t, --timeout <ms>', 'Timeout in milliseconds', parseInt)
.action(async (workflowId, options) => {
try {
const result = await this.engine.executeWorkflow(workflowId, {
maxConcurrency: options.concurrency,
timeout: options.timeout
});
console.log(`ā
Workflow ${workflowId} completed successfully`);
console.log(`Nodes: ${result.nodes.completed}/${result.nodes.total}`);
} catch (error) {
console.error(`ā Workflow ${workflowId} failed:`, error.message);
process.exit(1);
}
});
// List workflows command
program
.command('list-workflows')
.description('List all workflows')
.option('-s, --status <status>', 'Filter by status')
.action(async (options) => {
try {
let workflows = await this.engine.listWorkflows();
if (options.status) {
workflows = workflows.filter(w => w.status === options.status);
}
console.log(`\nš Found ${workflows.length} workflows:\n`);
workflows.forEach(workflow => {
console.log(`${workflow.isActive ? 'š¢' : 'āŖ'} ${workflow.id}`);
console.log(` Name: ${workflow.name}`);
console.log(` Status: ${workflow.status}`);
console.log(` Nodes: ${workflow.completedCount}/${workflow.nodeCount}`);
console.log(` Started: ${new Date(workflow.startedAt).toLocaleString()}`);
console.log('');
});
} catch (error) {
console.error('ā Failed to list workflows:', error.message);
process.exit(1);
}
});
// Metrics command
program
.command('workflow-metrics')
.description('Show workflow metrics and analytics')
.action(async () => {
try {
const metrics = await this.engine.getMetrics();
console.log('\nš Workflow Metrics:\n');
console.log(`Total Workflows: ${metrics.executor.total}`);
console.log(`Active: ${metrics.executor.active}`);
console.log(`Completed: ${metrics.executor.completed}`);
console.log(`Success Rate: ${metrics.executor.successRate.toFixed(1)}%`);
console.log(`Avg Completion Time: ${(metrics.executor.averageCompletionTime / 1000 / 60).toFixed(1)} minutes`);
console.log(`Available Templates: ${metrics.templates.available}`);
} catch (error) {
console.error('ā Failed to get metrics:', error.message);
process.exit(1);
}
});
}
}
/**
* Integration helper functions
*/
const WorkflowIntegrationHelpers = {
/**
* Initialize workflow engine for Shipdeck
*/
initializeForShipdeck(shipdeckInstance) {
return new ShipdeckWorkflowExtension(shipdeckInstance);
},
/**
* Create standalone workflow engine
*/
createStandaloneEngine(config) {
return WorkflowEngineFactory.createProductionEngine(config);
},
/**
* Setup CLI for workflow operations
*/
setupCLI(workflowEngine, program) {
const cli = new WorkflowCLI(workflowEngine);
cli.registerCommands(program);
return cli;
},
/**
* Quick MVP generation function
*/
async quickMVP(projectName, features = ['auth', 'dashboard']) {
const engine = WorkflowEngineFactory.createProductionEngine();
try {
const result = await engine.generateMVP({
name: projectName,
features
});
await engine.shutdown();
return result;
} catch (error) {
await engine.shutdown();
throw error;
}
}
};
module.exports = {
WorkflowEngineFactory,
ShipdeckWorkflowExtension,
WorkflowCLI,
WorkflowIntegrationHelpers
};