import { readFile, writeFile } from 'node:fs/promises';
const root = new URL('../../', import.meta.url);
const taskmasterPath = new URL('.taskmaster/tasks/tasks.json', root);
const shareTasksPath = new URL('taskmaster-share/tasks.json', root);
const indexPath = new URL('taskmaster-share/index.html', root);
const raw = JSON.parse(await readFile(taskmasterPath, 'utf8'));
const data = raw.master ?? raw;
await writeFile(shareTasksPath, `${JSON.stringify(data, null, 2)}\n`);
let html = await readFile(indexPath, 'utf8');
const tasks = data.tasks ?? [];
const subtasks = tasks.flatMap((task) => task.subtasks ?? []);
const allItems = [...tasks, ...subtasks];
const counts = {
parent: tasks.length,
subtask: subtasks.length,
pending: allItems.filter((item) => item.status !== 'done').length,
done: allItems.filter((item) => item.status === 'done').length,
};
const escapeHtml = (value) =>
String(value ?? '').replace(/[&<>"']/g, (char) => ({
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": ''',
})[char]);
const badge = (value, prefix = '') =>
`${escapeHtml(value)}`;
const formatDeps = (dependencies, parentId) => {
if (!dependencies?.length) return '';
const values = dependencies.map((dependency) =>
String(dependency).includes('.') ? dependency : `${parentId}.${dependency}`
);
return `
Depends on: ${escapeHtml(values.join(', '))}
`;
};
const renderSubtask = (task, subtask) => `
${escapeHtml(task.id)}.${escapeHtml(subtask.id)}
${escapeHtml(subtask.title)}
${badge(subtask.status)}
${badge(subtask.priority, 'priority-')}
${escapeHtml(subtask.description || subtask.details || '')}
${formatDeps(subtask.dependencies, task.id)}
`;
const renderTask = (task) => `
Task ${escapeHtml(task.id)}
${escapeHtml(task.title)}
${badge(task.status)}${badge(task.priority, 'priority-')}
${escapeHtml(task.description)}
Details and test strategy
${escapeHtml(task.details)}
${task.testStrategy ? `Test strategy: ${escapeHtml(task.testStrategy)}
` : ''}
${task.dependencies?.length ? `Depends on: ${escapeHtml(task.dependencies.join(', '))}
` : ''}
Subtasks (${(task.subtasks ?? []).length})
${(task.subtasks ?? []).map((subtask) => renderSubtask(task, subtask)).join('')}
`;
const taskFive = tasks.find((task) => Number(task.id) === 5);
if (!taskFive) {
throw new Error('Task 5 is missing from Taskmaster data.');
}
html = html
.replace(/\d+<\/strong>parent tasks<\/span><\/div>/, `${counts.parent}parent tasks
`)
.replace(/\d+<\/strong>subtasks<\/span><\/div>/, `${counts.subtask}subtasks
`)
.replace(/\d+<\/strong>pending items<\/span><\/div>/, `${counts.pending}pending items
`)
.replace(/\d+<\/strong>done items<\/span><\/div>/, `${counts.done}done items
`)
.replace(
'Track security remediation, payment architecture, refactor decisions, and completed documentation work from one place.',
'Track security remediation, payment architecture, Telegram-native work, refactor decisions, and completed documentation work from one place.'
);
const article = renderTask(taskFive);
if (html.includes('Task 5')) {
html = html.replace(
/\n \n \n
\n
Task 5<\/p>[\s\S]*?\n /,
`\n${article}\n `
);
} else {
html = html.replace(
'\n ',
`\n${article}\n `
);
}
await writeFile(indexPath, html);
console.log(`Updated share page: ${counts.parent} tasks, ${counts.subtask} subtasks.`);