aios-core
Version:
Synkra AIOS: AI-Orchestrated System for Full Stack Development - Core Framework
1,158 lines (945 loc) • 35.3 kB
Markdown
## Execution Modes
**Choose your execution mode:**
### 1. YOLO Mode - Fast, Autonomous (0-1 prompts)
- Autonomous decision making with logging
- Minimal user interaction
- **Best for:** Simple, deterministic tasks
### 2. Interactive Mode - Balanced, Educational (5-10 prompts) **[DEFAULT]**
- Explicit decision checkpoints
- Educational explanations
- **Best for:** Learning, complex decisions
### 3. Pre-Flight Planning - Comprehensive Upfront Planning
- Task analysis phase (identify all ambiguities)
- Zero ambiguity execution
- **Best for:** Ambiguous requirements, critical work
**Parameter:** `mode` (optional, default: `interactive`)
## Task Definition (AIOS Task Format V1.0)
```yaml
task: qaReviewProposal()
responsável: Quinn (Guardian)
responsavel_type: Agente
atomic_layer: Strategy
**Entrada:**
- campo: target
tipo: string
origem: User Input
obrigatório: true
validação: Must exist
- campo: criteria
tipo: array
origem: config
obrigatório: true
validação: Non-empty validation criteria
- campo: strict
tipo: boolean
origem: User Input
obrigatório: false
validação: Default: true
**Saída:**
- campo: validation_result
tipo: boolean
destino: Return value
persistido: false
- campo: errors
tipo: array
destino: Memory
persistido: false
- campo: report
tipo: object
destino: File (.ai/*.json)
persistido: true
```
## Pre-Conditions
**Purpose:** Validate prerequisites BEFORE task execution (blocking)
**Checklist:**
```yaml
pre-conditions:
- [ ] Validation rules loaded; target available for validation
tipo: pre-condition
blocker: true
validação: |
Check validation rules loaded; target available for validation
error_message: "Pre-condition failed: Validation rules loaded; target available for validation"
```
## Post-Conditions
**Purpose:** Validate execution success AFTER task completes
**Checklist:**
```yaml
post-conditions:
- [ ] Validation executed; results accurate; report generated
tipo: post-condition
blocker: true
validação: |
Verify validation executed; results accurate; report generated
error_message: "Post-condition failed: Validation executed; results accurate; report generated"
```
## Acceptance Criteria
**Purpose:** Definitive pass/fail criteria for task completion
**Checklist:**
```yaml
acceptance-criteria:
- [ ] Validation rules applied; pass/fail accurate; actionable feedback
tipo: acceptance-criterion
blocker: true
validação: |
Assert validation rules applied; pass/fail accurate; actionable feedback
error_message: "Acceptance criterion not met: Validation rules applied; pass/fail accurate; actionable feedback"
```
## Tools
**External/shared resources used by this task:**
- **Tool:** validation-engine
- **Purpose:** Rule-based validation and reporting
- **Source:** .aios-core/utils/validation-engine.js
- **Tool:** schema-validator
- **Purpose:** JSON/YAML schema validation
- **Source:** ajv or similar
## Scripts
**Agent-specific code for this task:**
- **Script:** run-validation.js
- **Purpose:** Execute validation rules and generate report
- **Language:** JavaScript
- **Location:** .aios-core/scripts/run-validation.js
## Error Handling
**Strategy:** retry
**Common Errors:**
1. **Error:** Validation Criteria Missing
- **Cause:** Required validation rules not defined
- **Resolution:** Ensure validation criteria loaded from config
- **Recovery:** Use default validation rules, log warning
2. **Error:** Invalid Schema
- **Cause:** Target does not match expected schema
- **Resolution:** Update schema or fix target structure
- **Recovery:** Detailed validation error report
3. **Error:** Dependency Missing
- **Cause:** Required dependency for validation not found
- **Resolution:** Install missing dependencies
- **Recovery:** Abort with clear dependency list
## Performance
**Expected Metrics:**
```yaml
duration_expected: 5-20 min (estimated)
cost_estimated: $0.003-0.015
token_usage: ~2,000-8,000 tokens
```
**Optimization Notes:**
- Iterative analysis with depth limits; cache intermediate results; batch similar operations
## Metadata
```yaml
story: N/A
version: 1.0.0
dependencies:
- N/A
tags:
- quality-assurance
- testing
updated_at: 2025-11-17
```
checklists:
- change-checklist.md
# Review Proposal - AIOS Developer Task
## Purpose
Review and provide feedback on modification proposals submitted through the collaborative modification system.
## Command Pattern
```
*review-proposal <proposal-id> [options]
```
## Parameters
- `proposal-id`: ID of the proposal to review
- `options`: Review configuration
### Options
- `--action <action>`: Review action (approve, reject, request-changes, comment)
- `--comment <text>`: Review comment or feedback
- `--conditions <text>`: Conditions for approval
- `--suggestions <file>`: File containing suggested changes
- `--priority <level>`: Update proposal priority
- `--assignees <users>`: Add/change assignees
- `--fast-review`: Skip detailed analysis
## Examples
```bash
# Approve proposal with conditions
*review-proposal proposal-1234567-abc123 --action approve --comment "Looks good with minor changes" --conditions "Add comprehensive tests before merging"
# Request changes with suggestions
*review-proposal proposal-1234567-def456 --action request-changes --comment "Need security improvements" --suggestions security-review.md
# Add comment without decision
*review-proposal proposal-1234567-ghi789 --action comment --comment "Please clarify the impact on API consumers"
```
## Implementation
```javascript
const fs = require('fs').promises;
const path = require('path');
const chalk = require('chalk');
const inquirer = require('inquirer');
class ReviewProposalTask {
constructor() {
this.taskName = 'review-proposal';
this.description = 'Review modification proposals';
this.rootPath = process.cwd();
this.proposalSystem = null;
this.impactAnalyzer = null;
this.notificationService = null;
this.diffGenerator = null;
}
async execute(params) {
try {
console.log(chalk.blue('📋 AIOS Proposal Review'));
console.log(chalk.gray('Reviewing modification proposal\n'));
// Parse and validate parameters
const config = await this.parseParameters(params);
// Initialize dependencies
await this.initializeDependencies();
// Load proposal
console.log(chalk.gray('Loading proposal...'));
const proposal = await this.loadProposal(config.proposalId);
// Display proposal summary
await this.displayProposalSummary(proposal);
// Perform review analysis if not fast review
let reviewAnalysis = null;
if (!config.fastReview) {
console.log(chalk.gray('Analyzing proposal impact...'));
reviewAnalysis = await this.analyzeProposal(proposal);
await this.displayReviewAnalysis(reviewAnalysis);
}
// Get review details
const reviewDetails = await this.getReviewDetails(proposal, reviewAnalysis, config);
// Process review
console.log(chalk.gray('Processing review...'));
const result = await this.processReview(proposal, reviewDetails, config);
// Update proposal status
await this.updateProposalStatus(proposal, result);
// Notify relevant parties
await this.notifyReviewComplete(proposal, result);
// Display success
console.log(chalk.green('\n✅ Review submitted successfully'));
console.log(chalk.gray(` Proposal: ${proposal.proposalId}`));
console.log(chalk.gray(` Action: ${result.action}`));
console.log(chalk.gray(` Reviewer: ${result.reviewer}`));
if (result.nextSteps) {
console.log(chalk.blue('\n📌 Next Steps:'));
result.nextSteps.forEach((step, index) => {
console.log(chalk.gray(` ${index + 1}. ${step}`));
});
}
return {
success: true,
proposalId: proposal.proposalId,
reviewAction: result.action,
reviewStatus: result.status,
reviewer: result.reviewer,
timestamp: result.timestamp
};
} catch (error) {
console.error(chalk.red(`\n❌ Review failed: ${error.message}`));
throw error;
}
}
async parseParameters(params) {
if (params.length < 1) {
throw new Error('Usage: *review-proposal <proposal-id> [options]');
}
const config = {
proposalId: params[0],
action: null,
comment: '',
conditions: '',
suggestions: null,
priority: null,
assignees: [],
fastReview: false
};
// Parse options
for (let i = 1; i < params.length; i++) {
const param = params[i];
if (param === '--fast-review') {
config.fastReview = true;
} else if (param.startsWith('--action') && params[i + 1]) {
config.action = params[++i];
} else if (param.startsWith('--comment') && params[i + 1]) {
config.comment = params[++i];
} else if (param.startsWith('--conditions') && params[i + 1]) {
config.conditions = params[++i];
} else if (param.startsWith('--suggestions') && params[i + 1]) {
config.suggestions = params[++i];
} else if (param.startsWith('--priority') && params[i + 1]) {
config.priority = params[++i];
} else if (param.startsWith('--assignees') && params[i + 1]) {
config.assignees = params[++i].split(',').map(a => a.trim());
}
}
// Validate action if provided
if (config.action) {
const validActions = ['approve', 'reject', 'request-changes', 'comment'];
if (!validActions.includes(config.action)) {
throw new Error(`Invalid action: ${config.action}. Must be one of: ${validActions.join(', ')}`);
}
}
return config;
}
async initializeDependencies() {
try {
const ProposalSystem = require('../scripts/proposal-system');
this.proposalSystem = new ProposalSystem({ rootPath: this.rootPath });
const ImpactAnalyzer = require('../scripts/dependency-impact-analyzer');
this.impactAnalyzer = new ImpactAnalyzer({ rootPath: this.rootPath });
const NotificationService = require('../scripts/notification-service');
this.notificationService = new NotificationService({ rootPath: this.rootPath });
// const DiffGenerator = require('../scripts/diff-generator'); // Archived in archived-utilities/ (Story 3.1.2)
// this.diffGenerator = new DiffGenerator({ rootPath: this.rootPath });
} catch (error) {
throw new Error(`Failed to initialize dependencies: ${error.message}`);
}
}
async loadProposal(proposalId) {
try {
const proposalFile = path.join(this.rootPath, '.aios', 'proposals', `${proposalId}.json`);
const content = await fs.readFile(proposalFile, 'utf-8');
return JSON.parse(content);
} catch (error) {
if (error.code === 'ENOENT') {
throw new Error(`Proposal not found: ${proposalId}`);
}
throw error;
}
}
async displayProposalSummary(proposal) {
console.log(chalk.blue('\n📄 Proposal Summary'));
console.log(chalk.gray('━'.repeat(50)));
console.log(`ID: ${chalk.white(proposal.proposalId)}`);
console.log(`Title: ${chalk.white(proposal.title)}`);
console.log(`Component: ${chalk.white(proposal.componentPath)}`);
console.log(`Type: ${chalk.white(proposal.modificationType)}`);
console.log(`Priority: ${this.formatPriority(proposal.priority)}`);
console.log(`Status: ${this.formatStatus(proposal.status)}`);
console.log(`Created by: ${chalk.white(proposal.metadata.createdBy)}`);
console.log(`Created at: ${chalk.white(new Date(proposal.metadata.createdAt).toLocaleString())}`);
if (proposal.assignees && proposal.assignees.length > 0) {
console.log(`Assignees: ${chalk.white(proposal.assignees.join(', '))}`);
}
if (proposal.tags && proposal.tags.length > 0) {
console.log(`Tags: ${chalk.gray(proposal.tags.join(', '))}`);
}
console.log(chalk.blue('\n📝 Description:'));
console.log(chalk.gray(proposal.description || 'No description provided'));
// Show modification-specific info
if (proposal.modificationType === 'deprecate' && proposal.deprecationInfo) {
console.log(chalk.yellow('\n⚠️ Deprecation Info:'));
console.log(`Target removal: ${proposal.deprecationInfo.targetRemovalDate || 'Not specified'}`);
}
if (proposal.modificationType === 'enhance' && proposal.enhancementInfo) {
console.log(chalk.green('\n✨ Enhancement Info:'));
console.log(`New capabilities: ${proposal.enhancementInfo.newCapabilities.join(', ')}`);
}
if (proposal.modificationType === 'refactor' && proposal.refactorInfo) {
console.log(chalk.blue('\n🔧 Refactor Info:'));
console.log(`Breaking changes: ${proposal.refactorInfo.breakingChanges ? 'Yes' : 'No'}`);
}
}
async analyzeProposal(proposal) {
const analysis = {
codeQuality: await this.analyzeCodeQuality(proposal),
impact: proposal.impactAnalysis || null,
conflicts: await this.checkForConflicts(proposal),
testCoverage: await this.analyzeTestCoverage(proposal),
securityIssues: await this.checkSecurityIssues(proposal),
recommendations: []
};
// Generate recommendations based on analysis
analysis.recommendations = this.generateRecommendations(analysis);
return analysis;
}
async analyzeCodeQuality(proposal) {
try {
const component = await fs.readFile(
path.resolve(this.rootPath, proposal.componentPath),
'utf-8'
);
const quality = {
complexity: this.calculateComplexity(component),
maintainability: this.assessMaintainability(component),
documentation: this.checkDocumentation(component),
codeStyle: this.checkCodeStyle(component)
};
return quality;
} catch (error) {
return {
error: `Could not analyze code quality: ${error.message}`
};
}
}
async checkForConflicts(proposal) {
// Check for other pending proposals on the same component
const indexFile = path.join(this.rootPath, '.aios', 'proposals', 'index.json');
try {
const content = await fs.readFile(indexFile, 'utf-8');
const index = JSON.parse(content);
const conflicts = index.proposals.filter(p =>
p.proposalId !== proposal.proposalId &&
p.componentPath === proposal.componentPath &&
(p.status === 'pending_review' || p.status === 'approved')
);
return {
hasConflicts: conflicts.length > 0,
conflictingProposals: conflicts
};
} catch (error) {
return {
hasConflicts: false,
conflictingProposals: []
};
}
}
async analyzeTestCoverage(proposal) {
// Check if component has tests
const testPaths = [
path.join(this.rootPath, 'tests', 'unit', proposal.componentType, `${path.basename(proposal.componentPath, path.extname(proposal.componentPath))}.test.js`),
path.join(this.rootPath, 'tests', 'integration', proposal.componentType, `${path.basename(proposal.componentPath, path.extname(proposal.componentPath))}.test.js`)
];
let hasTests = false;
for (const testPath of testPaths) {
try {
await fs.access(testPath);
hasTests = true;
break;
} catch (error) {
// Test file doesn't exist
}
}
return {
hasTests: hasTests,
recommendation: hasTests ?
'Component has test coverage' :
'Component lacks test coverage - tests should be added'
};
}
async checkSecurityIssues(proposal) {
try {
const component = await fs.readFile(
path.resolve(this.rootPath, proposal.componentPath),
'utf-8'
);
const issues = [];
// Check for common security patterns
if (component.includes('eval(') || component.includes('Function(')) {
issues.push('Uses dynamic code execution (eval/Function)');
}
if (component.includes('innerHTML') || component.includes('dangerouslySetInnerHTML')) {
issues.push('Potential XSS vulnerability with innerHTML usage');
}
if (component.includes('exec(') || component.includes('spawn(')) {
issues.push('Executes external processes - needs security review');
}
if (component.includes('fs.') && proposal.modificationType === 'enhance') {
issues.push('File system operations in enhancement - verify path validation');
}
return {
hasIssues: issues.length > 0,
issues: issues
};
} catch (error) {
return {
hasIssues: false,
issues: []
};
}
}
async displayReviewAnalysis(analysis) {
console.log(chalk.blue('\n🔍 Review Analysis'));
console.log(chalk.gray('━'.repeat(50)));
// Code Quality
if (analysis.codeQuality && !analysis.codeQuality.error) {
console.log(chalk.blue('\n📊 Code Quality:'));
console.log(` Complexity: ${this.formatScore(analysis.codeQuality.complexity)}`);
console.log(` Maintainability: ${this.formatScore(analysis.codeQuality.maintainability)}`);
console.log(` Documentation: ${this.formatScore(analysis.codeQuality.documentation)}`);
console.log(` Code Style: ${this.formatScore(analysis.codeQuality.codeStyle)}`);
}
// Impact Analysis
if (analysis.impact) {
console.log(chalk.blue('\n💥 Impact Summary:'));
console.log(` Affected components: ${analysis.impact.affectedComponents || 'Unknown'}`);
console.log(` Risk level: ${this.formatRiskLevel(analysis.impact.riskLevel || 'Unknown')}`);
}
// Conflicts
if (analysis.conflicts.hasConflicts) {
console.log(chalk.yellow('\n⚠️ Conflicts Detected:'));
analysis.conflicts.conflictingProposals.forEach(conflict => {
console.log(` - ${conflict.proposalId}: ${conflict.title} (${conflict.status})`);
});
} else {
console.log(chalk.green('\n✅ No conflicts detected'));
}
// Test Coverage
console.log(chalk.blue('\n🧪 Test Coverage:'));
console.log(` ${analysis.testCoverage.recommendation}`);
// Security Issues
if (analysis.securityIssues.hasIssues) {
console.log(chalk.red('\n🔒 Security Concerns:'));
analysis.securityIssues.issues.forEach(issue => {
console.log(` - ${issue}`);
});
} else {
console.log(chalk.green('\n🔒 No security issues detected'));
}
// Recommendations
if (analysis.recommendations.length > 0) {
console.log(chalk.blue('\n💡 Recommendations:'));
analysis.recommendations.forEach((rec, index) => {
console.log(` ${index + 1}. ${rec}`);
});
}
}
async getReviewDetails(proposal, analysis, config) {
const details = {
action: config.action,
comment: config.comment,
conditions: config.conditions,
suggestions: null,
priority: config.priority,
assignees: config.assignees
};
// Load suggestions if provided
if (config.suggestions) {
try {
details.suggestions = await fs.readFile(config.suggestions, 'utf-8');
} catch (error) {
console.warn(chalk.yellow(`Could not load suggestions file: ${error.message}`));
}
}
// Interactive review if action not provided
if (!details.action) {
const questions = await this.buildReviewQuestions(proposal, analysis);
const answers = await inquirer.prompt(questions);
Object.assign(details, answers);
}
// Set reviewer info
details.reviewer = process.env.USER || 'aios-reviewer';
details.reviewTimestamp = new Date().toISOString();
return details;
}
async buildReviewQuestions(proposal, analysis) {
const questions = [];
// Main action
questions.push({
type: 'list',
name: 'action',
message: 'Review action:',
choices: [
{ name: '✅ Approve', value: 'approve' },
{ name: '❌ Reject', value: 'reject' },
{ name: '🔄 Request Changes', value: 'request-changes' },
{ name: '💬 Add Comment Only', value: 'comment' }
]
});
// Comment
questions.push({
type: 'editor',
name: 'comment',
message: 'Review comment:',
default: this.getCommentTemplate(proposal, analysis)
});
// Approval conditions
questions.push({
type: 'input',
name: 'conditions',
message: 'Conditions for approval (if any):',
when: (answers) => answers.action === 'approve'
});
// Priority update
questions.push({
type: 'list',
name: 'priority',
message: 'Update priority?',
choices: [
{ name: 'Keep current', value: null },
{ name: 'Low', value: 'low' },
{ name: 'Medium', value: 'medium' },
{ name: 'High', value: 'high' },
{ name: 'Critical', value: 'critical' }
],
default: 0
});
// Additional assignees
questions.push({
type: 'input',
name: 'additionalAssignees',
message: 'Add additional reviewers (comma-separated):',
when: (answers) => answers.action === 'request-changes',
filter: (input) => input ? input.split(',').map(a => a.trim()) : []
});
return questions;
}
async processReview(proposal, reviewDetails, config) {
const review = {
reviewId: `review-${Date.now()}-${Math.random().toString(36).substr(2, 6)}`,
proposalId: proposal.proposalId,
action: reviewDetails.action,
status: this.getReviewStatus(reviewDetails.action),
reviewer: reviewDetails.reviewer,
timestamp: reviewDetails.reviewTimestamp,
comment: reviewDetails.comment,
conditions: reviewDetails.conditions,
suggestions: reviewDetails.suggestions,
metadata: {
reviewDuration: this.calculateReviewDuration(proposal),
analysisPerformed: !config.fastReview
}
};
// Store review
await this.storeReview(proposal, review);
// Determine next steps
review.nextSteps = this.determineNextSteps(proposal, review);
return review;
}
async storeReview(proposal, review) {
const reviewsDir = path.join(this.rootPath, '.aios', 'proposals', 'reviews');
await fs.mkdir(reviewsDir, { recursive: true });
const reviewFile = path.join(reviewsDir, `${review.reviewId}.json`);
await fs.writeFile(reviewFile, JSON.stringify(review, null, 2));
// Update proposal with review reference
if (!proposal.reviews) {
proposal.reviews = [];
}
proposal.reviews.push({
reviewId: review.reviewId,
reviewer: review.reviewer,
action: review.action,
timestamp: review.timestamp
});
}
async updateProposalStatus(proposal, review) {
// Update status based on review action
switch (review.action) {
case 'approve':
proposal.status = 'approved';
proposal.approvedBy = review.reviewer;
proposal.approvalTimestamp = review.timestamp;
break;
case 'reject':
proposal.status = 'rejected';
proposal.rejectedBy = review.reviewer;
proposal.rejectionTimestamp = review.timestamp;
break;
case 'request-changes':
proposal.status = 'changes_requested';
proposal.lastReviewTimestamp = review.timestamp;
break;
case 'comment':
// Status remains unchanged for comments
proposal.lastCommentTimestamp = review.timestamp;
break;
}
// Update priority if changed
if (review.priority) {
proposal.priority = review.priority;
}
// Update assignees if changed
if (review.assignees && review.assignees.length > 0) {
proposal.assignees = [...new Set([...proposal.assignees, ...review.assignees])];
}
// Update metadata
proposal.metadata.lastModified = new Date().toISOString();
proposal.metadata.version++;
// Save updated proposal
const proposalFile = path.join(this.rootPath, '.aios', 'proposals', `${proposal.proposalId}.json`);
await fs.writeFile(proposalFile, JSON.stringify(proposal, null, 2));
// Update index
await this.updateProposalIndex(proposal);
}
async updateProposalIndex(proposal) {
const indexFile = path.join(this.rootPath, '.aios', 'proposals', 'index.json');
try {
const content = await fs.readFile(indexFile, 'utf-8');
const index = JSON.parse(content);
const proposalIndex = index.proposals.findIndex(p => p.proposalId === proposal.proposalId);
if (proposalIndex !== -1) {
index.proposals[proposalIndex].status = proposal.status;
index.proposals[proposalIndex].priority = proposal.priority;
index.proposals[proposalIndex].lastModified = proposal.metadata.lastModified;
}
await fs.writeFile(indexFile, JSON.stringify(index, null, 2));
} catch (error) {
console.warn(chalk.yellow(`Failed to update proposal index: ${error.message}`));
}
}
async notifyReviewComplete(proposal, review) {
try {
const notifications = [];
// Notify proposal creator
notifications.push({
recipient: proposal.metadata.createdBy,
type: 'review_complete',
proposalId: proposal.proposalId,
reviewAction: review.action,
reviewer: review.reviewer
});
// Notify assignees if action requires it
if (review.action === 'request-changes' && proposal.assignees) {
proposal.assignees.forEach(assignee => {
notifications.push({
recipient: assignee,
type: 'changes_requested',
proposalId: proposal.proposalId,
reviewer: review.reviewer,
comment: review.comment
});
});
}
// Send notifications
for (const notification of notifications) {
await this.notificationService.sendNotification(notification);
}
console.log(chalk.gray(` Notifications sent: ${notifications.length}`));
} catch (error) {
console.warn(chalk.yellow(`Failed to send notifications: ${error.message}`));
}
}
// Helper methods
calculateComplexity(component) {
// Simple complexity calculation based on code patterns
const functionCount = (component.match(/function\s+\w+/g) || []).length;
const methodCount = (component.match(/\w+\s*\([^)]*\)\s*{/g) || []).length;
const conditionalCount = (component.match(/if\s*\(|switch\s*\(/g) || []).length;
const loopCount = (component.match(/for\s*\(|while\s*\(|\.forEach|\.map/g) || []).length;
const complexity = functionCount + methodCount + conditionalCount + loopCount;
if (complexity > 50) return { score: 'high', value: complexity };
if (complexity > 20) return { score: 'medium', value: complexity };
return { score: 'low', value: complexity };
}
assessMaintainability(component) {
// Check for maintainability indicators
const hasComments = component.includes('//') || component.includes('/*');
const hasJSDoc = component.includes('/**');
const hasErrorHandling = component.includes('try') || component.includes('catch');
const hasModularStructure = component.includes('module.exports') || component.includes('export');
let score = 0;
if (hasComments) score += 25;
if (hasJSDoc) score += 25;
if (hasErrorHandling) score += 25;
if (hasModularStructure) score += 25;
return { score: score >= 75 ? 'good' : score >= 50 ? 'fair' : 'poor', value: score };
}
checkDocumentation(component) {
const docPatterns = [
/\/\*\*[\s\S]*?\*\//g, // JSDoc
/#+\s+\w+/g, // Markdown headers
/@param/g, // Parameter documentation
/@returns/g, // Return documentation
/@example/g // Example documentation
];
let docScore = 0;
docPatterns.forEach(pattern => {
const matches = component.match(pattern);
if (matches) docScore += matches.length;
});
return { score: docScore > 10 ? 'good' : docScore > 5 ? 'fair' : 'poor', value: docScore };
}
checkCodeStyle(component) {
// Basic code style checks
const issues = [];
if (component.includes('\t')) {
issues.push('Uses tabs instead of spaces');
}
const lines = component.split('\n');
const longLines = lines.filter(line => line.length > 120).length;
if (longLines > 0) {
issues.push(`${longLines} lines exceed 120 characters`);
}
if (!component.includes('use strict') && !component.includes('"use strict"')) {
issues.push('Missing strict mode declaration');
}
return {
score: issues.length === 0 ? 'good' : issues.length <= 2 ? 'fair' : 'poor',
issues: issues
};
}
generateRecommendations(analysis) {
const recommendations = [];
// Code quality recommendations
if (analysis.codeQuality && !analysis.codeQuality.error) {
if (analysis.codeQuality.complexity.score === 'high') {
recommendations.push('Consider refactoring to reduce code complexity');
}
if (analysis.codeQuality.documentation.score === 'poor') {
recommendations.push('Add comprehensive documentation and JSDoc comments');
}
if (analysis.codeQuality.maintainability.score === 'poor') {
recommendations.push('Improve code maintainability with better structure and error handling');
}
}
// Test coverage recommendations
if (!analysis.testCoverage.hasTests) {
recommendations.push('Add unit tests before approving this modification');
}
// Security recommendations
if (analysis.securityIssues.hasIssues) {
recommendations.push('Address security concerns before approval');
}
// Conflict recommendations
if (analysis.conflicts.hasConflicts) {
recommendations.push('Resolve conflicts with other pending proposals');
}
return recommendations;
}
getCommentTemplate(proposal, analysis) {
let template = `## Review for: ${proposal.title}\n\n`;
template += `### Summary\n[Provide your overall assessment]\n\n`;
if (analysis && analysis.recommendations.length > 0) {
template += `### Recommendations\n`;
analysis.recommendations.forEach((rec, index) => {
template += `${index + 1}. ${rec}\n`;
});
template += '\n';
}
template += `### Details\n[Add specific feedback and suggestions]\n`;
return template;
}
formatPriority(priority) {
const colors = {
low: chalk.gray,
medium: chalk.yellow,
high: chalk.red,
critical: chalk.red.bold
};
return colors[priority] ? colors[priority](priority.toUpperCase()) : priority;
}
formatStatus(status) {
const statusMap = {
draft: chalk.gray('DRAFT'),
pending_review: chalk.yellow('PENDING REVIEW'),
approved: chalk.green('APPROVED'),
rejected: chalk.red('REJECTED'),
changes_requested: chalk.yellow('CHANGES REQUESTED'),
in_progress: chalk.blue('IN PROGRESS'),
completed: chalk.green('COMPLETED')
};
return statusMap[status] || status;
}
formatScore(score) {
if (typeof score === 'object') {
const colors = {
good: chalk.green,
fair: chalk.yellow,
poor: chalk.red,
low: chalk.green,
medium: chalk.yellow,
high: chalk.red
};
const color = colors[score.score] || chalk.gray;
return color(`${score.score.toUpperCase()} (${score.value})`);
}
return score;
}
formatRiskLevel(level) {
const colors = {
low: chalk.green,
medium: chalk.yellow,
high: chalk.red,
critical: chalk.red.bold
};
return colors[level] ? colors[level](level.toUpperCase()) : level;
}
getReviewStatus(action) {
const statusMap = {
'approve': 'approved',
'reject': 'rejected',
'request-changes': 'changes_requested',
'comment': 'commented'
};
return statusMap[action] || action;
}
calculateReviewDuration(proposal) {
const created = new Date(proposal.metadata.createdAt);
const now = new Date();
const duration = now - created;
const hours = Math.floor(duration / (1000 * 60 * 60));
const days = Math.floor(hours / 24);
if (days > 0) {
return `${days} day${days > 1 ? 's' : ''}`;
}
return `${hours} hour${hours !== 1 ? 's' : ''}`;
}
determineNextSteps(proposal, review) {
const steps = [];
switch (review.action) {
case 'approve':
steps.push('Proposal approved and ready for implementation');
steps.push('Assignees will be notified to begin work');
if (review.conditions) {
steps.push(`Ensure conditions are met: ${review.conditions}`);
}
break;
case 'reject':
steps.push('Proposal has been rejected');
steps.push('Creator should address feedback before resubmission');
break;
case 'request-changes':
steps.push('Changes have been requested');
steps.push('Proposal creator should address feedback');
steps.push('Resubmit for review after making changes');
break;
case 'comment':
steps.push('Comment added to proposal');
steps.push('No status change - review still pending');
break;
}
return steps;
}
}
module.exports = ReviewProposalTask;
```
## Validation Rules
### Review Validation
- Proposal must exist and be accessible
- Review action must be valid
- Reviewer must have appropriate permissions
- Cannot review own proposals (in production)
- Cannot approve high-risk changes without conditions
### Status Transitions
- Draft → Pending Review (on submission)
- Pending Review → Approved/Rejected/Changes Requested
- Changes Requested → Pending Review (on update)
- Approved → In Progress (on implementation start)
- In Progress → Completed (on implementation finish)
### Review Requirements
- All reviews must include comments
- Approvals may include conditions
- Rejections must include reasons
- Change requests should include specific feedback
## Integration Points
### Proposal System
- Loads and updates proposal data
- Manages proposal lifecycle
- Tracks review history
- Handles status transitions
### Impact Analysis
- Provides risk assessment for review
- Identifies affected components
- Helps inform review decisions
- Highlights critical issues
### Notification Service
- Notifies proposal creator of review
- Alerts assignees of changes requested
- Sends approval confirmations
- Tracks notification delivery
### Diff Generator
- Shows proposed changes clearly
- Highlights modifications
- Assists in code review
- Supports multiple diff formats
## Security Considerations
- Validate reviewer permissions
- Audit all review actions
- Prevent unauthorized status changes
- Protect sensitive proposal information
- Log all review activities for compliance