โ† ะะฐะทะฐะด
const fs = require('fs').promises; const path = require('path'); const { execSync } = require('child_process'); const IDEAS_DIR = '/home/app/ideas'; const ACTIVE_DIR = path.join(IDEAS_DIR, 'active'); const ARCHIVE_DIR = path.join(IDEAS_DIR, 'archive'); class IdeasManager { constructor() { this.activeDir = ACTIVE_DIR; this.archiveDir = ARCHIVE_DIR; } async ensureDirs() { await fs.mkdir(this.activeDir, { recursive: true }); await fs.mkdir(this.archiveDir, { recursive: true }); } parseMarkdown(content, filename) { const lines = content.split('\n'); const id = filename.match(/^(\d+)/)?.[1] || Date.now().toString(); let title = ''; let description = ''; let status = 'proposed'; let roi = ''; let priority = 'medium'; let tags = []; if (lines[0]?.startsWith('# ')) { title = lines[0].substring(2).trim(); } lines.forEach((line) => { if (line.includes('**Status:**')) { status = line.split('**Status:**')[1]?.trim().split(' ')[0] || 'proposed'; } if (line.includes('**ROI:**')) { roi = line.split('**ROI:**')[1]?.trim() || ''; } if (line.includes('**Priority:**')) { priority = line.split('**Priority:**')[1]?.trim() || 'medium'; } if (line.includes('**Tags:**')) { const tagsStr = line.split('**Tags:**')[1]?.trim(); tags = tagsStr ? tagsStr.split(',').map(t => t.trim()).filter(Boolean) : []; } }); const descIdx = lines.findIndex(l => l.startsWith('## Description')); if (descIdx > -1 && lines[descIdx + 1]) { description = lines[descIdx + 1].trim(); } return { id, title: title || 'Untitled Idea', description: description || 'No description', status: ['proposed', 'approved', 'in-progress', 'done', 'verified'].includes(status) ? status : 'proposed', priority: ['low', 'medium', 'high', 'critical'].includes(priority) ? priority : 'medium', roi: roi || 'TBD', tags: tags, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString() }; } async getAllIdeas() { await this.ensureDirs(); try { const files = await fs.readdir(this.activeDir); const mdFiles = files.filter(f => f.endsWith('.md')); const ideas = []; for (const file of mdFiles) { try { const content = await fs.readFile(path.join(this.activeDir, file), 'utf8'); const idea = this.parseMarkdown(content, file); ideas.push(idea); } catch (err) { console.error(`Error parsing ${file}:`, err); } } ideas.sort((a, b) => parseInt(a.id) - parseInt(b.id)); return { project: 'ideas', tasks: ideas, stats: { total: ideas.length, proposed: ideas.filter(i => i.status === 'proposed').length, approved: ideas.filter(i => i.status === 'approved').length, inProgress: ideas.filter(i => i.status === 'in-progress').length, done: ideas.filter(i => i.status === 'done').length, verified: ideas.filter(i => i.status === 'verified').length } }; } catch (err) { console.error('Error reading ideas:', err); return { project: 'ideas', tasks: [], stats: { total: 0, proposed: 0, approved: 0, done: 0, verified: 0 } }; } } // Update task status async updateTaskStatus(taskId, newStatus) { await this.ensureDirs(); const files = await fs.readdir(this.activeDir); const paddedId = taskId.toString().padStart(3, '0'); const file = files.find(f => f.startsWith(paddedId + '-')); if (!file) { throw new Error(`Task ${taskId} not found`); } const filePath = path.join(this.activeDir, file); let content = await fs.readFile(filePath, 'utf8'); // Update status in markdown const statusLine = content.match(/\*\*Status:\*\*.+/); if (statusLine) { const statusEmoji = { 'proposed': '๐Ÿ†•', 'approved': 'โœ…', 'in-progress': '๐Ÿ”จ', 'done': 'โœ“', 'verified': 'โœ“โœ“' }; content = content.replace( /\*\*Status:\*\*.+/, `**Status:** ${newStatus} ${statusEmoji[newStatus] || ''}` ); } await fs.writeFile(filePath, content, 'utf8'); // Run sync to update JSON try { execSync('cd /home/app/ideas && node sync.js', { stdio: 'pipe' }); } catch (e) { console.log('Sync may have failed, continuing...'); } return { id: taskId, status: newStatus }; } } module.exports = IdeasManager;