Layer 4: Blueprint Executor
VFS Management & Action Orchestration
The Blueprint Executor is the intelligence layer that analyzes blueprints, manages VFS pre-population, expands forEach actions, and delegates to action handlers.
Core Responsibilities
- Blueprint Analysis - Determine what files the blueprint needs
- VFS Pre-population - Load required files from disk into VFS
- forEach Expansion - Expand loop actions into individual actions
- Action Delegation - Route each action to appropriate handler
- Error Handling - Fail-fast on any error
Implementation
// src/core/services/execution/blueprint/blueprint-executor.ts
export class BlueprintExecutor {
private modifierRegistry: ModifierRegistry;
private actionHandlerRegistry: ActionHandlerRegistry;
private blueprintAnalyzer: BlueprintAnalyzer;
async executeBlueprint(
blueprint: Blueprint,
context: ProjectContext,
vfs: VirtualFileSystem
): Promise<BlueprintExecutionResult> {
// 1. Analyze blueprint
const analysis = this.blueprintAnalyzer.analyzeBlueprint(blueprint, context);
// 2. Pre-populate VFS
if (analysis.filesToRead.length > 0) {
await vfs.initializeWithFiles(analysis.filesToRead);
}
// 3. Expand forEach actions
const expandedActions = this.expandForEachActions(blueprint.actions, context);
// 4. Execute all actions
for (const action of expandedActions) {
const result = await this.actionHandlerRegistry.handleAction(
action, context, projectRoot, vfs
);
if (!result.success) {
return { success: false, errors: [result.error] };
}
}
return { success: true, files: [...], errors: [], warnings: [] };
}
}Blueprint Analysis
Purpose
Determine what files a blueprint will need to access before it runs.
Implementation
// src/core/services/project/blueprint-analyzer/blueprint-analyzer.ts
export class BlueprintAnalyzer {
analyzeBlueprint(blueprint: Blueprint, context: ProjectContext) {
const filesToRead = new Set<string>();
// 1. Add explicitly declared contextual files
if (blueprint.contextualFiles) {
blueprint.contextualFiles.forEach(f => filesToRead.add(f));
}
// 2. Scan actions for file references
blueprint.actions.forEach(action => {
if (action.type === 'ENHANCE_FILE' && action.path) {
filesToRead.add(action.path);
}
if (action.type === 'MERGE_JSON' && action.path) {
filesToRead.add(action.path);
}
// ... scan other action types
});
return {
filesToRead: Array.from(filesToRead),
requiresVFS: filesToRead.size > 0
};
}
}Result example:
{
filesToRead: ['package.json', 'tsconfig.json', 'src/app/layout.tsx'],
requiresVFS: true
}forEach Expansion
Purpose
Avoid repetitive actions in blueprints.
Example
Blueprint:
{
type: 'CREATE_FILE',
forEach: 'module.parameters.components', // ['button', 'card', 'dialog']
path: 'components/ui/{{item}}.tsx',
template: 'component.ejs'
}Expansion:
private expandForEachActions(actions: BlueprintAction[], context) {
const expanded = [];
for (const action of actions) {
if (action.forEach) {
// Resolve array path
const items = this.resolveForEachPath(action.forEach, context);
// items = ['button', 'card', 'dialog']
// Create action for each item
items.forEach(item => {
const newAction = {
...action,
path: action.path.replace(/\{\{item\}\}/g, item),
// Replace {{item}} in all string properties
};
expanded.push(newAction);
});
} else {
expanded.push(action);
}
}
return expanded;
}Result:
[
{ type: 'CREATE_FILE', path: 'components/ui/button.tsx', template: 'component.ejs' },
{ type: 'CREATE_FILE', path: 'components/ui/card.tsx', template: 'component.ejs' },
{ type: 'CREATE_FILE', path: 'components/ui/dialog.tsx', template: 'component.ejs' }
]