cortexweaver
Version:
CortexWeaver is a command-line interface (CLI) tool that orchestrates a swarm of specialized AI agents, powered by Claude Code and Gemini CLI, to assist in software development. It transforms a high-level project plan (plan.md) into a series of coordinate
437 lines (428 loc) • 19.1 kB
JavaScript
;
/**
* Architect Agent Core Logic
*
* Contains the main architectural design logic and analysis functionality
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.ArchitectCore = void 0;
class ArchitectCore {
constructor(agent) {
this.agent = agent;
}
/**
* Query Cognitive Canvas for existing architectural patterns and decisions
*/
async queryExistingPatterns() {
const cognitiveCanvas = this.agent.getCognitiveCanvas();
const currentTask = this.agent.getCurrentTask();
if (!cognitiveCanvas || !currentTask) {
return { decisions: [], similarTasks: [] };
}
try {
const [decisions, similarTasks] = await Promise.all([
cognitiveCanvas.getArchitecturalDecisionsByProject(currentTask.projectId),
cognitiveCanvas.findSimilarTasks(currentTask.id, [currentTask.title, ...currentTask.description.split(' ').slice(0, 10)])
]);
return { decisions, similarTasks };
}
catch (error) {
console.warn('Failed to query existing patterns:', error.message);
return { decisions: [], similarTasks: [] };
}
}
/**
* Generate comprehensive architectural design using Claude API
*/
async generateArchitecturalDesign(patterns) {
// Process formal contracts if available
const taskContext = this.agent.getTaskContext();
const formalContracts = taskContext?.formalContracts;
const contractContext = this.buildContractContext(formalContracts);
const currentTask = this.agent.getCurrentTask();
const prompt = this.agent.formatPrompt(this.getPromptTemplate(), {
task: currentTask.description,
context: JSON.stringify(taskContext, null, 2),
projectName: taskContext?.projectInfo?.name || 'Unknown Project',
existingDecisions: patterns.decisions.map(d => `- ${d.title}: ${d.description}`).join('\n'),
similarPatterns: patterns.similarTasks.map(t => `- ${t.title}: ${t.description}`).join('\n'),
...contractContext
});
const systemPrompt = formalContracts ?
'You are an expert software architect specializing in contract-driven development. Provide detailed, practical architectural designs that align with formal contracts (OpenAPI specs, JSON schemas) while maintaining clear documentation and visual diagrams.' :
'You are an expert software architect. Provide detailed, practical architectural designs with clear documentation and visual diagrams.';
const response = await this.agent.sendToClaude(prompt, {
maxTokens: 8000,
temperature: 0.3,
systemPrompt
});
const analysis = this.parseArchitecturalResponse(response.content);
// Add contract compliance analysis if contracts were provided
if (formalContracts) {
analysis.contractCompliance = this.analyzeContractCompliance(formalContracts, analysis);
}
return analysis;
}
/**
* Get architect-specific prompt template
*/
getPromptTemplate() {
return `You are an expert software architect tasked with creating comprehensive architectural designs.
TASK: {{task}}
CONTEXT: {{context}}
PROJECT: {{projectName}}
{{contractSection}}
Please provide a detailed architectural design that includes:
1. **System Overview**: High-level description of the system architecture
2. **Component Design**: Individual components and their responsibilities
3. **Data Models**: Database schemas and data structures
4. **API Specifications**: RESTful endpoints and contracts (OpenAPI format when applicable)
5. **Mermaid Diagrams**: Visual representations of the architecture
6. **Architectural Decisions**: Key design decisions with rationale
{{contractComplianceSection}}
## Requirements:
- Use Mermaid.js syntax for all diagrams
- Provide OpenAPI 3.0 specifications for APIs
- Include database schemas with proper relationships
- Consider scalability, security, and maintainability
- Document decision rationale and trade-offs
{{contractRequirements}}
## Output Format:
Structure your response with clear sections and include:
- Component diagrams using Mermaid syntax
- API endpoint specifications
- Database schema definitions
- Architectural decision records
{{contractComplianceFormat}}
Focus on creating a DESIGN.md file content that will be saved to the project worktree.
Previous architectural decisions for this project:
{{existingDecisions}}
Similar patterns found:
{{similarPatterns}}`;
}
/**
* Parse Claude's response into structured architectural analysis
*/
parseArchitecturalResponse(content) {
// Extract Mermaid diagrams
const mermaidMatches = content.match(/```mermaid\n([\s\S]*?)\n```/g);
const mermaidDiagram = mermaidMatches ? mermaidMatches.join('\n\n') : '';
// Extract OpenAPI specifications
const apiMatches = content.match(/```(?:yaml|yml)\n([\s\S]*?)\n```/g);
const apiSpec = apiMatches ? apiMatches.join('\n\n') : '';
// Extract architectural decisions (look for decision sections)
const decisions = this.extractArchitecturalDecisions(content);
// Extract data models (look for schema/model sections)
const dataModels = this.extractDataModels(content);
return {
designDocument: content,
mermaidDiagram,
apiSpec,
dataModels,
decisions
};
}
/**
* Extract architectural decisions from the design document
*/
extractArchitecturalDecisions(content) {
const decisions = [];
// Look for sections that indicate architectural decisions
const decisionPattern = /(?:## (?:Decision|Choice|Architectural Decision)[:\s]*(.+?)(?:\n|$))([\s\S]*?)(?=\n## |$)/gi;
let match;
while ((match = decisionPattern.exec(content)) !== null) {
const title = match[1]?.trim() || 'Architectural Decision';
const description = match[2]?.trim() || '';
const { alternatives, consequences } = this.extractDecisionDetails(description);
decisions.push({
title,
description,
rationale: this.extractRationale(description),
alternatives,
consequences
});
}
// If no explicit decisions found, create one from the main content
if (decisions.length === 0) {
const currentTask = this.agent.getCurrentTask();
decisions.push({
title: currentTask?.title || 'System Architecture',
description: content.substring(0, 500) + '...',
rationale: 'Based on requirements analysis and best practices'
});
}
return decisions;
}
/**
* Extract data models from the design document
*/
extractDataModels(content) {
const models = {};
// Look for database schemas, table definitions, etc.
const schemaPattern = /(?:table|model|schema)[:\s]+(\w+)[\s\S]*?(?=\n(?:table|model|schema|##)|$)/gi;
let match;
while ((match = schemaPattern.exec(content)) !== null) {
const modelName = match[1];
const definition = match[0];
models[modelName] = {
definition,
extracted: true
};
}
// If no explicit models found, create a generic structure
if (Object.keys(models).length === 0) {
models.generic = {
description: 'Data models as described in the architectural design',
source: 'architectural_design'
};
}
return models;
}
/**
* Extract rationale from decision content
*/
extractRationale(content) {
const rationaleMatch = content.match(/(?:rationale|reason|why)[:\s]*(.*?)(?:\n|$)/i);
return rationaleMatch ? rationaleMatch[1].trim() : 'Design decision based on architectural requirements';
}
/**
* Extract alternatives and consequences from decision content
*/
extractDecisionDetails(content) {
const alternativesMatch = content.match(/(?:alternatives?|options?)[:\s]*(.*?)(?:\n|$)/i);
const alternatives = alternativesMatch ?
alternativesMatch[1].split(',').map(alt => alt.trim()).filter(alt => alt.length > 0) : [];
const consequencesMatch = content.match(/(?:consequences?|implications?)[:\s]*(.*?)(?:\n|$)/i);
const consequences = consequencesMatch ?
consequencesMatch[1].split(',').map(cons => cons.trim()).filter(cons => cons.length > 0) : [];
return { alternatives, consequences };
}
/**
* Build contract context for prompt template
*/
buildContractContext(formalContracts) {
if (!formalContracts) {
return {
contractSection: '',
contractComplianceSection: '',
contractRequirements: '',
contractComplianceFormat: ''
};
}
const hasOpenApi = formalContracts.openApiSpecs && formalContracts.openApiSpecs.length > 0;
const hasSchemas = formalContracts.jsonSchemas && formalContracts.jsonSchemas.length > 0;
let contractSection = 'FORMAL CONTRACTS PROVIDED:\n';
if (hasOpenApi) {
contractSection += 'OpenAPI Specifications:\n';
formalContracts.openApiSpecs.forEach(spec => {
contractSection += `- ${spec.path}\n`;
// Include a preview of the contract content (first 500 chars)
const preview = spec.content.substring(0, 500).replace(/\n/g, '\n ');
contractSection += ` Content preview:\n ${preview}${spec.content.length > 500 ? '...' : ''}\n\n`;
});
}
if (hasSchemas) {
contractSection += 'JSON Schemas:\n';
formalContracts.jsonSchemas.forEach(schema => {
contractSection += `- ${schema.path}\n`;
// Include a preview of the schema content (first 300 chars)
const preview = schema.content.substring(0, 300).replace(/\n/g, '\n ');
contractSection += ` Content preview:\n ${preview}${schema.content.length > 300 ? '...' : ''}\n\n`;
});
}
return {
contractSection,
contractComplianceSection: '7. **Contract Compliance**: Analysis of how the design aligns with provided formal contracts',
contractRequirements: `- ENSURE all provided OpenAPI endpoints are covered in the design\n- ALIGN data models with provided JSON schemas\n- VALIDATE that the architecture can satisfy all contract requirements\n- DOCUMENT any deviations or limitations in contract compliance`,
contractComplianceFormat: '- Contract compliance analysis with specific coverage details\n- Mapping between contracts and architectural components'
};
}
/**
* Analyze contract compliance of the architectural design
*/
analyzeContractCompliance(formalContracts, analysis) {
const openApiCompliance = [];
const schemaCompliance = [];
// Analyze OpenAPI specifications
if (formalContracts.openApiSpecs) {
for (const spec of formalContracts.openApiSpecs) {
try {
const endpoints = this.extractEndpointsFromOpenApi(spec.content);
const coveredEndpoints = this.findCoveredEndpoints(endpoints, analysis.designDocument);
const missingEndpoints = endpoints.filter(ep => !coveredEndpoints.includes(ep));
openApiCompliance.push({
specPath: spec.path,
endpointsCovered: coveredEndpoints,
missingEndpoints,
complianceScore: endpoints.length > 0 ? (coveredEndpoints.length / endpoints.length) : 1
});
}
catch (error) {
console.warn(`Failed to analyze OpenAPI spec ${spec.path}:`, error.message);
openApiCompliance.push({
specPath: spec.path,
endpointsCovered: [],
missingEndpoints: [],
complianceScore: 0
});
}
}
}
// Analyze JSON schemas
if (formalContracts.jsonSchemas) {
for (const schema of formalContracts.jsonSchemas) {
try {
const models = this.extractModelsFromSchema(schema.content);
const alignedModels = this.findAlignedModels(models, analysis.dataModels);
const missingModels = models.filter(model => !alignedModels.includes(model));
schemaCompliance.push({
schemaPath: schema.path,
modelsAligned: alignedModels,
missingModels,
complianceScore: models.length > 0 ? (alignedModels.length / models.length) : 1
});
}
catch (error) {
console.warn(`Failed to analyze JSON schema ${schema.path}:`, error.message);
schemaCompliance.push({
schemaPath: schema.path,
modelsAligned: [],
missingModels: [],
complianceScore: 0
});
}
}
}
// Calculate overall compliance score
const allCompliance = [...openApiCompliance, ...schemaCompliance];
const overallScore = allCompliance.length > 0 ?
allCompliance.reduce((sum, comp) => sum + comp.complianceScore, 0) / allCompliance.length : 1;
return {
openApiCompliance,
schemaCompliance,
overallScore
};
}
/**
* Extract endpoints from OpenAPI specification content
*/
extractEndpointsFromOpenApi(content) {
const endpoints = [];
try {
// Simple regex-based extraction for paths section
const pathsMatch = content.match(/paths:\s*([\s\S]*?)(?=\n\w|$)/);
if (pathsMatch) {
const pathsSection = pathsMatch[1];
const pathMatches = pathsSection.match(/^\s*([^\s:]+):/gm);
if (pathMatches) {
pathMatches.forEach(match => {
const path = match.replace(/^\s*/, '').replace(/:$/, '');
if (path.startsWith('/')) {
endpoints.push(path);
}
});
}
}
}
catch (error) {
console.warn('Failed to extract endpoints from OpenAPI spec:', error.message);
}
return endpoints;
}
/**
* Find covered endpoints in the design document
*/
findCoveredEndpoints(endpoints, designDocument) {
return endpoints.filter(endpoint => {
// Check if the endpoint path is mentioned in the design document
const escapedEndpoint = endpoint.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const regex = new RegExp(escapedEndpoint, 'i');
return regex.test(designDocument);
});
}
/**
* Extract model names from JSON schema
*/
extractModelsFromSchema(content) {
const models = [];
try {
const schema = JSON.parse(content);
if (schema.title) {
models.push(schema.title);
}
else if (schema.properties) {
// If no title, use 'Schema' as default model name
models.push('Schema');
}
}
catch (error) {
console.warn('Failed to parse JSON schema:', error.message);
}
return models;
}
/**
* Find aligned models in the data models
*/
findAlignedModels(schemaModels, dataModels) {
const alignedModels = [];
const dataModelNames = Object.keys(dataModels);
schemaModels.forEach(schemaModel => {
// Check for exact match or partial match
const found = dataModelNames.find(dataModel => dataModel.toLowerCase().includes(schemaModel.toLowerCase()) ||
schemaModel.toLowerCase().includes(dataModel.toLowerCase()));
if (found) {
alignedModels.push(schemaModel);
}
});
return alignedModels;
}
/**
* Store architectural decisions in Cognitive Canvas
*/
async storeArchitecturalDecisions(decisions) {
const cognitiveCanvas = this.agent.getCognitiveCanvas();
const currentTask = this.agent.getCurrentTask();
if (!cognitiveCanvas || !currentTask) {
return;
}
try {
for (const decision of decisions) {
await cognitiveCanvas.storeArchitecturalDecision({
id: `decision-${currentTask.id}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
projectId: currentTask.projectId,
title: decision.title,
description: decision.description,
rationale: decision.rationale,
status: 'approved',
createdAt: new Date().toISOString()
});
}
// Create pheromone for architectural work completion
const taskContext = this.agent.getTaskContext();
const formalContracts = taskContext?.formalContracts;
await cognitiveCanvas.createPheromone({
id: `arch-${currentTask.id}-${Date.now()}`,
type: 'architectural',
strength: 0.8,
context: 'design_completed',
metadata: {
taskId: currentTask.id,
projectId: currentTask.projectId,
agentId: this.agent.getConfig()?.id,
decisionsCount: decisions.length,
designType: 'system_architecture',
contractDriven: !!formalContracts,
hasOpenApiSpecs: !!(formalContracts?.openApiSpecs?.length),
hasJsonSchemas: !!(formalContracts?.jsonSchemas?.length)
},
createdAt: new Date().toISOString(),
expiresAt: new Date(Date.now() + 7200000).toISOString() // 2 hours
});
}
catch (error) {
console.warn('Failed to store architectural decisions:', error.message);
}
}
}
exports.ArchitectCore = ArchitectCore;
//# sourceMappingURL=core.js.map