โ ะะฐะทะฐะด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;